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 throw std::invalid_argument("setted hour is not between [0, 24)");
61 }
62 if (minute_ >= MINUTES_PER_HOUR) {
63 ANSR_LOGE("setted minute is not between [0, 60)");
64 throw std::invalid_argument("setted minute is not between [0, 60)");
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 throw std::invalid_argument("The length of daysOfWeek should not larger than 7");
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 int today = GetActualTime(TimeTransferType::WEEK, gmtime(&now)->tm_wday);
164 int dayCount = now >= target ? 1 : 0;
165 for (; dayCount <= DAYS_PER_WEEK; dayCount++) {
166 int day = (today + dayCount) % DAYS_PER_WEEK;
167 day = (day == 0) ? SUNDAY : day;
168 if (IsRepeatDay(day)) {
169 break;
170 }
171 }
172 ANSR_LOGI("NextDayInterval is %{public}d", dayCount);
173 return dayCount;
174 }
175
IsRepeatDay(int day) const176 bool ReminderRequestAlarm::IsRepeatDay(int day) const
177 {
178 return (repeatDays_ & (1 << (day - 1))) > 0;
179 }
180
GetDaysOfWeek() const181 std::vector<int> ReminderRequestAlarm::GetDaysOfWeek() const
182 {
183 std::vector<int> repeatDays;
184 int days[] = {1, 2, 3, 4, 5, 6, 7};
185 int len = sizeof(days) / sizeof(int);
186 for (int i = 0; i < len; i++) {
187 if (IsRepeatDay(days[i])) {
188 repeatDays.push_back(days[i]);
189 }
190 }
191 return repeatDays;
192 }
193
GetHour() const194 uint8_t ReminderRequestAlarm::GetHour() const
195 {
196 return hour_;
197 }
198
GetMinute() const199 uint8_t ReminderRequestAlarm::GetMinute() const
200 {
201 return minute_;
202 }
203
GetRepeatDay() const204 uint8_t ReminderRequestAlarm::GetRepeatDay() const
205 {
206 return repeatDays_;
207 }
208
OnDateTimeChange()209 bool ReminderRequestAlarm::OnDateTimeChange()
210 {
211 return ReminderRequest::OnDateTimeChange();
212 }
213
OnTimeZoneChange()214 bool ReminderRequestAlarm::OnTimeZoneChange()
215 {
216 return ReminderRequest::OnTimeZoneChange();
217 }
218
UpdateNextReminder()219 bool ReminderRequestAlarm::UpdateNextReminder()
220 {
221 ANSR_LOGD("UpdateNextReminder alarm time");
222 if (IsRepeatReminder()) {
223 uint8_t letfSnoozeTimes = GetSnoozeTimesDynamic();
224 if ((letfSnoozeTimes > 0) && (GetTimeInterval() > 0)) {
225 ANSR_LOGI("Left times: %{public}d, update next triggerTime", GetSnoozeTimesDynamic());
226 SetTriggerTimeInMilli(GetTriggerTimeInMilli() + GetTimeInterval() * MILLI_SECONDS);
227 SetSnoozeTimesDynamic(--letfSnoozeTimes);
228 } else {
229 SetSnoozeTimesDynamic(GetSnoozeTimes());
230 if (repeatDays_ == 0) {
231 ANSR_LOGI("No need to update next triggerTime");
232 SetExpired(true);
233 return false;
234 }
235 uint64_t nextTriggerTime = GetNextTriggerTime(true);
236 if (nextTriggerTime != INVALID_LONG_LONG_VALUE) {
237 ANSR_LOGI("Set next trigger time successful, reset dynamic snoozeTimes");
238 SetTriggerTimeInMilli(nextTriggerTime);
239 } else {
240 ANSR_LOGW("Set reminder to expired");
241 SetExpired(true);
242 return false;
243 }
244 }
245 return true;
246 } else {
247 ANSR_LOGD("Single time reminder, not need to update next trigger time");
248 SetSnoozeTimesDynamic(GetSnoozeTimes());
249 SetExpired(true);
250 return false;
251 }
252 }
253
Marshalling(Parcel & parcel) const254 bool ReminderRequestAlarm::Marshalling(Parcel &parcel) const
255 {
256 ReminderRequest::Marshalling(parcel);
257
258 // write int
259 if (!parcel.WriteUint8(hour_)) {
260 ANSR_LOGE("Failed to write hour");
261 return false;
262 }
263 if (!parcel.WriteUint8(minute_)) {
264 ANSR_LOGE("Failed to write minute");
265 return false;
266 }
267 if (!parcel.WriteUint8(repeatDays_)) {
268 ANSR_LOGE("Failed to write daysOfWeek");
269 return false;
270 }
271 return true;
272 }
273
Unmarshalling(Parcel & parcel)274 ReminderRequestAlarm *ReminderRequestAlarm::Unmarshalling(Parcel &parcel)
275 {
276 ANSR_LOGD("New alarm");
277 auto objptr = new (std::nothrow) ReminderRequestAlarm();
278 if (objptr == nullptr) {
279 ANSR_LOGE("Failed to create reminder alarm due to no memory.");
280 return objptr;
281 }
282 if (!objptr->ReadFromParcel(parcel)) {
283 delete objptr;
284 objptr = nullptr;
285 }
286 return objptr;
287 }
288
ReadFromParcel(Parcel & parcel)289 bool ReminderRequestAlarm::ReadFromParcel(Parcel &parcel)
290 {
291 ReminderRequest::ReadFromParcel(parcel);
292
293 // read int
294 if (!parcel.ReadUint8(hour_)) {
295 ANSR_LOGE("Failed to read hour");
296 return false;
297 }
298 if (!parcel.ReadUint8(minute_)) {
299 ANSR_LOGE("Failed to read minute");
300 return false;
301 }
302 if (!parcel.ReadUint8(repeatDays_)) {
303 ANSR_LOGE("Failed to read repeatDays");
304 return false;
305 }
306 ANSR_LOGD("hour_=%{public}d, minute_=%{public}d, repeatDays_=%{public}d", hour_, minute_, repeatDays_);
307 return true;
308 }
309
RecoverFromDb(const std::shared_ptr<NativeRdb::AbsSharedResultSet> & resultSet)310 void ReminderRequestAlarm::RecoverFromDb(const std::shared_ptr<NativeRdb::AbsSharedResultSet> &resultSet)
311 {
312 ReminderRequest::RecoverFromDb(resultSet);
313
314 // repeatDays
315 repeatDays_ =
316 static_cast<uint8_t>(RecoverInt64FromDb(resultSet, REPEAT_DAYS_OF_WEEK, DbRecoveryType::INT));
317
318 // hour
319 hour_ =
320 static_cast<uint8_t>(RecoverInt64FromDb(resultSet, ALARM_HOUR, DbRecoveryType::INT));
321
322 // minute
323 minute_ =
324 static_cast<uint8_t>(RecoverInt64FromDb(resultSet, ALARM_MINUTE, DbRecoveryType::INT));
325 }
326
AppendValuesBucket(const sptr<ReminderRequest> & reminder,const sptr<NotificationBundleOption> & bundleOption,NativeRdb::ValuesBucket & values)327 void ReminderRequestAlarm::AppendValuesBucket(const sptr<ReminderRequest> &reminder,
328 const sptr<NotificationBundleOption> &bundleOption, NativeRdb::ValuesBucket &values)
329 {
330 uint8_t repeatDays = 0;
331 uint8_t hour = 0;
332 uint8_t minute = 0;
333 if (reminder->GetReminderType() == ReminderRequest::ReminderType::ALARM) {
334 ReminderRequestAlarm* alarm = static_cast<ReminderRequestAlarm*>(reminder.GetRefPtr());
335 repeatDays = alarm->GetRepeatDay();
336 hour = alarm->GetHour();
337 minute = alarm->GetMinute();
338 }
339 values.PutInt(REPEAT_DAYS_OF_WEEK, repeatDays);
340 values.PutInt(ALARM_HOUR, hour);
341 values.PutInt(ALARM_MINUTE, minute);
342 }
343
InitDbColumns()344 void ReminderRequestAlarm::InitDbColumns()
345 {
346 ReminderRequest::AddColumn(REPEAT_DAYS_OF_WEEK, "INT", false);
347 ReminderRequest::AddColumn(ALARM_HOUR, "INT", false);
348 ReminderRequest::AddColumn(ALARM_MINUTE, "INT", true);
349 }
350 }
351 }