• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }