1/**
2 * @file Describe the file
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import data_rdb from '@ohos.data.relationalStore';
18import dataSharePredicates from '@ohos.data.dataSharePredicates';
19import { sendBroadcast } from '@ohos/common/src/main/ets/broadcast/BroadcastHelper';
20import { Log } from '@ohos/common/src/main/ets/utils/Log';
21import {
22  getCurrentTimeZoneMillisecond,
23  MILLS_PER_MINUTE,
24  MILLS_PER_HOUR,
25  MILLS_PER_DAY,
26  MILLS_PER_WEEK
27} from '@ohos/common/src/main/ets/utils/TimeUtils';
28import { getBundleNameByUri } from '@ohos/common/src/main/ets/utils/UrlUtils';
29
30import { CalendarAccountType } from '@ohos/datastructure/src/main/ets/calendars/CalendarAccountType';
31import { CalendarAlerts } from '@ohos/datastructure/src/main/ets/calendaralerts/CalendarAlerts';
32import { parseCalendarAlerts } from '@ohos/datastructure/src/main/ets/calendaralerts/CalendarAlertsParser';
33import { CalendarAlertStateType } from '@ohos/datastructure/src/main/ets/calendaralerts/CalendarAlertStateType';
34import { CalendarAlertsColumns } from '@ohos/datastructure/src/main/ets/calendaralerts/CalendarAlertsColumns';
35import { CalendarAlertsIndexes } from '@ohos/datastructure/src/main/ets/calendaralerts/CalendarAlertsIndexes';
36import { CalendarsColumns } from '@ohos/datastructure/src/main/ets/calendars/CalendarsColumns';
37import { EventColumns } from '@ohos/datastructure/src/main/ets/events/EventColumns';
38import { parseEvents } from '@ohos/datastructure/src/main/ets/events/EventParser';
39import { Events } from '@ohos/datastructure/src/main/ets/events/Events';
40import { EventIndexes, parseIndexes } from '@ohos/datastructure/src/main/ets/events/EventIndexes';
41import { InstancesColumns } from '@ohos/datastructure/src/main/ets/instances/InstancesColumns';
42import { ReminderMethodType } from '@ohos/datastructure/src/main/ets/reminders/ReminderMethodType';
43import { RemindersColumns } from '@ohos/datastructure/src/main/ets/reminders/RemindersColumns';
44
45import { CommonEventConstants } from '../../commonevents/CommonEventConstants';
46import { DefaultProcessor } from '../DefaultProcessor';
47import { ErrorCode } from '../../constants/ErrorCode';
48import { notifyEventReminder } from '../../commonevents/notify/ScheduleAlarmNotifier';
49import CalendarDataHelper from '../../utils/CalendarDataHelper';
50import { acquireExpandAll } from '../instances/InstancesProcessor';
51import { initValueCreator, initPredicateCreator, deleteValueCreator } from '../DatabaseProcessorHelper';
52import { ValueType, ValuesBucket } from '@ohos.data.ValuesBucket';
53import { BusinessError } from '@ohos.base';
54
55const TAG = 'AlertsProcessor';
56
57const SCHEDULE_ALARM_SLACK = 2 * MILLS_PER_HOUR;
58
59const CLEAR_OLD_ALARM_THRESHOLD = MILLS_PER_WEEK + SCHEDULE_ALARM_SLACK;
60
61const ALLDAY_EVENT_ALARM_TIME = 9 * MILLS_PER_HOUR;
62
63const INVALIDATE_TIME_MILLIS = -1;
64
65const INVALID_CALENDARALERTS_SELECTOR = `SELECT ca.${CalendarAlertsColumns.ID} FROM `
66+ `${CalendarAlertsColumns.TABLE_NAME} AS ca LEFT OUTER JOIN ${InstancesColumns.TABLE_NAME} USING `
67+ `(${InstancesColumns.EVENT_ID},${InstancesColumns.BEGIN},${InstancesColumns.END}) LEFT OUTER JOIN `
68+ `${RemindersColumns.TABLE_NAME} AS r ON (ca.${CalendarAlertsColumns.EVENT_ID}=r.${RemindersColumns.EVENT_ID} AND `
69+ `ca.${CalendarAlertsColumns.MINUTES}=r.${RemindersColumns.MINUTES}) LEFT OUTER JOIN `
70+ `(${EventColumns.TABLE_NAME} AS e JOIN ${CalendarsColumns.TABLE_NAME} AS c ON (e.${EventColumns.CALENDAR_ID}=`
71+ `c.${CalendarsColumns.ID})) ON (ca.${CalendarAlertsColumns.EVENT_ID}=e.${EventColumns.ID}) WHERE `
72+ `${InstancesColumns.TABLE_NAME}.${InstancesColumns.BEGIN} ISNULL OR ca.${CalendarAlertsColumns.ALARM_TIME}<? OR `
73+ `(r.${RemindersColumns.MINUTES} ISNULL AND ca.${CalendarAlertsColumns.MINUTES}<>0) OR `
74+ `c.${CalendarsColumns.CAN_REMINDER}=0 OR c.${CalendarsColumns.VISIBLE}=0`;
75
76const SINGLE_REMINDERS_SELECTOR = `select min ( ${RemindersColumns.ID} ) as _id FROM ${RemindersColumns.TABLE_NAME} `
77+ `group by ${RemindersColumns.EVENT_ID},${RemindersColumns.MINUTES},${RemindersColumns.METHOD}`;
78
79const ALL_DAY_SUB_QUERY_PREFIX = `SELECT (CASE WHEN `
80+ `${CalendarsColumns.ACCOUNT_TYPE}='${CalendarAccountType.BIRTHDAY_ACCOUNT_TYPE}' THEN `
81+ `${InstancesColumns.BEGIN} -? -(${RemindersColumns.MINUTES}*${MILLS_PER_MINUTE}) ELSE `
82+ `${InstancesColumns.BEGIN} -? + (${ALLDAY_EVENT_ALARM_TIME}) -`
83+ `(${RemindersColumns.MINUTES}*${MILLS_PER_MINUTE}) END)`;
84
85const SUB_QUERY_PREFIX = `SELECT ${InstancesColumns.BEGIN} -(${RemindersColumns.MINUTES}*${MILLS_PER_MINUTE})`;
86
87const SUB_QUERY_SUFFIX = ` AS alertAlarmTime,${InstancesColumns.TABLE_NAME}.${InstancesColumns.EVENT_ID} AS eventId, `
88+ `${EventColumns.TABLE_NAME}.${EventColumns.CREATOR} AS ${EventColumns.CREATOR}, `
89+ `${InstancesColumns.BEGIN},${InstancesColumns.END},${CalendarsColumns.TABLE_NAME}.account_type AS account_type,`
90+ `${EventColumns.TITLE},${EventColumns.ALLDAY},${RemindersColumns.METHOD},${RemindersColumns.MINUTES} FROM `
91+ `${InstancesColumns.TABLE_NAME} INNER JOIN (${EventColumns.TABLE_NAME} JOIN ${CalendarsColumns.TABLE_NAME} ON `
92+ `(${EventColumns.TABLE_NAME}.${EventColumns.CALENDAR_ID}=${CalendarsColumns.TABLE_NAME}.${CalendarsColumns.ID})) ON `
93+ `(${EventColumns.TABLE_NAME}.${EventColumns.ID}=${InstancesColumns.TABLE_NAME}.${InstancesColumns.EVENT_ID}) `
94+ `INNER JOIN ${RemindersColumns.TABLE_NAME} ON (${InstancesColumns.TABLE_NAME}.${InstancesColumns.EVENT_ID}=`
95+ `${RemindersColumns.TABLE_NAME}.${RemindersColumns.EVENT_ID}) WHERE ${CalendarsColumns.VISIBLE}=1 AND `
96+ `${CalendarsColumns.CAN_REMINDER}=1 AND alertAlarmTime>=CAST(? AS INT) AND alertAlarmTime<=CAST(? AS INT) AND `
97+ `${InstancesColumns.END}>=? AND ${RemindersColumns.METHOD}=${ReminderMethodType.METHOD_ALERT}`;
98
99const ALL_DAY_QUERY = `${ALL_DAY_SUB_QUERY_PREFIX} ${SUB_QUERY_SUFFIX} AND ${EventColumns.ALLDAY}=1`;
100
101const NO_ALL_DAY_QUERY = `${SUB_QUERY_PREFIX} ${SUB_QUERY_SUFFIX} AND ${EventColumns.ALLDAY}=0`;
102
103const ALERT_GENERATE_QUERY = `SELECT * FROM (${ALL_DAY_QUERY} UNION ALL ${NO_ALL_DAY_QUERY}) WHERE 0=(SELECT count(*) FROM `
104+ `${CalendarAlertsColumns.TABLE_NAME} CA WHERE CA.${CalendarAlertsColumns.EVENT_ID}=eventId AND `
105+ `CA.${CalendarAlertsColumns.BEGIN}=${InstancesColumns.BEGIN} AND `
106+ `CA.${CalendarAlertsColumns.ALARM_TIME}=alertAlarmTime) `
107+ `ORDER BY alertAlarmTime,${InstancesColumns.BEGIN},${EventColumns.TITLE}`;
108
109/**
110 * the AlertsProcessor table processor
111 *
112 * @since 2022-10-25
113 */
114export class AlertsProcessor extends DefaultProcessor {
115  async insertByHighAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, callback: Function) {
116    const callerName = getBundleNameByUri(uri);
117    initValueCreator(values, callerName);
118    const isEventExist = await isEventSameWithAlertId(rdbStore, values);
119    if (isEventExist) {
120      this.doInsert(rdbStore, uri, values, callback);
121    } else {
122      Log.warn(TAG, 'not support insert operation');
123      const err: BusinessError = {
124        code: ErrorCode.UN_SUPPORT_OPERATION,
125        name: 'UnSupportedOperationException',
126        message: 'The calling application cannot insert an reminder without its own event'
127      };
128      callback(err, -1);
129    }
130  }
131
132  async insertByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: ValuesBucket, callback: Function) {
133    const callerName = getBundleNameByUri(uri);
134    initValueCreator(values, callerName);
135    const isEventCreatorExist = await isEventSameWithAlertCreator(rdbStore, values);
136    if (isEventCreatorExist) {
137      this.doInsert(rdbStore, uri, values, callback);
138    } else {
139      Log.warn(TAG, 'not support insert operation');
140      const err: BusinessError = {
141        code: ErrorCode.UN_SUPPORT_OPERATION,
142        name: 'UnSupportedOperationException',
143        message: 'The calling application cannot insert an reminder with different creator from event'
144      };
145      callback(err, -1);
146    }
147  }
148
149  async deleteByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
150    const callerName = getBundleNameByUri(uri);
151    initPredicateCreator(predicates, callerName);
152    this.doDelete(rdbStore, uri, predicates, callback);
153  }
154
155  async updateByHighAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
156    values = deleteValueCreator(values);
157    this.doUpdate(rdbStore, uri, values, predicates, callback)
158  }
159
160  async updateByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
161    const callerName = getBundleNameByUri(uri);
162    values = deleteValueCreator(values);
163    initPredicateCreator(predicates, callerName);
164    this.doUpdate(rdbStore, uri, values, predicates, callback)
165  }
166
167  async queryByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, columns: Array<string>, predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
168    const callerName = getBundleNameByUri(uri);
169    initPredicateCreator(predicates, callerName);
170    this.doQuery(rdbStore, uri, columns, predicates, callback);
171  }
172}
173
174/**
175 * 检查待插入的 alert 与 event 表中相同 event_id 的元组是否拥有相同的 creator
176 *
177 * @param rdbStore rdb数据库
178 * @param values 插入操作的数据
179 * @return true 相同 false 不相同
180 */
181async function isEventSameWithAlertCreator(rdbStore: data_rdb.RdbStore, values: ValuesBucket): Promise<boolean> {
182  Log.debug(TAG, 'isEventSameWithAlertCreator start');
183  const calendarAlertCreator = values[CalendarsColumns.CREATOR];
184  let resultSet = await queryEventIdAndCreatorByAlert(rdbStore, values);
185  if (resultSet === null || resultSet === undefined) {
186    return false;
187  }
188  try {
189    const eventIndexes: EventIndexes = parseIndexes(resultSet) as EventIndexes;
190    if (resultSet.goToFirstRow()) {
191      let events: Events | undefined = parseEvents(resultSet, eventIndexes);
192      if (events === null || events === undefined) {
193        return false;
194      }
195      return events.creator === calendarAlertCreator;
196    }
197  } catch (err) {
198    Log.warn(TAG, `isEventSameWithAlertCreator err ${JSON.stringify(err)}`);
199  } finally {
200    if (resultSet) {
201      resultSet.close();
202    }
203  }
204  return false;
205}
206
207/**
208 * 检查待插入的 alert 与 event 表中是否存在相同 event_id 的元组
209 *
210 * @param rdbStore rdb数据库
211 * @param values 插入操作的数据
212 * @return true 相同 false 不相同
213 */
214async function isEventSameWithAlertId(rdbStore: data_rdb.RdbStore, values: data_rdb.ValuesBucket): Promise<boolean> {
215  Log.debug(TAG, 'isEventSameWithAlertId start');
216  let resultSet = await queryEventIdAndCreatorByAlert(rdbStore, values);
217  try {
218    if (resultSet === null || resultSet === undefined) {
219      return false;
220    }
221    if (resultSet.rowCount > 0) {
222      return true;
223    }
224  } catch (err) {
225    Log.warn(TAG, `isEventSameWithAlertId err ${JSON.stringify(err)}`);
226  } finally {
227    if (resultSet) {
228      resultSet.close();
229    }
230  }
231  return false;
232}
233
234/**
235 * 查询待插入的 alert 数据中 event_id 与 event 表相同的结果
236 *
237 * @param rdbStore rdb数据库
238 * @param values 插入操作的数据
239 * @return DataShareResultSet
240 */
241async function queryEventIdAndCreatorByAlert(rdbStore: data_rdb.RdbStore, values: data_rdb.ValuesBucket) {
242  const eventId = values[CalendarAlertsColumns.EVENT_ID] as ValueType;
243  const columns = [EventColumns.ID, EventColumns.CREATOR];
244  let predicates = new dataSharePredicates.DataSharePredicates();
245  predicates.equalTo(EventColumns.ID, eventId);
246  try {
247    return await rdbStore.query(EventColumns.TABLE_NAME, predicates, columns);
248  } catch (err) {
249    Log.error(TAG, 'Event query data error');
250  }
251  return;
252}
253
254/**
255 * 为下一个日历中的事件生成alarm
256 *
257 * @param isRemoveAlarms 是否需要移除状态为0的Alarms
258 */
259export async function runScheduleNextAlarm(isRemoveAlarms: boolean = false) {
260  Log.info(TAG, 'runScheduleNextAlarm start.');
261  let rdbStore = await CalendarDataHelper.getInstance().getRdbStore();
262  if (!rdbStore) {
263    Log.warn(TAG, 'runScheduleNextAlarm: rdbStore is null.');
264    return;
265  }
266  await deleteRepeatReminders(rdbStore);
267  try {
268    if (isRemoveAlarms) {
269      await removeScheduledAlarmsLocked(rdbStore);
270    }
271    await scheduleNextAlarmLocked(rdbStore);
272  } catch (err) {
273    Log.error(TAG, "runScheduleNextAlarm error");
274  }
275}
276
277/**
278 * 检索数据表,生成alarm,在提醒时间发送广播
279 *
280 * @param rdbStore RdbStore
281 */
282async function scheduleNextAlarmLocked(rdbStore: data_rdb.RdbStore) {
283  Log.info(TAG, 'scheduleNextAlarmLocked start.');
284  let rowsDeleted: number = 0;
285  let isAlarmLessThenCurrent: boolean = false;
286  const date: Date = new Date();
287  let currentMillis = date.getTime();
288  const start = currentMillis - SCHEDULE_ALARM_SLACK;
289  const end = start + MILLS_PER_DAY + MILLS_PER_HOUR + SCHEDULE_ALARM_SLACK;
290
291  try {
292    rowsDeleted = await deleteInvalidAlert(rdbStore, currentMillis);
293  } catch (err) {
294    Log.error(TAG, 'TAG, Error in deleting invalidAlert');
295  }
296
297  let nextAlarmTime = end;
298  try {
299    let tmpAlarmTime: number = await findNextAlarmTime(rdbStore, currentMillis);
300    if (tmpAlarmTime !== INVALIDATE_TIME_MILLIS && tmpAlarmTime < nextAlarmTime) {
301      nextAlarmTime = tmpAlarmTime;
302    }
303  } catch (err) {
304    Log.error(TAG, 'TAG, Error in getting nextAlarmTime');
305  }
306  const localOffset = getCurrentTimeZoneMillisecond(date);
307  const queryParams = [localOffset.toString(), localOffset.toString(), start.toString(), nextAlarmTime.toString(),
308  currentMillis.toString(), start.toString(), nextAlarmTime.toString(), currentMillis.toString()];
309
310  // 扩展Instances:扩展范围为一天
311  await acquireExpandAll(rdbStore, start - MILLS_PER_DAY, end + MILLS_PER_DAY);
312  let resultSet: data_rdb.ResultSet | null = null;
313  try {
314    resultSet = await rdbStore.querySql(ALERT_GENERATE_QUERY, queryParams);
315    Log.info(TAG, "scheduleNextAlarmLocked() result row count is " + resultSet.rowCount);
316    const indexes: CalendarAlertsIndexes = parseScheduleCalendarAlertsIndexes(resultSet) as CalendarAlertsIndexes;
317    while (resultSet.goToNextRow()) {
318      let calendarAlerts: CalendarAlerts | undefined = parseCalendarAlerts(resultSet, indexes);
319      if (calendarAlerts === null || calendarAlerts === undefined) {
320        Log.debug(TAG, "scheduleNextAlarmLocked() result is null or undefined");
321        continue;
322      }
323      if (calendarAlerts.alarmTime < nextAlarmTime) {
324        nextAlarmTime = calendarAlerts.alarmTime;
325      }
326
327      const isExistAlarm = await alarmExists(rdbStore, calendarAlerts);
328      if (isExistAlarm) {
329        continue;
330      }
331
332      const rowId = await insertAlert(rdbStore, date, calendarAlerts);
333      if (rowId == -1) {
334        continue;
335      }
336      if (!await notifyEventReminder(calendarAlerts.alarmTime)) {
337        isAlarmLessThenCurrent = true;
338      }
339    }
340    if (isAlarmLessThenCurrent || rowsDeleted > 0) {
341      sendBroadcast(CommonEventConstants.EVENT_REMINDER);
342      runScheduleNextAlarm();
343    }
344  } catch (err) {
345    Log.error(TAG, 'This is a resultSet ergodic error');
346  } finally {
347    if (resultSet) {
348      resultSet.close();
349    }
350  }
351}
352
353/**
354 * 查找给定时间之后的下一个alarm时间
355 *
356 * @param rdbStore RdbStore
357 * @param mills 给定的事件
358 * @return 返回下一个alarm的时间,如果不存在此类alarm,则返回-1
359 */
360async function findNextAlarmTime(rdbStore: data_rdb.RdbStore, mills: number): Promise<number> {
361  Log.info(TAG, 'findNextAlarmTime start.');
362  let alarmTime = INVALIDATE_TIME_MILLIS;
363  const columns = [CalendarAlertsColumns.ALARM_TIME];
364  let predicates = new dataSharePredicates.DataSharePredicates();
365  predicates.greaterThanOrEqualTo(CalendarAlertsColumns.ALARM_TIME, mills.toString());
366  predicates.orderByAsc(CalendarAlertsColumns.ALARM_TIME);
367  try {
368    let resultSet = await rdbStore.query(CalendarAlertsColumns.TABLE_NAME, predicates, columns);
369    if (resultSet === null || resultSet === undefined) {
370      return alarmTime;
371    }
372    if (resultSet.goToFirstRow()) {
373      alarmTime = resultSet.getLong(resultSet.getColumnIndex(CalendarAlertsColumns.ALARM_TIME));
374      Log.debug(TAG, 'findNextAlarmTime succeed');
375    }
376  } catch (err) {
377    Log.error(TAG, 'findNextAlarmTime error');
378  }
379  return alarmTime;
380}
381
382/**
383 * 查看alarm是否已经存在
384 *
385 * @param calendarAlerts 携带参数的calendarAlerts
386 * @return 存在则返回true
387 */
388async function alarmExists(rdbStore: data_rdb.RdbStore, calendarAlerts: CalendarAlerts): Promise<boolean> {
389  let isExistAlarm = false;
390  const columns = [CalendarAlertsColumns.ALARM_TIME];
391  let predicates = new dataSharePredicates.DataSharePredicates();
392  predicates.equalTo(InstancesColumns.EVENT_ID, calendarAlerts.eventId.toString());
393  predicates.equalTo(CalendarAlertsColumns.BEGIN, calendarAlerts.begin.toString());
394  predicates.equalTo(CalendarAlertsColumns.ALARM_TIME, calendarAlerts.alarmTime.toString());
395  try {
396    let resultSet = await rdbStore.query(CalendarAlertsColumns.TABLE_NAME, predicates, columns);
397    if (resultSet === null || resultSet === undefined) {
398      return isExistAlarm;
399    }
400    if (resultSet.rowCount > 0) {
401      isExistAlarm = true;
402      Log.debug(TAG, 'alarmExists:alarm already exist');
403    }
404  } catch (err) {
405    Log.error(TAG, 'alarmExists query data error');
406  }
407  return isExistAlarm;
408}
409
410/**
411 * 获取触发提醒sql语句所查询的Alert表的列
412 *
413 * @param resultSet 执行查询sql语句的结果
414 * @return CalendarAlertsIndexes 返回查询的列Index
415 */
416function parseScheduleCalendarAlertsIndexes(resultSet: data_rdb.ResultSet) {
417  if (resultSet === null || resultSet === undefined) {
418    return;
419  }
420  let indexes: CalendarAlertsIndexes = new CalendarAlertsIndexes();
421  indexes.alarmTimeIndex = resultSet.getColumnIndex('alertAlarmTime');
422  indexes.eventIdIndex = resultSet.getColumnIndex('eventId');
423  indexes.minutesIndex = resultSet.getColumnIndex(CalendarAlertsColumns.MINUTES);
424  indexes.beginIndex = resultSet.getColumnIndex(CalendarAlertsColumns.BEGIN);
425  indexes.endIndex = resultSet.getColumnIndex(CalendarAlertsColumns.END);
426  indexes.creatorIndex = resultSet.getColumnIndex(CalendarAlertsColumns.CREATOR);
427  return indexes;
428}
429
430/**
431 * Alert插入数据表中
432 *
433 * @param calendarAlerts 携带参数的calendarAlerts
434 * @return 成功则返回rowId
435 */
436async function insertAlert(rdbStore: data_rdb.RdbStore, date: Date, calendarAlerts: CalendarAlerts): Promise<number> {
437  let currentMillis = date.getTime();
438  let rowId: number = -1;
439  const valueBucket: ValuesBucket = {};
440  valueBucket[CalendarAlertsColumns.EVENT_ID] = calendarAlerts.eventId;
441  valueBucket[CalendarAlertsColumns.BEGIN] = calendarAlerts.begin;
442  valueBucket[CalendarAlertsColumns.END] = calendarAlerts.end;
443  valueBucket[CalendarAlertsColumns.ALARM_TIME] = calendarAlerts.alarmTime;
444  valueBucket[CalendarAlertsColumns.CREATION_TIME] = currentMillis;
445  valueBucket[CalendarAlertsColumns.RECEIVED_TIME] = 0;
446  valueBucket[CalendarAlertsColumns.NOTIFY_TIME] = 0;
447  valueBucket[CalendarAlertsColumns.STATE] = CalendarAlertStateType.STATE_SCHEDULED;
448  valueBucket[CalendarAlertsColumns.MINUTES] = calendarAlerts.minutes;
449  valueBucket[CalendarAlertsColumns.CREATOR] = calendarAlerts.creator;
450  try {
451    rowId = await rdbStore.insert(CalendarAlertsColumns.TABLE_NAME, valueBucket);
452    Log.debug(TAG, `insertAlert succeed , rowId = ${rowId}`);
453  } catch (err) {
454    Log.error(TAG, 'insertAlert error');
455  }
456  return rowId;
457}
458
459/**
460 * 删除无用的alarm
461 *
462 * @param rdbStore RdbStore
463 * @param currentMillis 当前时间
464 * @return 成功则返回受影响的行数
465 */
466async function deleteInvalidAlert(rdbStore: data_rdb.RdbStore, currentMillis: number): Promise<number> {
467  Log.info(TAG, 'deleteInvalidAlert start.');
468  let rowsDeleted: number = 0;
469  let arraysDeleteId: number[] = [];
470  let predicates = new dataSharePredicates.DataSharePredicates();
471  const selectArg = [(currentMillis - CLEAR_OLD_ALARM_THRESHOLD).toString()];
472  try {
473    let resultSet = await rdbStore.querySql(INVALID_CALENDARALERTS_SELECTOR, selectArg);
474    if (resultSet === null || resultSet === undefined) {
475      return 0;
476    }
477    if (!resultSet.goToFirstRow()) {
478      return 0;
479    }
480    do {
481      let deleteId = resultSet.getLong(resultSet.getColumnIndex(CalendarAlertsColumns.ID));
482      arraysDeleteId.push(deleteId);
483    } while (resultSet.goToNextRow());
484    predicates.in(CalendarAlertsColumns.ID, arraysDeleteId);
485    rowsDeleted = await rdbStore.delete(CalendarAlertsColumns.TABLE_NAME, predicates);
486    Log.debug(TAG, `deleteInvalidAlert succeed, rowsDeleted = ${rowsDeleted}`);
487  } catch (err) {
488    Log.error(TAG, 'deleteInvalidAlert error');
489  }
490  return rowsDeleted;
491}
492
493/**
494 * 删除重复的Reminder
495 *
496 * @param rdbStore RdbStore
497 */
498async function deleteRepeatReminders(rdbStore: data_rdb.RdbStore) {
499  Log.info(TAG, 'deleteRepeatReminders start.');
500  let arraysList: number[] = [];
501  let predicates = new dataSharePredicates.DataSharePredicates();
502  try {
503    let resultSet = await rdbStore.querySql(SINGLE_REMINDERS_SELECTOR);
504    if (resultSet === null || resultSet === undefined) {
505      return;
506    }
507    if (!resultSet.goToFirstRow()) {
508      return;
509    }
510    do {
511      let deleteId = resultSet.getLong(resultSet.getColumnIndex(RemindersColumns.ID));
512      arraysList.push(deleteId);
513    } while (resultSet.goToNextRow());
514    predicates.notIn(RemindersColumns.ID, arraysList);
515    await rdbStore.delete(RemindersColumns.TABLE_NAME, predicates);
516    Log.debug(TAG, `deleteRepeatReminders succeed`);
517  } catch (err) {
518    Log.error(TAG, 'deleteRepeatReminders error');
519  }
520}
521
522/**
523 * 移除状态为0的Alarms
524 *
525 * @param rdbStore
526 */
527async function removeScheduledAlarmsLocked(rdbStore: data_rdb.RdbStore) {
528  Log.info(TAG, 'removeScheduledAlarmsLocked start.');
529  let predicates = new dataSharePredicates.DataSharePredicates();
530  predicates.equalTo(CalendarAlertsColumns.STATE, CalendarAlertStateType.STATE_SCHEDULED)
531  try {
532    await rdbStore.delete(CalendarAlertsColumns.TABLE_NAME, predicates);
533    Log.debug(TAG, `removeScheduledAlarmsLocked succeed`);
534  } catch (err) {
535    Log.error(TAG, 'removeScheduledAlarmsLocked error');
536  }
537}
538
539