1 /*
2 * Copyright (c) 2021-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
16 #include "reminder_request_alarm.h"
17
18 #include "ans_log_wrapper.h"
19 #include "reminder_store.h"
20
21 namespace OHOS {
22 namespace Notification {
23 const uint8_t ReminderRequestAlarm::DAYS_PER_WEEK = 7;
24 const uint8_t ReminderRequestAlarm::MONDAY = 1;
25 const uint8_t ReminderRequestAlarm::SUNDAY = 7;
26 const uint8_t ReminderRequestAlarm::HOURS_PER_DAY = 24;
27 const uint16_t ReminderRequestAlarm::SECONDS_PER_HOUR = 3600;
28 const uint8_t ReminderRequestAlarm::MINUTES_PER_HOUR = 60;
29 const int8_t ReminderRequestAlarm::INVALID_INT_VALUE = -1;
30 const int8_t ReminderRequestAlarm::DEFAULT_SNOOZE_TIMES = 3;
31
32 // For database recovery.
33 const std::string ReminderRequestAlarm::REPEAT_DAYS_OF_WEEK = "repeat_days_of_week";
34 const std::string ReminderRequestAlarm::ALARM_HOUR = "alarm_hour";
35 const std::string ReminderRequestAlarm::ALARM_MINUTE = "alarm_minute";
36
ReminderRequestAlarm(uint8_t hour,uint8_t minute,const std::vector<uint8_t> daysOfWeek)37 ReminderRequestAlarm::ReminderRequestAlarm(uint8_t hour, uint8_t minute, const std::vector<uint8_t> daysOfWeek)
38 : ReminderRequest(ReminderRequest::ReminderType::ALARM)
39 {
40 SetSnoozeTimes(DEFAULT_SNOOZE_TIMES);
41 hour_ = hour;
42 minute_ = minute;
43 CheckParamValid();
44 SetDaysOfWeek(true, daysOfWeek);
45 SetTriggerTimeInMilli(GetNextTriggerTime(true));
46 }
47
ReminderRequestAlarm(const ReminderRequestAlarm & other)48 ReminderRequestAlarm::ReminderRequestAlarm(const ReminderRequestAlarm &other) : ReminderRequest(other)
49 {
50 this->hour_ = other.hour_;
51 this->minute_ = other.minute_;
52 this->repeatDays_ = other.repeatDays_;
53 ANSR_LOGD("hour_=%{public}d, minute_=%{public}d, repeatDays_=%{public}d", hour_, minute_, repeatDays_);
54 }
55
CheckParamValid() const56 void ReminderRequestAlarm::CheckParamValid() const
57 {
58 if (hour_ >= HOURS_PER_DAY) {
59 ANSR_LOGE("setted hour is not between [0, 24)");
60 return;
61 }
62 if (minute_ >= MINUTES_PER_HOUR) {
63 ANSR_LOGE("setted minute is not between [0, 60)");
64 return;
65 }
66 }
67
IsRepeatReminder() const68 bool ReminderRequestAlarm::IsRepeatReminder() const
69 {
70 if ((repeatDays_ != 0) || ((GetTimeInterval() > 0) && (GetSnoozeTimes() > 0))) {
71 return true;
72 } else {
73 return false;
74 }
75 }
76
SetDaysOfWeek(bool set,std::vector<uint8_t> daysOfWeek)77 void ReminderRequestAlarm::SetDaysOfWeek(bool set, std::vector<uint8_t> daysOfWeek)
78 {
79 if (daysOfWeek.size() == 0) {
80 return;
81 }
82 if (daysOfWeek.size() > DAYS_PER_WEEK) {
83 ANSR_LOGE("The length of daysOfWeek should not larger than 7");
84 return;
85 }
86 for (std::vector<uint8_t>::iterator it = daysOfWeek.begin(); it != daysOfWeek.end(); ++it) {
87 if (*it < MONDAY || *it > SUNDAY) {
88 continue;
89 }
90 if (set) {
91 repeatDays_ |= 1 << (*it - 1);
92 } else {
93 repeatDays_ &= ~(1 << (*it - 1));
94 }
95 }
96 }
97
PreGetNextTriggerTimeIgnoreSnooze(bool ignoreRepeat,bool forceToGetNext) const98 uint64_t ReminderRequestAlarm::PreGetNextTriggerTimeIgnoreSnooze(bool ignoreRepeat, bool forceToGetNext) const
99 {
100 if (ignoreRepeat || (repeatDays_)) {
101 return GetNextTriggerTime(forceToGetNext);
102 } else {
103 return INVALID_LONG_LONG_VALUE;
104 }
105 }
106
GetNextTriggerTime(bool forceToGetNext) const107 uint64_t ReminderRequestAlarm::GetNextTriggerTime(bool forceToGetNext) const
108 {
109 time_t now;
110 (void)time(&now); // unit is seconds.
111 struct tm nowTime;
112 (void)localtime_r(&now, &nowTime);
113 ANSR_LOGD("Now: year=%{public}d, mon=%{public}d, day=%{public}d, hour=%{public}d, "
114 "min=%{public}d, sec=%{public}d, week=%{public}d, Target: tar_hour=%{public}d, tar_min=%{public}d",
115 GetActualTime(TimeTransferType::YEAR, nowTime.tm_year),
116 GetActualTime(TimeTransferType::MONTH, nowTime.tm_mon),
117 nowTime.tm_mday, nowTime.tm_hour, nowTime.tm_min, nowTime.tm_sec,
118 GetActualTime(TimeTransferType::WEEK, nowTime.tm_wday), hour_, minute_);
119
120 struct tm tar;
121 tar.tm_year = nowTime.tm_year;
122 tar.tm_mon = nowTime.tm_mon;
123 tar.tm_mday = nowTime.tm_mday;
124 tar.tm_hour = hour_;
125 tar.tm_min = minute_;
126 tar.tm_sec = 0;
127 tar.tm_isdst = -1;
128
129 const time_t target = mktime(&tar);
130 int8_t nextDayInterval = GetNextAlarm(now, target);
131 time_t nextTriggerTime = 0;
132 if (nextDayInterval == INVALID_INT_VALUE) {
133 if (now >= target) {
134 if (forceToGetNext) {
135 nextTriggerTime = target + 1 * HOURS_PER_DAY * SECONDS_PER_HOUR;
136 }
137 } else {
138 nextTriggerTime = target;
139 }
140 } else {
141 nextTriggerTime = target + nextDayInterval * HOURS_PER_DAY * SECONDS_PER_HOUR;
142 }
143 struct tm test;
144 (void)localtime_r(&nextTriggerTime, &test);
145 ANSR_LOGI("NextTriggerTime: year=%{public}d, mon=%{public}d, day=%{public}d, hour=%{public}d, "
146 "min=%{public}d, sec=%{public}d, week=%{public}d, nextTriggerTime=%{public}lld",
147 GetActualTime(TimeTransferType::YEAR, test.tm_year),
148 GetActualTime(TimeTransferType::MONTH, test.tm_mon),
149 test.tm_mday, test.tm_hour, test.tm_min, test.tm_sec,
150 GetActualTime(TimeTransferType::WEEK, test.tm_wday), (long long)nextTriggerTime);
151
152 if (static_cast<int64_t>(nextTriggerTime) <= 0) {
153 return 0;
154 }
155 return ReminderRequest::GetDurationSinceEpochInMilli(nextTriggerTime);
156 }
157
GetNextAlarm(const time_t now,const time_t target) const158 int8_t ReminderRequestAlarm::GetNextAlarm(const time_t now, const time_t target) const
159 {
160 if (repeatDays_ == 0) {
161 return INVALID_INT_VALUE;
162 }
163 struct tm nowTime;
164 (void)localtime_r(&now, &nowTime);
165 int32_t today = GetActualTime(TimeTransferType::WEEK, nowTime.tm_wday);
166 int32_t dayCount = now >= target ? 1 : 0;
167 for (; dayCount <= DAYS_PER_WEEK; dayCount++) {
168 int32_t day = (today + dayCount) % DAYS_PER_WEEK;
169 day = (day == 0) ? SUNDAY : day;
170 if (IsRepeatDay(day)) {
171 break;
172 }
173 }
174 ANSR_LOGI("NextDayInterval is %{public}d", dayCount);
175 return dayCount;
176 }
177
IsRepeatDay(int32_t day) const178 bool ReminderRequestAlarm::IsRepeatDay(int32_t day) const
179 {
180 return (repeatDays_ & (1 << (day - 1))) > 0;
181 }
182
GetDaysOfWeek() const183 std::vector<int32_t> ReminderRequestAlarm::GetDaysOfWeek() const
184 {
185 std::vector<int32_t> repeatDays;
186 int32_t days[] = {1, 2, 3, 4, 5, 6, 7};
187 int32_t len = sizeof(days) / sizeof(int32_t);
188 for (int32_t i = 0; i < len; i++) {
189 if (IsRepeatDay(days[i])) {
190 repeatDays.push_back(days[i]);
191 }
192 }
193 return repeatDays;
194 }
195
GetHour() const196 uint8_t ReminderRequestAlarm::GetHour() const
197 {
198 return hour_;
199 }
200
GetMinute() const201 uint8_t ReminderRequestAlarm::GetMinute() const
202 {
203 return minute_;
204 }
205
GetRepeatDay() const206 uint8_t ReminderRequestAlarm::GetRepeatDay() const
207 {
208 return repeatDays_;
209 }
210
OnDateTimeChange()211 bool ReminderRequestAlarm::OnDateTimeChange()
212 {
213 return ReminderRequest::OnDateTimeChange();
214 }
215
OnTimeZoneChange()216 bool ReminderRequestAlarm::OnTimeZoneChange()
217 {
218 return ReminderRequest::OnTimeZoneChange();
219 }
220
UpdateNextReminder()221 bool ReminderRequestAlarm::UpdateNextReminder()
222 {
223 ANSR_LOGD("UpdateNextReminder alarm time");
224 if (IsRepeatReminder()) {
225 uint8_t letfSnoozeTimes = GetSnoozeTimesDynamic();
226 if ((letfSnoozeTimes > 0) && (GetTimeInterval() > 0)) {
227 ANSR_LOGI("Left times: %{public}d, update next triggerTime", GetSnoozeTimesDynamic());
228 SetTriggerTimeInMilli(GetTriggerTimeInMilli() + GetTimeInterval() * MILLI_SECONDS);
229 SetSnoozeTimesDynamic(--letfSnoozeTimes);
230 } else {
231 SetSnoozeTimesDynamic(GetSnoozeTimes());
232 if (repeatDays_ == 0) {
233 ANSR_LOGI("No need to update next triggerTime");
234 SetExpired(true);
235 return false;
236 }
237 uint64_t nextTriggerTime = GetNextTriggerTime(true);
238 if (nextTriggerTime != INVALID_LONG_LONG_VALUE) {
239 ANSR_LOGI("Set next trigger time successful, reset dynamic snoozeTimes");
240 SetTriggerTimeInMilli(nextTriggerTime);
241 } else {
242 ANSR_LOGW("Set reminder to expired");
243 SetExpired(true);
244 return false;
245 }
246 }
247 return true;
248 } else {
249 ANSR_LOGD("Single time reminder, not need to update next trigger time");
250 SetSnoozeTimesDynamic(GetSnoozeTimes());
251 SetExpired(true);
252 return false;
253 }
254 }
255
Marshalling(Parcel & parcel) const256 bool ReminderRequestAlarm::Marshalling(Parcel &parcel) const
257 {
258 ReminderRequest::Marshalling(parcel);
259
260 // write int
261 if (!parcel.WriteUint8(hour_)) {
262 ANSR_LOGE("Failed to write hour");
263 return false;
264 }
265 if (!parcel.WriteUint8(minute_)) {
266 ANSR_LOGE("Failed to write minute");
267 return false;
268 }
269 if (!parcel.WriteUint8(repeatDays_)) {
270 ANSR_LOGE("Failed to write daysOfWeek");
271 return false;
272 }
273 return true;
274 }
275
Unmarshalling(Parcel & parcel)276 ReminderRequestAlarm *ReminderRequestAlarm::Unmarshalling(Parcel &parcel)
277 {
278 ANSR_LOGD("New alarm");
279 auto objptr = new (std::nothrow) ReminderRequestAlarm();
280 if (objptr == nullptr) {
281 ANSR_LOGE("Failed to create reminder alarm due to no memory.");
282 return objptr;
283 }
284 if (!objptr->ReadFromParcel(parcel)) {
285 delete objptr;
286 objptr = nullptr;
287 }
288 return objptr;
289 }
290
ReadFromParcel(Parcel & parcel)291 bool ReminderRequestAlarm::ReadFromParcel(Parcel &parcel)
292 {
293 ReminderRequest::ReadFromParcel(parcel);
294
295 // read int
296 if (!parcel.ReadUint8(hour_)) {
297 ANSR_LOGE("Failed to read hour");
298 return false;
299 }
300 if (!parcel.ReadUint8(minute_)) {
301 ANSR_LOGE("Failed to read minute");
302 return false;
303 }
304 if (!parcel.ReadUint8(repeatDays_)) {
305 ANSR_LOGE("Failed to read repeatDays");
306 return false;
307 }
308 ANSR_LOGD("hour_=%{public}d, minute_=%{public}d, repeatDays_=%{public}d", hour_, minute_, repeatDays_);
309 return true;
310 }
311
RecoverFromDb(const std::shared_ptr<NativeRdb::ResultSet> & resultSet)312 void ReminderRequestAlarm::RecoverFromDb(const std::shared_ptr<NativeRdb::ResultSet> &resultSet)
313 {
314 ReminderRequest::RecoverFromDb(resultSet);
315
316 // repeatDays
317 repeatDays_ =
318 static_cast<uint8_t>(RecoverInt64FromDb(resultSet, REPEAT_DAYS_OF_WEEK, DbRecoveryType::INT));
319
320 // hour
321 hour_ =
322 static_cast<uint8_t>(RecoverInt64FromDb(resultSet, ALARM_HOUR, DbRecoveryType::INT));
323
324 // minute
325 minute_ =
326 static_cast<uint8_t>(RecoverInt64FromDb(resultSet, ALARM_MINUTE, DbRecoveryType::INT));
327 }
328
AppendValuesBucket(const sptr<ReminderRequest> & reminder,const sptr<NotificationBundleOption> & bundleOption,NativeRdb::ValuesBucket & values)329 void ReminderRequestAlarm::AppendValuesBucket(const sptr<ReminderRequest> &reminder,
330 const sptr<NotificationBundleOption> &bundleOption, NativeRdb::ValuesBucket &values)
331 {
332 uint8_t repeatDays = 0;
333 uint8_t hour = 0;
334 uint8_t minute = 0;
335 if (reminder->GetReminderType() == ReminderRequest::ReminderType::ALARM) {
336 ReminderRequestAlarm* alarm = static_cast<ReminderRequestAlarm*>(reminder.GetRefPtr());
337 repeatDays = alarm->GetRepeatDay();
338 hour = alarm->GetHour();
339 minute = alarm->GetMinute();
340 }
341 values.PutInt(REPEAT_DAYS_OF_WEEK, repeatDays);
342 values.PutInt(ALARM_HOUR, hour);
343 values.PutInt(ALARM_MINUTE, minute);
344 }
345
InitDbColumns()346 void ReminderRequestAlarm::InitDbColumns()
347 {
348 ReminderRequest::AddColumn(REPEAT_DAYS_OF_WEEK, "INT", false);
349 ReminderRequest::AddColumn(ALARM_HOUR, "INT", false);
350 ReminderRequest::AddColumn(ALARM_MINUTE, "INT", true);
351 }
352 }
353 }