diff --git a/frameworks/ans/native/src/reminder_request.cpp b/frameworks/ans/native/src/reminder_request.cpp new file mode 100755 index 0000000000000000000000000000000000000000..354359bc87d03be82b954ca72ada6772f5ccff59 --- /dev/null +++ b/frameworks/ans/native/src/reminder_request.cpp @@ -0,0 +1,577 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ans_log_wrapper.h" +#include "reminder_request.h" +#include "want_agent_helper.h" + +namespace OHOS { +namespace Notification { +uint16_t ReminderRequest::MILLI_SECONDS = 1000; +int32_t ReminderRequest::GLOBAL_ID = 0; +const uint8_t ReminderRequest::REMINDER_STATUS_INACTIVE = 0; +const uint8_t ReminderRequest::REMINDER_STATUS_SHOWING = 4; +const std::string ReminderRequest::REMINDER_EVENT_CLOSE = "ohos.event.notification.reminder.CLOSE"; +const uint64_t ReminderRequest::INVALID_LONG_VALUE = 0; + +ReminderRequest::ReminderRequest() +{ + wantAgentInfo_ = wantAgentInfo_ == nullptr ? std::make_shared() : wantAgentInfo_; +} + +ReminderRequest::ReminderRequest(const ReminderRequest &other) +{ + this->actionButtonMap_ = other.actionButtonMap_; + this->content_ = other.content_; + this->expiredContent_ = other.expiredContent_; + this->notificationId_ = other.notificationId_; + this->reminderId_ = other.reminderId_; + this->reminderType_ = other.reminderType_; + this->slotType_ = other.slotType_; + this->title_ = other.title_; + this->triggerTimeInMilli_ = other.triggerTimeInMilli_; + this->wantAgentInfo_ = other.wantAgentInfo_; +} + +ReminderRequest::ReminderRequest(ReminderType reminderType) +{ + reminderType_ = reminderType; + wantAgentInfo_ = wantAgentInfo_ == nullptr ? std::make_shared() : wantAgentInfo_; +} + +bool ReminderRequest::CanRemove() +{ + if ((state_ & REMINDER_STATUS_SHOWING) == 0) { + return true; + } + return false; +} + +std::string ReminderRequest::Dump() const +{ + struct tm *timeInfo; + const time_t nextTriggerTime = static_cast(triggerTimeInMilli_ / 1000); + timeInfo = localtime(&nextTriggerTime); + uint8_t dateTimeLen = 80; + char dateTimeBuffer[dateTimeLen]; + strftime(dateTimeBuffer, dateTimeLen, "%Y-%m-%d %H:%M:%S", timeInfo); + return "Reminder[" + "id=" + std::to_string(reminderId_) + + ", type=" + std::to_string(static_cast(reminderType_)) + + ", state=" + GetState(state_) + + ", nextTriggerTime=" + dateTimeBuffer + + "]"; // todo +} + +ReminderRequest& ReminderRequest::SetActionButton(const std::string &title, const ActionButtonType &type) +{ + if (type != ActionButtonType::CLOSE) { + REMINDER_LOGI("Button type only support: %{public}d", static_cast(ActionButtonType::CLOSE)); + return *this; + } + ActionButtonInfo actionButtonInfo; + actionButtonInfo.type = type; + actionButtonInfo.title = title; + actionButtonMap_.insert(std::pair(type, actionButtonInfo)); + return *this; +} + +ReminderRequest& ReminderRequest::SetContent(const std::string &content) +{ + content_ = content; + return *this; +} + +ReminderRequest& ReminderRequest::SetExpiredContent(const std::string &expiredContent) +{ + expiredContent_ = expiredContent; + return *this; +} + +void ReminderRequest::SetExpired(bool isExpired) +{ + isExpired_ = isExpired; +} + +void ReminderRequest::InitReminderId() +{ + std::lock_guard lock(std::mutex); + if (GLOBAL_ID < 0) { + REMINDER_LOGW("GLOBAL_ID overdule"); + GLOBAL_ID = 0; + } + reminderId_ = ++GLOBAL_ID; + REMINDER_LOGI("reminderId_=%{public}d", reminderId_); +} + +bool ReminderRequest::IsExpired() const +{ + return isExpired_; +} + +bool ReminderRequest::IsShowing() const +{ + if ((state_ & REMINDER_STATUS_SHOWING) != 0) { + return true; + } + return false; +} + +bool ReminderRequest::OnDateTimeChange() +{ + uint64_t nextTriggerTime = PreGetNextTriggerTimeIgnoreSnooze(false); + return HandleSysTimeChange(triggerTimeInMilli_, nextTriggerTime); +} + +bool ReminderRequest::HandleSysTimeChange(uint64_t oriTriggerTime, uint64_t optTriggerTime) +{ + if (isExpired_) { + return false; + } + bool showImmediately = false; + if (optTriggerTime != INVALID_LONG_VALUE && optTriggerTime <= oriTriggerTime) { + // case1. switch to a previous time + SetTriggerTimeInMilli(optTriggerTime); + } else { + time_t now; + time(&now); // unit is seconds. + if (static_cast(now) < 0) { + REMINDER_LOGE("Get now time error"); + return false; + } + if (oriTriggerTime <= (static_cast(now) * MILLI_SECONDS)) { + // case2. switch to a future time, trigger time is less than now time. + // when the reminder show immediately, trigger time will update in onShow function. + showImmediately = true; + } else { + // case3. switch to a future time, trigger time is larger than now time. + showImmediately = false; + } + } + return showImmediately; +} + +bool ReminderRequest::HandleTimeZoneChange(uint64_t oldZoneTriggerTime, uint64_t newZoneTriggerTime, uint64_t optTriggerTime) +{ + if (isExpired_) { + return false; + } + REMINDER_LOGD("Handle timezone change, oldZoneTriggerTime:%{public}llu, newZoneTriggerTime:%{public}llu", + oldZoneTriggerTime, newZoneTriggerTime); + bool showImmediately = false; + if (optTriggerTime != INVALID_LONG_VALUE && oldZoneTriggerTime < newZoneTriggerTime) { + // case1. timezone change to smaller + SetTriggerTimeInMilli(optTriggerTime); + } else { + time_t now; + time(&now); // unit is seconds. + if (static_cast(now) < 0) { + REMINDER_LOGE("Get now time error"); + return false; + } + if (newZoneTriggerTime <= (static_cast(now))) { + // case2. timezone change to larger + showImmediately = true; + } else { + SetTriggerTimeInMilli(newZoneTriggerTime); + showImmediately = false; + } + } + return showImmediately; +} + +void ReminderRequest::OnSameNotificationIdCovered() +{ + SetState(false, REMINDER_STATUS_SHOWING, "OnSameNotificationIdCovered"); +} + +void ReminderRequest::OnShow(bool isSysTimeChanged, bool allowToNotify) +{ + // todo isSysTimeChanged + if (allowToNotify) { + SetState(true, REMINDER_STATUS_SHOWING, "OnShow"); + } + UpdateNextReminder(); +} + +bool ReminderRequest::OnTimeZoneChange() +{ + time_t oldZoneTriggerTime = static_cast(triggerTimeInMilli_ / MILLI_SECONDS); + struct tm *oriTime; + oriTime = gmtime(&oldZoneTriggerTime); + time_t newZoneTriggerTime = mktime(oriTime); + uint64_t nextTriggerTime = PreGetNextTriggerTimeIgnoreSnooze(false); + return HandleTimeZoneChange(oldZoneTriggerTime, newZoneTriggerTime, nextTriggerTime); +} + +ReminderRequest& ReminderRequest::SetNotificationId(int32_t notificationId) +{ + notificationId_ = notificationId; + return *this; +} + +ReminderRequest& ReminderRequest::SetSlotType(const NotificationConstant::SlotType &slotType) +{ + slotType_ = slotType; + return *this; +} + +ReminderRequest& ReminderRequest::SetTitle(const std::string &title) +{ + title_ = title; + return *this; +} + +void ReminderRequest::SetTriggerTimeInMilli(uint64_t triggerTimeInMilli) +{ + triggerTimeInMilli_ = triggerTimeInMilli; +} + +ReminderRequest& ReminderRequest::SetWantAgentInfo(const std::shared_ptr &wantAgentInfo) +{ + wantAgentInfo_ = wantAgentInfo; + return *this; +} + +std::map ReminderRequest::GetActionButtons() const +{ + return actionButtonMap_; +} + +std::string ReminderRequest::GetContent() const +{ + return content_; +} + +std::string ReminderRequest::GetExpiredContent() const +{ + return expiredContent_; +} + +int32_t ReminderRequest::GetNotificationId() const +{ + return notificationId_; +} + +sptr ReminderRequest::GetNotificationRequest() const +{ + return notificationRequest_; +} + +int32_t ReminderRequest::GetReminderId() const +{ + return reminderId_; +} + +void ReminderRequest::SetReminderId(int32_t reminderId) +{ + reminderId_ = reminderId; +} + +NotificationConstant::SlotType ReminderRequest::GetSlotType() const +{ + return slotType_; +} + +std::string ReminderRequest::GetTitle() const +{ + return title_; +} + +uint64_t ReminderRequest::GetTriggerTimeInMilli() const +{ + return triggerTimeInMilli_; +} + +std::shared_ptr ReminderRequest::GetWantAgentInfo() const +{ + return wantAgentInfo_; +} + +ReminderRequest::ReminderType ReminderRequest::GetReminderType() const +{ + return reminderType_; +} + +bool ReminderRequest::UpdateNextReminder() +{ + return false; +} + +bool ReminderRequest::Marshalling(Parcel &parcel) const +{ + // write string + if (!parcel.WriteString(content_)) { + REMINDER_LOGE("Failed to write content"); + return false; + } + + if (!parcel.WriteString(expiredContent_)) { + REMINDER_LOGE("Failed to write expiredContent"); + return false; + } + + if (!parcel.WriteString(title_)) { + REMINDER_LOGE("Failed to write title"); + return false; + } + + if (!parcel.WriteString(wantAgentInfo_->abilityName)) { + REMINDER_LOGE("Failed to write wantAgentInfo`s abilityName"); + return false; + } + + if (!parcel.WriteString(wantAgentInfo_->pkgName)) { + REMINDER_LOGE("Failed to write wantAgentInfo`s pkgName"); + return false; + } + + // write int + if (!parcel.WriteInt32(reminderId_)) { + REMINDER_LOGE("Failed to write reminderId"); + return false; + } + + if (!parcel.WriteInt32(notificationId_)) { + REMINDER_LOGE("Failed to write notificationId"); + return false; + } + + if (!parcel.WriteUint64(triggerTimeInMilli_)) { + REMINDER_LOGE("Failed to write triggerTimeInMilli"); + return false; + } + + // write enum + if (!parcel.WriteUint8(static_cast(reminderType_))) { + REMINDER_LOGE("Failed to write reminder type"); + return false; + } + + if (!parcel.WriteInt32(static_cast(slotType_))) { + REMINDER_LOGE("Failed to write slot type"); + return false; + } + + // write map + int32_t buttonMapSize = static_cast(actionButtonMap_.size()); + if (!parcel.WriteInt32(buttonMapSize)) { + REMINDER_LOGE("Failed to write action button size"); + return false; + } + + for (auto it = actionButtonMap_.begin(); it != actionButtonMap_.end(); ++it) { + if (!parcel.WriteUint8(static_cast(it->first))) { + REMINDER_LOGE("Failed to write action button type"); + return false; + } + if (!parcel.WriteString(static_cast(it->second.title))) { + REMINDER_LOGE("Failed to write action button title"); + return false; + } + } + + return true; +} + +ReminderRequest *ReminderRequest::Unmarshalling(Parcel &parcel) +{ + auto objptr = new ReminderRequest(); + if ((nullptr != objptr) && !objptr->ReadFromParcel(parcel)) { + delete objptr; + objptr = nullptr; + } + + return objptr; +} + +bool ReminderRequest::ReadFromParcel(Parcel &parcel) +{ + // read string + if (!parcel.ReadString(content_)) { + REMINDER_LOGE("Failed to read content"); + return false; + } + if (!parcel.ReadString(expiredContent_)) { + REMINDER_LOGE("to read expiredContent"); + return false; + } + if (!parcel.ReadString(title_)) { + REMINDER_LOGE("Failed to read title"); + return false; + } + if (!parcel.ReadString(wantAgentInfo_->abilityName)) { + REMINDER_LOGE("Failed to read wantAgentInfo`s abilityName"); + return false; + } + if (!parcel.ReadString(wantAgentInfo_->pkgName)) { + REMINDER_LOGE("Failed to read wantAgentInfo`s pkgName"); + return false; + } + + // read int + int32_t tempReminderId = -1; + if (!parcel.ReadInt32(tempReminderId)) { + REMINDER_LOGE("Failed to read tempReminderId"); + return false; + } + reminderId_ = tempReminderId == -1 ? reminderId_ : tempReminderId; + + if (!parcel.ReadInt32(notificationId_)) { + REMINDER_LOGE("Failed to read notificationId"); + return false; + } + if (!parcel.ReadUint64(triggerTimeInMilli_)) { + REMINDER_LOGE("Failed to read triggerTimeInMilli"); + return false; + } + + // read enum + uint8_t reminderType = static_cast(ReminderType::INVALID); + if (!parcel.ReadUint8(reminderType)) { + REMINDER_LOGE("Failed to read reminderType"); + return false; + } + reminderType_ = static_cast(reminderType); + + int32_t slotType = static_cast(NotificationConstant::SlotType::OTHER); + if (!parcel.ReadInt32(slotType)) { + REMINDER_LOGE("Failed to read slotType"); + return false; + } + slotType_ = static_cast(slotType); + + // read map + int32_t buttonMapSize = 0; + if (!parcel.ReadInt32(buttonMapSize)) { + REMINDER_LOGE("Failed to read buttonMapSize"); + return false; + } + for (int i = 0; i < buttonMapSize; i++) { + uint8_t buttonType = static_cast(ActionButtonType::INVALID); + if (!parcel.ReadUint8(buttonType)) { + REMINDER_LOGE("Failed to read buttonType"); + return false; + } + ActionButtonType type = static_cast(buttonType); + std::string title = parcel.ReadString(); + ActionButtonInfo info; + info.type = type; + info.title = title; + actionButtonMap_.insert(std::pair(type, info)); + } + InitNotificationRequest(); + return true; +} + +void ReminderRequest::InitNotificationRequest() +{ + REMINDER_LOGI("Init notification"); + auto notificationNormalContent = std::make_shared(); + notificationNormalContent->SetText(content_); + notificationNormalContent->SetTitle(title_); + auto notificationContent = std::make_shared(notificationNormalContent); + notificationRequest_ = new NotificationRequest(notificationId_); + notificationRequest_->SetSlotType(slotType_); + notificationRequest_->SetContent(notificationContent); + SetWantAgent(); + // AddActionButtons(); // todo crash +} + +std::string ReminderRequest::GetState(const uint8_t state) const +{ + std::string stateInfo = "Inactive"; + if (state == REMINDER_STATUS_INACTIVE) { + return stateInfo; + } else { + if ((state & REMINDER_STATUS_SHOWING) != 0) { + stateInfo = "Showing"; + } + } + return stateInfo; +} + +void ReminderRequest::AddActionButtons() +{ + REMINDER_LOGD("##1"); + int requestCode = 10; + std::vector flags; + flags.push_back(WantAgent::WantAgentConstant::Flags::UPDATE_PRESENT_FLAG); + REMINDER_LOGD("##2"); + for (auto it = actionButtonMap_.begin(); it != actionButtonMap_.end(); ++it) { + auto want = std::make_shared(); + auto type = it->first; + if (type == ActionButtonType::CLOSE) { + want->SetAction(REMINDER_EVENT_CLOSE); + REMINDER_LOGD("Action button type is close"); + } + want->SetParam("REMINDER_ID", reminderId_); + std::vector> wants; + wants.push_back(want); + REMINDER_LOGD("##3"); + auto title = static_cast(it->second.title); + WantAgent::WantAgentInfo buttonWantAgentInfo( + requestCode, + WantAgent::WantAgentConstant::OperationType::SEND_COMMON_EVENT, + flags, + wants, + nullptr + ); + std::shared_ptr buttonWantAgent = + WantAgent::WantAgentHelper::GetWantAgent(buttonWantAgentInfo); + REMINDER_LOGD("##4"); + std::shared_ptr actionButton + = NotificationActionButton::Create(nullptr, title, buttonWantAgent); + REMINDER_LOGD("##5"); + notificationRequest_->AddActionButton(actionButton); + REMINDER_LOGD("##6"); + } +} + +void ReminderRequest::SetWantAgent() +{ + int requestCode = 10; + std::vector flags; + flags.push_back(WantAgent::WantAgentConstant::Flags::UPDATE_PRESENT_FLAG); + auto want = std::make_shared(); + AppExecFwk::ElementName element("", wantAgentInfo_->pkgName, wantAgentInfo_->abilityName); + want->SetElement(element); + std::vector> wants; + wants.push_back(want); + WantAgent::WantAgentInfo wantAgentInfo( + requestCode, + WantAgent::WantAgentConstant::OperationType::START_ABILITY, + flags, + wants, + nullptr + ); + std::shared_ptr wantAgent = WantAgent::WantAgentHelper::GetWantAgent(wantAgentInfo); + notificationRequest_->SetWantAgent(wantAgent); +} + +void ReminderRequest::SetState(bool deSet, const uint8_t newState, std::string function) +{ + uint8_t oldState = state_; + if (deSet) { + state_ |= newState; + } else { + state_ &= ~newState; + } + REMINDER_LOGI("Switch the reminder(id=%{public}d) state, from %{public}s to %{public}s, called by %{public}s", + reminderId_, GetState(oldState).c_str(), GetState(state_).c_str(), function.c_str()); +} +} +} \ No newline at end of file diff --git a/frameworks/ans/native/src/reminder_request_alarm.cpp b/frameworks/ans/native/src/reminder_request_alarm.cpp new file mode 100755 index 0000000000000000000000000000000000000000..91f861487257b8b51d58ac9db8b6bebd94ff3225 --- /dev/null +++ b/frameworks/ans/native/src/reminder_request_alarm.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "ans_log_wrapper.h" +#include "reminder_request_alarm.h" + +namespace OHOS { +namespace Notification { +const uint8_t ReminderRequestAlarm::DAYS_PER_WEEK = 7; +const uint8_t ReminderRequestAlarm::MONDAY = 1; +const uint8_t ReminderRequestAlarm::SUNDAY = 7; +const uint8_t ReminderRequestAlarm::HOURS_PER_DAY = 24; +const uint16_t ReminderRequestAlarm::SECONDS_PER_HOUR = 3600; +const uint8_t ReminderRequestAlarm::MINUTES_PER_HOUR = 60; +const int8_t ReminderRequestAlarm::INVALID_INT_VALUE = -1; + +ReminderRequestAlarm::ReminderRequestAlarm(uint8_t hour, uint8_t minute, const std::vector daysOfWeek) +: ReminderRequest(ReminderRequest::ReminderType::ALARM) +{ + REMINDER_LOGD("hour_=%{public}d, minute_=%{public}d", hour_, minute_); + hour_ = hour; + minute_ = minute; + CheckParamValid(); + SetDaysOfWeek(true, daysOfWeek); + SetTriggerTimeInMilli(GetNextTriggerTime(true)); +} + +ReminderRequestAlarm::ReminderRequestAlarm(const ReminderRequestAlarm &other) : ReminderRequest(other) +{ + this->hour_ = other.hour_; + REMINDER_LOGD("this->hour_=%{public}d", this->hour_); + this->minute_ = other.minute_; + this->repeatDays_ = other.repeatDays_; +} + +void ReminderRequestAlarm::CheckParamValid() const +{ + if (hour_ >= HOURS_PER_DAY || hour_ < 0) { + REMINDER_LOGE("setted hour is not between [0, 24)"); + throw std::invalid_argument("setted hour is not between [0, 24)"); + } + if (minute_ < 0 || minute_ >= MINUTES_PER_HOUR) { + REMINDER_LOGE("setted minute is not between [0, 60)"); + throw std::invalid_argument("setted minute is not between [0, 60)"); + } +} + +void ReminderRequestAlarm::SetDaysOfWeek(bool set, std::vector daysOfWeek) +{ + if (daysOfWeek.size() == 0) { + return; + } + if (daysOfWeek.size() > DAYS_PER_WEEK) { + REMINDER_LOGE("The length of daysOfWeek should not larger than 7"); + throw std::invalid_argument("The length of daysOfWeek should not larger than 7"); + } + for (std::vector::iterator it = daysOfWeek.begin(); it != daysOfWeek.end(); ++it) { + if (*it < MONDAY || *it > SUNDAY) { + continue; + } + if (set) { + repeatDays_ |= 1 << (*it - 1); + } else { + repeatDays_ &= ~(1 << (*it - 1)); + } + } +} + +uint64_t ReminderRequestAlarm::PreGetNextTriggerTimeIgnoreSnooze(bool forceToGetNext) const +{ + return GetNextTriggerTime(false); +} + +uint64_t ReminderRequestAlarm::GetNextTriggerTime(bool forceToGetNext) const +{ + time_t now; + time(&now); // unit is seconds. + struct tm *nowTime; + nowTime = localtime(&now); + REMINDER_LOGI("Now: year=%{public}d, mon=%{public}d, day=%{public}d, hour=%{public}d, " + "min=%{public}d, sec=%{public}d, week=%{public}d, tar_hour=%{public}d, tar_min=%{public}d", + nowTime->tm_year, nowTime->tm_mon, nowTime->tm_mday, nowTime->tm_hour, + nowTime->tm_min, nowTime->tm_sec, nowTime->tm_wday, hour_, minute_); + + struct tm tar; + tar.tm_year = nowTime->tm_year; + tar.tm_mon = nowTime->tm_mon; + tar.tm_mday = nowTime->tm_mday; + tar.tm_hour = hour_; + tar.tm_min = minute_; + tar.tm_sec = 0; + const time_t target = mktime(&tar); + REMINDER_LOGI("Target: year=%{public}d, mon=%{public}d, day=%{public}d, hour=%{public}d, " + "min=%{public}d, sec=%{public}d, week=%{public}d", + tar.tm_year, tar.tm_mon, tar.tm_mday, tar.tm_hour, tar.tm_min, tar.tm_sec, tar.tm_wday); + + int8_t nextDayInterval = GetNextAlarm(now, target); + time_t nextTriggerTime = 0; + if (nextDayInterval == INVALID_INT_VALUE) { + if (now >= target) { + if (forceToGetNext) { + nextTriggerTime = target + 1 * HOURS_PER_DAY * SECONDS_PER_HOUR; + } + } else { + nextTriggerTime = target; + } + } else { + nextTriggerTime = target + nextDayInterval * HOURS_PER_DAY * SECONDS_PER_HOUR; + } + struct tm *test; + test = localtime(&nextTriggerTime); + REMINDER_LOGI("NextTriggerTime: year=%{public}d, mon=%{public}d, day=%{public}d, hour=%{public}d, " + "min=%{public}d, sec=%{public}d, week=%{public}d, nextTriggerTime=%{public}ld", test->tm_year, + test->tm_mon, test->tm_mday, test->tm_hour, test->tm_min, test->tm_sec, test->tm_wday, nextTriggerTime); + + if (static_cast(nextTriggerTime) <= 0) { + return 0; + } + return static_cast(nextTriggerTime) * ReminderRequest::MILLI_SECONDS; +} + +int8_t ReminderRequestAlarm::GetNextAlarm(const time_t now, const time_t target) const +{ + if (repeatDays_ == 0) { + return INVALID_INT_VALUE; + } + int today = gmtime(&now)->tm_wday; + int dayCount = now >= target ? 1 : 0; + for (; dayCount <= DAYS_PER_WEEK; dayCount++) { + int day = (today + dayCount) % DAYS_PER_WEEK; + day = (day == 0) ? SUNDAY : day; + if (IsRepeatDay(day)) { + break; + } + } + REMINDER_LOGI("NextDayInterval is %{public}d", dayCount); + return dayCount; +} + +bool ReminderRequestAlarm::IsRepeatDay(int day) const +{ + return (repeatDays_ & (1 << (day - 1))) > 0; +} + +std::vector ReminderRequestAlarm::GetDaysOfWeek() const +{ + std::vector repeatDays; + int days[] = {1, 2, 3, 4, 5, 6, 7}; + int len = sizeof(days) / sizeof(int); + for (int i = 0; i < len; i++) { + if (IsRepeatDay(days[i])) { + repeatDays.push_back(days[i]); + } + } + return repeatDays; +} + +uint8_t ReminderRequestAlarm::GetHour() const +{ + return hour_; +} + +uint8_t ReminderRequestAlarm::GetMinute() const +{ + return minute_; +} + +bool ReminderRequestAlarm::UpdateNextReminder() +{ + if (repeatDays_ == 0) { + REMINDER_LOGD("Set reminder to expired"); + SetExpired(true); + return false; + } + uint64_t nextTriggerTime = GetNextTriggerTime(true); + if (nextTriggerTime != 0) { + REMINDER_LOGI("Set next trigger time=%{public}llu", nextTriggerTime); + SetTriggerTimeInMilli(nextTriggerTime); + return true; + } else { + REMINDER_LOGD("Set reminder to expired"); + SetExpired(true); + return false; + } +} + +bool ReminderRequestAlarm::Marshalling(Parcel &parcel) const +{ + ReminderRequest::Marshalling(parcel); + + // write int + if (!parcel.WriteUint8(hour_)) { + REMINDER_LOGE("Failed to write hour"); + return false; + } + if (!parcel.WriteUint8(minute_)) { + REMINDER_LOGE("Failed to write minute"); + return false; + } + if (!parcel.WriteUint8(repeatDays_)) { + REMINDER_LOGE("Failed to write daysOfWeek"); + return false; + } + + return true; +} + +ReminderRequestAlarm *ReminderRequestAlarm::Unmarshalling(Parcel &parcel) +{ + std::vector daysOfWeek; + REMINDER_LOGD("New alarm"); + auto objptr = new ReminderRequestAlarm(); + if ((nullptr != objptr) && !objptr->ReadFromParcel(parcel)) { + delete objptr; + objptr = nullptr; + } + return objptr; +} + +bool ReminderRequestAlarm::ReadFromParcel(Parcel &parcel) +{ + ReminderRequest::ReadFromParcel(parcel); + + // read int + if (!parcel.ReadUint8(hour_)) { + REMINDER_LOGE("Failed to read hour"); + return false; + } + REMINDER_LOGD("Hour_=%{public}d", hour_); + if (!parcel.ReadUint8(minute_)) { + REMINDER_LOGE("Failed to read minute"); + return false; + } + if (!parcel.ReadUint8(repeatDays_)) { + REMINDER_LOGE("Failed to read repeatDays"); + return false; + } + return true; +} +} +} \ No newline at end of file diff --git a/frameworks/ans/native/src/reminder_request_timer.cpp b/frameworks/ans/native/src/reminder_request_timer.cpp new file mode 100755 index 0000000000000000000000000000000000000000..215b45720a4d75557b879a195ffd572445e9c6c8 --- /dev/null +++ b/frameworks/ans/native/src/reminder_request_timer.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "ans_log_wrapper.h" +#include "reminder_request_timer.h" + +namespace OHOS { +namespace Notification { +ReminderRequestTimer::ReminderRequestTimer(uint64_t countDownTimeInSeconds) +: ReminderRequest(ReminderRequest::ReminderType::TIMER) +{ + CheckParamsValid(countDownTimeInSeconds); + time_t now; // unit is seconds. + time(&now); + firstRealTimeInMilliSeconds_ = static_cast(now) * ReminderRequest::MILLI_SECONDS; + countDownTimeInSeconds_ = countDownTimeInSeconds; + ReminderRequest::SetTriggerTimeInMilli( + firstRealTimeInMilliSeconds_ + countDownTimeInSeconds_ * ReminderRequest::MILLI_SECONDS); +} + +ReminderRequestTimer::ReminderRequestTimer(const ReminderRequestTimer &other) : ReminderRequest(other) +{ + firstRealTimeInMilliSeconds_ = other.firstRealTimeInMilliSeconds_; + countDownTimeInSeconds_ = other.countDownTimeInSeconds_; +} + +uint64_t ReminderRequestTimer::GetInitInfo() const +{ + return countDownTimeInSeconds_; +} + +uint64_t ReminderRequestTimer::PreGetNextTriggerTimeIgnoreSnooze(bool forceToGetNext) const +{ + REMINDER_LOGD("countdonw time not support PreGetNextTriggerTimeIgnoreSnooze"); + return ReminderRequest::INVALID_LONG_VALUE; +} + +bool ReminderRequestTimer::UpdateNextReminder() +{ + REMINDER_LOGD("countdonw time not support repeat reminder, no need to update next triggerTime"); + SetExpired(true); + return false; +} + +void ReminderRequestTimer::CheckParamsValid(const uint64_t countDownTimeInSeconds) const +{ + uint64_t maxVal = 1000000; // todo + if (countDownTimeInSeconds == 0 || countDownTimeInSeconds >= maxVal / ReminderRequest::MILLI_SECONDS) { + REMINDER_LOGE("Illegal count down time, please check the description of the constructor"); + throw std::invalid_argument("Illegal count down time, please check the description of the constructor"); + } +} + +bool ReminderRequestTimer::Marshalling(Parcel &parcel) const +{ + ReminderRequest::Marshalling(parcel); + + // write int + if (!parcel.WriteUint64(firstRealTimeInMilliSeconds_)) { + REMINDER_LOGE("Failed to write firstRealTimeInMilliSeconds"); + return false; + } + if (!parcel.WriteUint64(countDownTimeInSeconds_)) { + REMINDER_LOGE("Failed to write countDownTimeInSeconds"); + return false; + } + return true; +} + +ReminderRequestTimer *ReminderRequestTimer::Unmarshalling(Parcel &parcel) +{ + auto objptr = new ReminderRequestTimer(); + if ((nullptr != objptr) && !objptr->ReadFromParcel(parcel)) { + delete objptr; + objptr = nullptr; + } + return objptr; +} + +bool ReminderRequestTimer::ReadFromParcel(Parcel &parcel) +{ + ReminderRequest::ReadFromParcel(parcel); + + // read int + if (!parcel.ReadUint64(firstRealTimeInMilliSeconds_)) { + REMINDER_LOGE("Failed to read firstRealTimeInMilliSeconds"); + return false; + } + if (!parcel.ReadUint64(countDownTimeInSeconds_)) { + REMINDER_LOGE("Failed to read countDownTimeInSeconds"); + return false; + } + return true; +} +} +} \ No newline at end of file diff --git a/interfaces/innerkits/ans/native/include/reminder_request.h b/interfaces/innerkits/ans/native/include/reminder_request.h new file mode 100755 index 0000000000000000000000000000000000000000..c356d05de9558ff498379500125d25399adfb770 --- /dev/null +++ b/interfaces/innerkits/ans/native/include/reminder_request.h @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_H +#define BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_H + +#include +#include + +#include "notification_constant.h" +#include "notification_request.h" + +namespace OHOS { +namespace Notification { +class ReminderRequest : public Parcelable { +public: + /** + * Supported reminder type. + */ + enum class ReminderType : uint8_t { + /** + * Indicates the classification of reminder for timer. + */ + TIMER, + /** + * Indicates the classification of reminder for calendar. + */ + CALENDAR, + /** + * Indicates the classification of reminder for alarm. + */ + ALARM, + INVALID + }; + + /** + * Supported action button type. + */ + enum class ActionButtonType : uint8_t { + CLOSE, + INVALID + }; + + /** + * Attributes of action button. + */ + struct ActionButtonInfo + { + /** + * Type of the button. + */ + ActionButtonType type; + + /** + * Content show on the button. + */ + std::string title; + }; + + /** + * Want agent information. Indicates the package and the ability to switch to. + */ + struct WantAgentInfo + { + std::string pkgName = ""; + std::string abilityName = ""; + }; + + /** + * @brief Copy construct from an exist reminder. + * + * @param Indicates the exist reminder. + */ + ReminderRequest(const ReminderRequest &other); + ReminderRequest(ReminderType reminderType); + ~ReminderRequest() {}; + + /** + * Marshal a NotificationRequest object into a Parcel. + * @param parcel the object into the parcel + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * Unmarshal object from a Parcel. + * @return the NotificationRequest + */ + static ReminderRequest *Unmarshalling(Parcel &parcel); + virtual bool ReadFromParcel(Parcel &parcel); + + /** + * If the reminder is showing on the notification panel, it should not be removed automatically. + * + * @return true if it can be removed automatically. + */ + bool CanRemove(); + + /** + * Obtains all the information of the reminder. + * + * @return Information of the reminder. + */ + std::string Dump() const; + + /** + * Obtains the configured action buttons. + * + * @return map of action buttons. + */ + std::map GetActionButtons() const; + + /** + * Obtains the configured content. + * + * @return content text. + */ + std::string GetContent() const; + + /** + * Obtains the configured expired content. + * + * @return expired content text. + */ + std::string GetExpiredContent() const; + + /** + * Obtains notification id. + * + * @return notification id. + */ + int32_t GetNotificationId() const; + + /** + * Obtains notification request. + * + * @return notification request instance. + */ + sptr GetNotificationRequest() const; + + /** + * Obtains reminder id. + * + * @return reminder id. + */ + int32_t GetReminderId() const; + + /** + * Obtains reminder type. + * + * @return reminder type. + */ + ReminderType GetReminderType() const; + + /** + * Obtains slot type. + * + * @return slot type. + */ + NotificationConstant::SlotType GetSlotType() const; + + /** + * Obtains title. + * + * @return title. + */ + std::string GetTitle() const; + + /** + * Obtains trigger time in milli. + * + * @return trigger time. + */ + uint64_t GetTriggerTimeInMilli() const; + + /** + * Obtains want agent information. + * + * @return want agent information. + */ + std::shared_ptr GetWantAgentInfo() const; + + /** + * Inits reminder id when publish reminder success. + */ + void InitReminderId(); + + /** + * Check the reminder is expired or not. + * + * @return true is the reminder is expired. + */ + bool IsExpired() const; + + /** + * Check the reminder is showing on the panel. + * + * @return true if the reminder is showing on the panel. + */ + bool IsShowing() const; + + /** + * @brief When date/time change, reminder need to refresh next trigger time. + * + * @return true if date/time is changed to earlier, otherwise return false. + */ + bool OnDateTimeChange(); + + /** + * When shown notification is covered by a new notification with the same id, we should remove the state of showing, so + * that the reminder can be removed automatically when it is expired. + */ + void OnSameNotificationIdCovered(); + + /** + * @brief Show the reminder on panel. TriggerTime will be updated to next. + * + * @param isSysTimeChanged true means it is called when the system time is changed by user, otherwise false. + * @param allowToNotify true means that the notification will be shown as normal, otherwise false. + */ + void OnShow(bool isSysTimeChanged, bool allowToNotify); + + /** + * @brief When timezone change, reminder need to refresh next trigger time. + * + * @return true if need to show reminder immediately. + */ + bool OnTimeZoneChange(); + + /** + * Sets action button. + * + * @param title Indicates the title of the button. + * @param type Indicates the type of the button. + * @return Current reminder self. + */ + ReminderRequest& SetActionButton(const std::string &title, const ActionButtonType &type); + + /** + * Sets reminder content. + * + * @param content Indicates content text. + * @return Current reminder self. + */ + ReminderRequest& SetContent(const std::string &content); + + /** + * Sets reminder is expired or not. + * + * @param isExpired Indicates the reminder is expired or not. + */ + void SetExpired(bool isExpired); + + /** + * Sets expired content. + * + * @param expiredContent Indicates expired content. + * @return Current reminder self. + */ + ReminderRequest& SetExpiredContent(const std::string &expiredContent); + + /** + * Sets notification id. + * + * @param notificationId Indicates notification id. + * @return Current reminder self. + */ + ReminderRequest& SetNotificationId(int32_t notificationId); + + /** + * Sets reminder id. + * + * @param reminderId Indicates reminder id. + */ + void SetReminderId(int32_t reminderId); + + /** + * Sets slot type. + * + * @param slotType Indicates slot type. + * @return Current slot type self. + */ + ReminderRequest& SetSlotType(const NotificationConstant::SlotType &slotType); + + /** + * Sets title. + * + * @param title Indicates title. + * @return Current reminder self. + */ + ReminderRequest& SetTitle(const std::string &title); + + /** + * Sets trigger time. + * + * @param triggerTimeInMilli Indicates trigger time in milli. + */ + void SetTriggerTimeInMilli(uint64_t triggerTimeInMilli); + + /** + * Sets want agent information. + * + * @param wantAgentInfo Indicates want agent information. + * @return Current reminder self. + */ + ReminderRequest& SetWantAgentInfo(const std::shared_ptr &wantAgentInfo); + + /** + * @brief Updates {@link triggerTimeInMilli_} to next. + * @note If next trigger time not exist, {@link isExpired_} flag will be set with true. + * + * @return true if next trigger time exist and set success. + */ + virtual bool UpdateNextReminder(); + + static uint16_t MILLI_SECONDS; + static int32_t GLOBAL_ID; + static const std::string REMINDER_EVENT_CLOSE; + static const uint64_t INVALID_LONG_VALUE; + +protected: + ReminderRequest(); + virtual uint64_t PreGetNextTriggerTimeIgnoreSnooze(bool forceToGetNext) const { + return INVALID_LONG_VALUE; + }; + +private: + void AddActionButtons(); + std::string GetState(const uint8_t state) const; + bool HandleSysTimeChange(uint64_t oriTriggerTime, uint64_t optTriggerTime); + bool HandleTimeZoneChange(uint64_t oldZoneTriggerTime, uint64_t newZoneTriggerTime, uint64_t optTriggerTime); + void InitNotificationRequest(); + void SetState(bool deSet, const uint8_t newState, std::string function); + void SetWantAgent(); + std::map actionButtonMap_ {}; + + static const uint8_t REMINDER_STATUS_INACTIVE; + static const uint8_t REMINDER_STATUS_SHOWING; + + std::string content_ {}; + std::string expiredContent_ {}; + bool isExpired_ {false}; + int32_t notificationId_ {0}; + sptr notificationRequest_ = nullptr; + int32_t reminderId_ {-1}; + ReminderType reminderType_ {ReminderType::INVALID}; + NotificationConstant::SlotType slotType_ {NotificationConstant::SlotType::SOCIAL_COMMUNICATION}; + uint8_t state_ {0}; + std::string title_ {}; + uint64_t triggerTimeInMilli_; + std::shared_ptr wantAgentInfo_ = nullptr; +}; +} // namespace Reminder +} // namespace OHOS +#endif // BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_H diff --git a/interfaces/innerkits/ans/native/include/reminder_request_alarm.h b/interfaces/innerkits/ans/native/include/reminder_request_alarm.h new file mode 100755 index 0000000000000000000000000000000000000000..bf1c1120571cf4d807dc6760fb6e6d392d22acff --- /dev/null +++ b/interfaces/innerkits/ans/native/include/reminder_request_alarm.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_ALARM_H +#define BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_ALARM_H + +#include "reminder_request.h" + +#include +#include + +namespace OHOS { +namespace Notification { +class ReminderRequestAlarm : public ReminderRequest { +public: + /** + * @brief A {@link ReminderRequest} child class used for creating reminders of alarm clocks. + * You can use this class to publish alarm reminders at a specified time (accurate to minute) on a + * particular day or on particular days every week. + * + * @param hour The value must between [0, 23]. + * @param minute The value must between [0, 59]. + * @param daysOfWeek The value must between [1, 7], and the length of array can not be greater than 7. + * + * @see ReminderRequestTimer + */ + ReminderRequestAlarm(uint8_t hour, uint8_t minute, std::vector daysOfWeek); + + /** + * @brief Copy construct from an exist reminder. + * + * @param Indicates the exist alarm reminder. + */ + ReminderRequestAlarm(const ReminderRequestAlarm &other); + ~ReminderRequestAlarm(){}; + + /** + * Obtains the repeat days vector. + * + * @return vector of repeat days. + */ + std::vector GetDaysOfWeek() const; + + /** + * @brief Obtains the setted {@link hour_}. + * + * @return setted hour. + */ + uint8_t GetHour() const; + + /** + * @brief Obtains the setted {@link minute_}. + * + * @return setted minute. + */ + uint8_t GetMinute() const; + + virtual bool UpdateNextReminder() override; + + /** + * Marshal a reminder object into a Parcel. + * + * @param parcel Indicates the Parcel. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * Unmarshal object from a Parcel. + * + * @param parcel Indicates the Parcel. + * @return reminder object. + */ + static ReminderRequestAlarm *Unmarshalling(Parcel &parcel); + + /** + * Unmarshal unique properties of alarm from a Parcel. + * + * @param parcel Indicates the Parcel. + * @return true if read parcel success. + */ + bool ReadFromParcel(Parcel &parcel) override; + +protected: + virtual uint64_t PreGetNextTriggerTimeIgnoreSnooze(bool forceToGetNext) const override; + +private: + ReminderRequestAlarm() : ReminderRequest() {}; + void CheckParamValid() const; + + /** + * Obtains the next trigger time. + * + * @param forceToGetNext Indicates whether force to get next reminder. + * When set the alarm firstly, you should set force with true, so if repeat information + * is not set, and the target time is overdue, the reminder will be set to next day. + * When change the time manually by user, you should set force with false, so if repeat + * information is not set, and target time is overdue, the reminder will not be set to + * next day. + * @return next trigger time in milli. + */ + uint64_t GetNextTriggerTime(bool forceToGetNext) const; + + /** + * Judge is it the repeat day setted by user or not. + * + * @param day Indicates the day of week. + * @return true if it is a repeat day. + */ + bool IsRepeatDay(int day) const; + void SetDaysOfWeek(bool set, std::vector daysOfWeek); + + /** + * Obtains the next day interval if it is a week repeat alarm. + * + * @param now Indicates current time. + * @param now Indicatet target time. + * @return next day interval. Returns {@link INVALID_INT_VALUE} if it is not a week repeat alarm. + */ + int8_t GetNextAlarm(const time_t now, const time_t target) const; + + static const uint8_t DAYS_PER_WEEK; + static const uint8_t MONDAY; + static const uint8_t SUNDAY; + static const uint8_t HOURS_PER_DAY; + static const uint16_t SECONDS_PER_HOUR; + static const uint8_t MINUTES_PER_HOUR; + static const int8_t INVALID_INT_VALUE; + + uint8_t hour_ = {0}; + uint8_t minute_ = {0}; + uint8_t repeatDays_ = {0}; +}; + +} // namespace Notification +} // namespace OHOS + +#endif // BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_ALARM_H \ No newline at end of file diff --git a/interfaces/innerkits/ans/native/include/reminder_request_timer.h b/interfaces/innerkits/ans/native/include/reminder_request_timer.h new file mode 100755 index 0000000000000000000000000000000000000000..5ccb342cae8650969ed65109c89d2235c2d2543b --- /dev/null +++ b/interfaces/innerkits/ans/native/include/reminder_request_timer.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_TIMER_H +#define BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_TIMER_H + +#include "reminder_request.h" + +namespace OHOS { +namespace Notification { +class ReminderRequestTimer : public ReminderRequest { +public: + /** + * A constructor used to create a ReminderRequestTimer instance. The countdown timer reminder + * will be triggered after a specified duration. + * + * @note The input parameter must be larger than 0, + * otherwise, the application may crash due to an illegal parameter exception. + * + * @param countDownTimeInSeconds Indicates the duration after which this timer reminder will be triggered. + */ + ReminderRequestTimer(uint64_t countDownTimeInSeconds); + + /** + * @brief Copy construct from an exist reminder. + * + * @param Indicates the exist reminder. + */ + ReminderRequestTimer(const ReminderRequestTimer &other); + ~ReminderRequestTimer(){}; + + uint64_t GetInitInfo() const; + + virtual bool UpdateNextReminder() override; + + /** + * Marshal a NotificationRequest object into a Parcel. + * @param parcel the object into the parcel + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * Unmarshal object from a Parcel. + * @return the NotificationRequest + */ + static ReminderRequestTimer *Unmarshalling(Parcel &parcel); + + bool ReadFromParcel(Parcel &parcel) override; + +protected: + virtual uint64_t PreGetNextTriggerTimeIgnoreSnooze(bool forceToGetNext) const override; + +private: + ReminderRequestTimer(){}; + void CheckParamsValid(const uint64_t countDownTimeInSeconds) const; + uint64_t countDownTimeInSeconds_; + uint64_t firstRealTimeInMilliSeconds_ {-1}; +}; + +} // namespace Reminder +} // namespace OHOS +#endif // BASE_NOTIFICATION_ANS_STANDARD_FRAMEWORKS_ANS_CORE_INCLUDE_REMINDER_REQUEST_TIMER_H \ No newline at end of file