• 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 IContactRepository from './IContactRepository';
19import Contact from '../entity/Contact';
20import RawContact from '../entity/RawContact';
21import ContactBuilder from '../entity/ContactBuilder';
22import { DataItem } from '../entity/DataItem';
23import ContactList from './ContactList';
24import DAOperation from './DAOperation';
25import ContactDelta from './ContactDelta';
26import { RawContacts } from '../contract/RawContacts';
27import { Contacts } from '../contract/Contacts';
28import { Data } from '../contract/Data';
29import { HiLog } from '../../../../../../common/src/main/ets/util/HiLog';
30import ContactListItem from './ContactListItem';
31import { DataItemType } from '../contract/DataType';
32import Calls from '../../../../../call/src/main/ets/contract/Calls';
33import { CallLog } from '../../../../../call/src/main/ets/entity/CallLog';
34import CallLogBuilder from '../../../../../call/src/main/ets/entity/CallLogBuilder';
35import { SearchContacts } from '../contract/SearchContacts';
36import SearchContactListItem from './SearchContactListItem';
37import ContactUsuallyListItem from './ContactUsuallyListItem';
38
39const TAG = 'ContactRepository';
40
41/**
42 * Contact storage management, shielding dependency on the CP layer
43 * Contacts Only
44 */
45export class ContactRepository implements IContactRepository {
46  static readonly RAW_CONTACT_URL: string = RawContacts.CONTENT_URI;
47  private dataShareHelper;
48  private static instance: ContactRepository;
49  private context: Context
50
51  private constructor() {
52  }
53
54  /*
55   * init if Call From serviceAbility globalThis.context is Null
56   *@param ctx Context used for dataShare
57   */
58  init(ctx: Context) {
59    this.context = ctx;
60  }
61
62  public static getInstance(): ContactRepository {
63    if (!ContactRepository.instance) {
64      ContactRepository.instance = new ContactRepository();
65    }
66    return ContactRepository.instance;
67  }
68
69  saveTest() {
70    return false;
71  }
72
73  private async getDataAbilityHelper() {
74    if (this.dataShareHelper == undefined) {
75      this.dataShareHelper = await dataShare.createDataShareHelper(this.context ? this.context : globalThis.context,
76      Contacts.CONTENT_URI);
77    }
78    return this.dataShareHelper;
79  }
80
81  save(contact: ContactDelta, callback) {
82    this.getDataAbilityHelper().then((dataAbilityHelper) => {
83      let opts = contact.buildDiff();
84      return dataAbilityHelper.executeBatch(ContactRepository.RAW_CONTACT_URL, opts)
85        .then(resultSet => {
86          callback(resultSet);
87        })
88        .catch(error => {
89          HiLog.w(TAG, 'save 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  findById(id: number, callback) {
99    if (id < 0) {
100      HiLog.w(TAG, 'findById: id is invalid.');
101      callback();
102      return;
103    }
104    this.getDataAbilityHelper().then((dataAbilityHelper) => {
105      let conditionArgs = new dataSharePredicates.DataSharePredicates();
106      conditionArgs.equalTo(RawContacts.CONTACT_ID, id).orderByAsc(Data.RAW_CONTACT_ID);
107      dataAbilityHelper.query(Data.CONTENT_URI, conditionArgs, null).then(resultSet => {
108        if (resultSet == undefined || !resultSet.goToFirstRow()) {
109          HiLog.w(TAG, 'findById not found.');
110          callback();
111          return;
112        }
113        let contactBuilder = ContactBuilder.fromResultSet(resultSet);
114        let currentRawContactId = -1;
115        let rawContact: RawContact = null;
116        do {
117          let rawContactId = resultSet.getLong(resultSet.getColumnIndex(Data.RAW_CONTACT_ID));
118          if (rawContactId != currentRawContactId) {
119            currentRawContactId = rawContactId;
120            rawContact = RawContact.fromResultSet(resultSet);
121            contactBuilder.rowContacts.push(rawContact);
122          }
123          if (rawContact != undefined) {
124            rawContact.dataItems.push(DataItem.fromResultSet(resultSet));
125          }
126        } while (resultSet.goToNextRow());
127        resultSet.close();
128        callback(contactBuilder.buildContact());
129      }).catch(error => {
130        HiLog.e(TAG, 'findById error:%s' + JSON.stringify(error.message));
131        callback();
132      });
133    }).catch(error => {
134      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
135      callback();
136    });
137  }
138
139  findAll(actionData, callback) {
140    let conditionArgs = new dataSharePredicates.DataSharePredicates();
141    let offset = actionData.page < 3 ? (actionData.page - 1) * 50 : (actionData.page - 2) * 500 + 50;
142    conditionArgs.limit(actionData.limit, offset)
143    //      conditionArgs.limitAs(actionData.limit);
144    //      conditionArgs.offsetAs(offset);
145    conditionArgs.equalTo(RawContacts.IS_DELETED, '0').orderByAsc(RawContacts.SORT_FIRST_LETTER);
146    this.getDataAbilityHelper().then((dataAbilityHelper) => {
147      dataAbilityHelper.query(Contacts.CONTACT_URI, conditionArgs, ContactListItem.COLUMNS)
148        .then(resultSet => {
149          let rst: ContactListItem[] = [];
150          if (resultSet.rowCount === 0) {
151            resultSet.close();
152            callback(rst);
153          } else {
154            resultSet.goToFirstRow();
155            do {
156              rst.push(new ContactListItem(resultSet));
157            } while (resultSet.goToNextRow());
158            resultSet.close();
159            callback(rst);
160          }
161        })
162        .catch(error => {
163          HiLog.w(TAG, 'findAll error:%s' + JSON.stringify(error.message));
164          callback([]);
165        });
166    }).catch(error => {
167      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
168      callback([]);
169    });
170  }
171
172  findByQuickSearchKey(searchKey: string, callback) {
173    this.getDataAbilityHelper().then((dataAbilityHelper) => {
174      let conditionArgs = new dataSharePredicates.DataSharePredicates();
175      conditionArgs.equalTo(Contacts.QUICK_SEARCH_KEY, searchKey).orderByAsc(Data.RAW_CONTACT_ID);
176      dataAbilityHelper.query(Data.CONTENT_URI, conditionArgs, null).then(resultSet => {
177        if (resultSet == undefined || !resultSet.goToFirstRow()) {
178          HiLog.w(TAG, 'findByQuickSearchKey not found.');
179          callback();
180          return;
181        }
182        let contactBuilder = ContactBuilder.fromResultSet(resultSet);
183        let currentRawContactId = -1;
184        let rawContact: RawContact = null;
185        do {
186          let rawContactId = resultSet.getLong(resultSet.getColumnIndex(Data.RAW_CONTACT_ID));
187          if (rawContactId != currentRawContactId) {
188            currentRawContactId = rawContactId;
189            rawContact = RawContact.fromResultSet(resultSet);
190            contactBuilder.rowContacts.push(rawContact);
191          }
192          if (rawContact != undefined) {
193            rawContact.dataItems.push(DataItem.fromResultSet(resultSet));
194          }
195        } while (resultSet.goToNextRow());
196        resultSet.close();
197        callback(contactBuilder.buildContact());
198      }).catch(error => {
199        HiLog.e(TAG, 'findByQuickSearchKey error:%s' + JSON.stringify(error.message));
200        callback();
201      });
202    }).catch(error => {
203      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
204      callback();
205    });
206  }
207
208  findAllWithBookIndex() {
209    return new ContactList({});
210  }
211
212  search(queryStr: string) {
213    return new ContactList({});
214  }
215
216  findByPhoneIsNotNull(favorite: number, editContact: number, callback) {
217    HiLog.i(TAG, 'initContactsList resultList success favoriteForm favorite :' + favorite + '---' + editContact);
218    this.getAllContactNumbers(favorite, editContact, (contactNumberMap) => {
219      this.getDataAbilityHelper().then((dataAbilityHelper) => {
220        let conditionArgs = new dataSharePredicates.DataSharePredicates();
221        if (-1 !== editContact || 0 === favorite) {
222          conditionArgs.equalTo(RawContacts.IS_DELETED, '0');
223          if (0 === favorite) {
224            conditionArgs.and();
225            conditionArgs.equalTo(RawContacts.FAVORITE, 0);
226          }
227          conditionArgs.orderByAsc(RawContacts.SORT_FIRST_LETTER);
228        } else {
229          conditionArgs.equalTo(RawContacts.IS_DELETED, '0')
230            .and()
231            .equalTo(Contacts.HAS_PHONE_NUMBER, '1')
232            .orderByAsc(RawContacts.SORT_FIRST_LETTER);
233        }
234        dataAbilityHelper.query(Contacts.CONTACT_URI, conditionArgs, ContactListItem.COLUMNS)
235          .then(resultSet => {
236            let rst: ContactListItem[] = [];
237            if (resultSet.rowCount === 0) {
238              resultSet.close();
239              callback(rst);
240            } else {
241              resultSet.goToFirstRow();
242              do {
243                let id = resultSet.getLong(resultSet.getColumnIndex(Contacts.ID));
244                if (!contactNumberMap.has(id)) {
245                  HiLog.w(TAG, 'findAll: contact id is invalid or contact has no phone number.');
246                  continue;
247                }
248                let contactListItem = new ContactListItem(resultSet);
249                contactListItem.phoneNumbers = contactNumberMap.get(id);
250                rst.push(contactListItem);
251              } while (resultSet.goToNextRow());
252              resultSet.close();
253              callback(rst);
254            }
255          })
256          .catch(error => {
257            HiLog.w(TAG, 'findAll error:%s' + JSON.stringify(error.message));
258            callback();
259          });
260      }).catch(error => {
261        HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
262        callback();
263      });
264    });
265  }
266
267  /**
268   * 查询所有联系人手机号
269   */
270  private getAllContactNumbers(favorite: number, editContact: number, callback) {
271    this.getDataAbilityHelper().then((dataAbilityHelper) => {
272      let resultColumns = [RawContacts.CONTACT_ID, Data.DETAIL_INFO, Data.EXTEND7, Data.CUSTOM_DATA];
273      let conditionArgs = new dataSharePredicates.DataSharePredicates();
274      if (-1 !== editContact || 0 === favorite) {
275        conditionArgs.orderByAsc(RawContacts.CONTACT_ID);
276      } else {
277        conditionArgs.equalTo(Data.TYPE_ID, DataItemType.PHONE).orderByAsc(RawContacts.CONTACT_ID);
278      }
279      dataAbilityHelper.query(Data.CONTENT_URI, conditionArgs, resultColumns).then(resultSet => {
280        // 用于存储联系人及其电话号码的对应关系
281        let contactNumberMap = new Map();
282        if (resultSet == undefined || !resultSet.goToFirstRow()) {
283          HiLog.w(TAG, 'getAllContactNumbers not found.');
284          callback(contactNumberMap);
285          return;
286        }
287        let oldContact = resultSet.getLong(resultSet.getColumnIndex(RawContacts.CONTACT_ID));
288        let oldPhoneNumber = '';
289        let numberList = [];
290        do {
291          let newContact = resultSet.getLong(resultSet.getColumnIndex(RawContacts.CONTACT_ID));
292          let phoneNumberObj = {
293            'phoneNumber': resultSet.getString(resultSet.getColumnIndex(Data.DETAIL_INFO)),
294            'labelId': resultSet.getString(resultSet.getColumnIndex(Data.EXTEND7)),
295            'numType': resultSet.getString(resultSet.getColumnIndex(Data.CUSTOM_DATA))
296          };
297          // 如果是同一联系人则把手机号放到同一个list中
298          if (oldContact === newContact) {
299            if (oldPhoneNumber != phoneNumberObj.phoneNumber) {
300              numberList.push(phoneNumberObj);
301            }
302          } else {
303            // 联系人变化时,存储联系人与手机号码列表的对应关系
304            contactNumberMap.set(oldContact, numberList);
305            oldContact = newContact;
306            // 将最新的号码数据存储到新的numberList
307            numberList = [phoneNumberObj];
308          }
309          oldPhoneNumber = phoneNumberObj.phoneNumber;
310        } while (resultSet.goToNextRow());
311        contactNumberMap.set(oldContact, numberList);
312        resultSet.close();
313        callback(contactNumberMap);
314      });
315    }).catch(error => {
316      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
317      callback(new Map());
318    });
319  }
320
321  findByMailIsNotNull() {
322    return new ContactList({});
323  }
324
325  deleteById(id: number, callback) {
326    if (id < 0) {
327      callback();
328      return;
329    }
330    this.getDataAbilityHelper().then((dataAbilityHelper) => {
331      let condition = new dataSharePredicates.DataSharePredicates();
332      condition.equalTo(Contacts.ID, id);
333      dataAbilityHelper.delete(Contacts.CONTACT_URI, condition).then(data => {
334        callback(data);
335      }).catch(error => {
336        HiLog.w(TAG, 'deleteById error:%s' + JSON.stringify(error.message));
337        callback();
338      });
339    }).catch(error => {
340      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
341      callback();
342    });
343  }
344
345  deleteByIdIn(ids: number[]) {
346    return false;
347  }
348
349  notifyChange() {
350    this.getDataAbilityHelper().then((dataAbilityHelper) => {
351      if (dataAbilityHelper) {
352        dataAbilityHelper.notifyChange(Data.CONTENT_URI).then(() => {
353          HiLog.i(TAG, 'notifyChange success')
354        }).catch(error => {
355          HiLog.w(TAG, 'notifyChange error:%s' + JSON.stringify(error.message));
356        });
357      }
358    }).catch(error => {
359      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
360    });
361  }
362
363  observers: Array<() => void> = [];
364  contactsUrl: Array<string> = [Contacts.CONTACT_URI, Data.CONTENT_URI];
365  callback = () => {
366    HiLog.d(TAG, 'Contacts changed: Notifying observers...');
367    for (const observer of this.observers) {
368      observer();
369    }
370  }
371
372  registerContactsDataChange() {
373    this.contactsUrl.forEach((url, index, array) => {
374      this.getDataAbilityHelper().then((dataAbilityHelper) => {
375        if (dataAbilityHelper) {
376          dataAbilityHelper.on('dataChange', url, this.callback);
377          HiLog.i(TAG, 'registerContactsDataChange success:' + index)
378        }
379      }).catch(error => {
380        HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
381      });
382    })
383  }
384
385  unregisterContactsDataChange() {
386    this.contactsUrl.forEach((url, index, array) => {
387      this.getDataAbilityHelper().then((dataAbilityHelper) => {
388        if (dataAbilityHelper) {
389          HiLog.i(TAG, 'start unregisterContactsDataChange:' + index)
390          dataAbilityHelper.off('dataChange', url, this.callback);
391          HiLog.i(TAG, 'unregisterContactsDataChange success:' + index)
392        }
393      }).catch(error => {
394        HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
395      });
396    })
397  }
398
399  registerDataChangeObserver(observer: () => void) {
400    if (!observer) {
401      HiLog.i(TAG, `registerDataChangeObserver: observer is null.`);
402      return;
403    }
404    if (this.observers.length == 0) {
405      this.registerContactsDataChange()
406    }
407    const isExist = this.observers.includes(observer);
408    if (isExist) {
409      return HiLog.i(TAG, 'registerDataChangeObserver: Observer has been attached already.');
410    }
411    HiLog.i(TAG, 'registerDataChangeObserver: Attached an observer.');
412    this.observers.push(observer);
413  }
414
415  unRegisterDataChangeObserver(observer: () => void) {
416    const observerIndex = this.observers.indexOf(observer);
417    if (observerIndex === -1) {
418      HiLog.i(TAG, 'unRegisterDataChangeObserver: Nonexistent observer.');
419      return
420    }
421    this.observers.splice(observerIndex, 1);
422    HiLog.i(TAG, 'unRegisterDataChangeObserver: Detached an observer.');
423    if (this.observers.length == 0) {
424      this.unregisterContactsDataChange();
425    }
426  }
427
428  queryContactDataByNumber(numberList, callback) {
429    this.getDataAbilityHelper().then((dataAbilityHelper) => {
430      if (!dataAbilityHelper) {
431        HiLog.e(TAG, 'queryContactDataByNumber, dataAbilityHelper is null');
432        callback([]);
433        return;
434      }
435      let resultColumns = [
436        'detail_info',
437        'display_name',
438      ];
439      let condition = new dataSharePredicates.DataSharePredicates();
440      condition.in('detail_info', numberList);
441      condition.and();
442      condition.equalTo('type_id', '5');
443      condition.and();
444      condition.equalTo('is_deleted', '0');
445      dataAbilityHelper.query(Data.CONTENT_URI, condition, resultColumns).then(resultSet => {
446        callback(this.dealContactResultSet(resultSet));
447      }).catch(error => {
448        HiLog.e(TAG, 'queryContactDataByNumber query, error: ' + JSON.stringify(error.message));
449      })
450    }).catch(error => {
451      HiLog.e(TAG, 'queryContactDataByNumber, error: ' + JSON.stringify(error.message));
452      callback([]);
453    });
454  }
455
456  dealContactResultSet(resultSet) {
457    let contacts = [];
458    while (resultSet?.goToNextRow()) {
459      let contact: { [key: string]: any } = {};
460      contact.detailInfo = resultSet.getString(0);
461      contact.displayName = resultSet.getString(1);
462      contacts.push(contact);
463    }
464    return contacts;
465  }
466
467  findAllFavorite(actionData, callback) {
468    HiLog.i(TAG, 'refreshUsually findAllFavorite start.');
469    let conditionArgs = new dataSharePredicates.DataSharePredicates();
470    conditionArgs.equalTo(RawContacts.IS_DELETED, '0');
471    conditionArgs.and();
472    conditionArgs.equalTo(RawContacts.FAVORITE, 1);
473    conditionArgs.and();
474    conditionArgs.orderByAsc(RawContacts.FAVORITE_ORDER);
475    this.getDataAbilityHelper().then((dataAbilityHelper) => {
476      dataAbilityHelper.query(Contacts.CONTACT_URI, conditionArgs, ContactListItem.COLUMNS)
477        .then(resultSet => {
478          let rst: ContactListItem[] = [];
479          if (resultSet.rowCount === 0) {
480            resultSet.close();
481            callback(rst);
482          } else {
483            resultSet.goToFirstRow();
484            do {
485              rst.push(new ContactListItem(resultSet));
486            } while (resultSet.goToNextRow());
487            resultSet.close();
488            HiLog.i(TAG, 'findAllFavorite query data success.');
489            callback(rst);
490          }
491        })
492        .catch(error => {
493          HiLog.e(TAG, 'findAllFavorite error:%s' + JSON.stringify(error.message));
494          callback([]);
495        });
496    }).catch(error => {
497      HiLog.e(TAG, 'findAllFavorite error:%s' + JSON.stringify(error.message));
498      callback([]);
499    });
500  }
501
502  findAllUsually(actionData, callback) {
503    HiLog.i(TAG, 'refreshUsually findAllUsually start.');
504    let conditionArgs = new dataSharePredicates.DataSharePredicates();
505    conditionArgs.groupBy([Calls.DISPLAY_NAME, Calls.PHONE_NUMBER]).distinct();
506    conditionArgs.and();
507    conditionArgs.orderByDesc(Calls.TALK_DURATION);
508    conditionArgs.and();
509    conditionArgs.orderByDesc(Calls.CREATE_TIME);
510    this.getDataAbilityHelper().then((dataAbilityHelper) => {
511      dataAbilityHelper.query(Calls.CALL_LOG_URI, conditionArgs, null)
512        .then(resultSet => {
513          let rst: CallLog[] = [];
514          if (resultSet.rowCount === 0) {
515            resultSet.close();
516            callback(rst);
517          } else {
518            resultSet.goToFirstRow();
519            do {
520              let builder = CallLogBuilder.fromResultSet(resultSet);
521              if (builder.id > 0) {
522                rst.push(new CallLog(builder));
523              }
524            } while (resultSet.goToNextRow());
525            resultSet.close();
526            HiLog.i(TAG, 'findAllUsually query data success.');
527            callback(rst);
528          }
529        })
530        .catch(error => {
531          HiLog.e(TAG, 'findAllUsually error:%s' + JSON.stringify(error.message));
532          callback([]);
533        });
534    }).catch(error => {
535      HiLog.e(TAG, 'findAllUsually error:%s' + JSON.stringify(error.message));
536      callback([]);
537    });
538  }
539
540  getDisplayNameByFavorite(displayName, usuallyPhone, callback) {
541    HiLog.i(TAG, 'getDisplayNameByFavorite start.');
542    let conditionArgs = new dataSharePredicates.DataSharePredicates();
543    conditionArgs.equalTo(RawContacts.IS_DELETED, '0');
544    conditionArgs.and();
545    conditionArgs.in(RawContacts.DISPLAY_NAME, displayName);
546    conditionArgs.and();
547    conditionArgs.in(Data.DETAIL_INFO, usuallyPhone);
548    conditionArgs.and();
549    conditionArgs.equalTo(RawContacts.FAVORITE, 0);
550    conditionArgs.and();
551    conditionArgs.equalTo(Data.CONTENT_TYPE, 'phone');
552    this.getDataAbilityHelper().then((dataAbilityHelper) => {
553      dataAbilityHelper.query(Data.CONTENT_URI, conditionArgs, ContactUsuallyListItem.COLUMNS)
554        .then(resultSet => {
555          let rst: ContactUsuallyListItem[] = [];
556          if (resultSet.rowCount === 0) {
557            resultSet.close();
558            callback(rst);
559          } else {
560            resultSet.goToFirstRow();
561            do {
562              rst.push(new ContactUsuallyListItem(resultSet));
563            } while (resultSet.goToNextRow());
564            resultSet.close();
565            HiLog.i(TAG, 'getDisplayNameByFavorite query data sc.');
566            callback(rst);
567          }
568        })
569        .catch(error => {
570          HiLog.e(TAG, 'getDisplayNameByFavorite error:%s' + JSON.stringify(error.message));
571          callback([]);
572        });
573    }).catch(error => {
574      HiLog.e(TAG, 'getDisplayNameByFavorite error:%s' + JSON.stringify(error.message));
575      callback([]);
576    });
577  }
578
579  searchContact(actionData, callback) {
580    HiLog.i(TAG, 'searchContact start.');
581    let conditionArgs = new dataSharePredicates.DataSharePredicates();
582    let searchValue: string = actionData.value;
583    conditionArgs.beginWrap()
584    conditionArgs.equalTo(SearchContacts.CONTENT_TYPE, 'phone')
585    conditionArgs.and()
586    conditionArgs.beginWrap()
587    conditionArgs.like(SearchContacts.DETAIL_INFO, '%' + searchValue + '%')
588    conditionArgs.endWrap()
589    conditionArgs.or()
590    conditionArgs.beginWrap()
591    conditionArgs.equalTo(SearchContacts.SORT_FIRST_LETTER, '#')
592    conditionArgs.and()
593    conditionArgs.like(SearchContacts.SEARCH_NAME, '%' + searchValue + '%')
594    conditionArgs.endWrap()
595    conditionArgs.endWrap()
596    conditionArgs.or()
597    conditionArgs.beginWrap()
598    conditionArgs.equalTo(SearchContacts.SORT_FIRST_LETTER, searchValue[0].toUpperCase())
599    conditionArgs.and()
600    conditionArgs.like(SearchContacts.SEARCH_NAME, '%' + searchValue + '%')
601    conditionArgs.and()
602    conditionArgs.equalTo(SearchContacts.CONTENT_TYPE, 'phone')
603    conditionArgs.endWrap()
604    conditionArgs.or()
605    conditionArgs.beginWrap()
606    conditionArgs.equalTo(SearchContacts.SORT_FIRST_LETTER, searchValue.toUpperCase())
607    conditionArgs.and()
608    conditionArgs.equalTo(SearchContacts.CONTENT_TYPE, 'phone')
609    conditionArgs.endWrap()
610    conditionArgs.or()
611    conditionArgs.beginWrap()
612    conditionArgs.like(SearchContacts.SEARCH_NAME, '%' + actionData.value + '%')
613    conditionArgs.and()
614    conditionArgs.equalTo(SearchContacts.CONTENT_TYPE, 'phone')
615    conditionArgs.endWrap()
616    conditionArgs.or()
617    conditionArgs.beginWrap()
618    conditionArgs.like(SearchContacts.SEARCH_NAME, '%' + actionData.value + '%')
619    conditionArgs.and()
620    conditionArgs.equalTo(SearchContacts.CONTENT_TYPE, 'name')
621    conditionArgs.and()
622    conditionArgs.equalTo(SearchContacts.HAS_PHONE_NUMBER, '0')
623    conditionArgs.endWrap()
624    conditionArgs.and()
625    conditionArgs.groupBy([SearchContacts.ROW_CONTACT_ID]).distinct();
626    this.getDataAbilityHelper().then((dataAbilityHelper) => {
627      dataAbilityHelper.query(SearchContacts.CONTENT_URI, conditionArgs, SearchContactListItem.COLUMNS)
628        .then(resultSet => {
629          HiLog.i(TAG, 'searchContact resultSet.rowCount : ' + JSON.stringify(resultSet.rowCount) );
630          let rst: SearchContactListItem[] = [];
631          let goTo: boolean = false;
632          if (resultSet.rowCount === 0) {
633            resultSet.close();
634            callback(rst);
635          } else {
636            resultSet.goToFirstRow();
637            do {
638              rst.push(new SearchContactListItem(resultSet));
639              goTo = resultSet.goToNextRow();
640            } while (goTo);
641            resultSet.close();
642            HiLog.i(TAG, 'searchContact query data success.');
643            callback(rst);
644          }
645        })
646        .catch(error => {
647          HiLog.i(TAG, 'searchContact error:%s' + JSON.stringify(error.message));
648          callback([]);
649        });
650    }).catch(error => {
651      HiLog.i(TAG, 'searchContact:%s' + JSON.stringify(error.message));
652      callback([]);
653    });
654  }
655
656  queryT9PhoneIsNotNull(favorite: any, callback) {
657    this.getAllContactNumbers(0, 0, (contactNumberMap) => {
658      this.getDataAbilityHelper().then((dataAbilityHelper) => {
659        let conditionArgs = new dataSharePredicates.DataSharePredicates();
660        conditionArgs.like(SearchContacts.DETAIL_INFO, `%${favorite.teleNumber}%`);
661        conditionArgs.equalTo(SearchContacts.CONTENT_TYPE, 'phone');
662        conditionArgs.orderByAsc(SearchContacts.DISPLAY_NAME)
663        dataAbilityHelper.query(
664        SearchContacts.CONTENT_URI,
665          conditionArgs,
666        SearchContactListItem.COLUMNS
667        ).then(resultSet => {
668          let rst: ContactListItem[] = [];
669          if (resultSet.rowCount === 0) {
670            resultSet.close();
671            callback(rst);
672          } else {
673            resultSet.goToFirstRow();
674            do {
675              let id = resultSet.getLong(resultSet.getColumnIndex(Contacts.ID));
676              if (!contactNumberMap.has(id)) {
677                HiLog.w(TAG, 'findAll: contact id is invalid or contact has no phone number.');
678                continue;
679              }
680              let contactListItem = new ContactListItem(resultSet);
681              contactListItem.phoneNumbers = contactNumberMap.get(id);
682              rst.push(contactListItem);
683            } while (resultSet.goToNextRow());
684            resultSet.close();
685            callback(rst);
686          }
687        })
688          .catch(error => {
689            HiLog.w(TAG, 'findAll error:%s' + JSON.stringify(error.message));
690            callback();
691          });
692      }).catch(error => {
693        HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
694        callback();
695      });
696    });
697  }
698}