• 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         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 }