* Copyright (c) 2022-2026 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 "task_notification_subscriber.h"
#include <sstream>
#include "bg_continuous_task_mgr.h"
#include "bgtask_hitrace_chain.h"
#include "common_utils.h"
#include "continuous_task_log.h"
#include "string_wrapper.h"
#include "notification_content.h"
#include "int_wrapper.h"
#include "res_type.h"
extern "C" void ReportDataInProcess(uint32_t resType, int64_t value, const nlohmann::json& payload);
namespace OHOS {
namespace BackgroundTaskMgr {
namespace {
static constexpr char LABEL_SPLITER = '_';
static constexpr char NOTIFICATION_PREFIX[] = "bgmode";
static constexpr uint32_t LABEL_BGMODE_PREFIX_POS = 0;
static constexpr uint32_t LABEL_APP_UID_POS = 1;
static constexpr uint32_t LABEL_SIZE = 5;
static constexpr uint32_t LABEL_ABILITYID_INDEX = 3;
static constexpr uint32_t LABEL_TASKID_INDEX = 4;
static constexpr uint32_t LABEL_BANNER_SIZE = 4;
static constexpr char NAVIGATION[] = "NAVIGATION";
static constexpr int32_t CAPSULE_STATUS_ACTIVE = 1;
}
std::shared_ptr<BgContinuousTaskMgr> TaskNotificationSubscriber::continuousTaskMgr_
= BgContinuousTaskMgr::GetInstance();
TaskNotificationSubscriber::TaskNotificationSubscriber() {}
TaskNotificationSubscriber::~TaskNotificationSubscriber() {}
void TaskNotificationSubscriber::OnConnected() {}
void TaskNotificationSubscriber::OnDisconnected() {}
void TaskNotificationSubscriber::OnCanceled(const std::shared_ptr<Notification::Notification> ¬ification,
const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap, int deleteReason)
{
BgTaskHiTraceChain traceChain(__func__);
if (notification == nullptr) {
BGTASK_LOGW("notification param is null");
return;
}
const Notification::NotificationRequest &request = notification->GetNotificationRequest();
auto notificationType = request.GetNotificationType();
int32_t creatorUid = request.GetCreatorUid();
if (creatorUid == continuousTaskMgr_->GetBgTaskUid()) {
CancelNotificationByBgTask(request, deleteReason);
} else if ((creatorUid == request.GetOwnerUid()) &&
notificationType == Notification::NotificationContent::Type::LIVE_VIEW) {
std::string eventName = "";
int32_t capsuleStatus = 0;
GetLiveViewExtraInfo(request, eventName, capsuleStatus);
if (eventName == NAVIGATION) {
continuousTaskMgr_->SetLiveViewInfo(creatorUid, false, eventName);
continuousTaskMgr_->SendNotificationByLiveViewCancel(creatorUid);
}
nlohmann::json payload;
payload["uid"] = std::to_string(creatorUid);
payload["eventName"] = eventName;
ReportDataInProcess(ResourceSchedule::ResType::RES_TYPE_LIVE_VIEW_EVENT,
ResourceSchedule::ResType::LiveViewState::LIVE_VIEW_EXIT, payload);
}
}
void TaskNotificationSubscriber::OnConsumed(const std::shared_ptr<Notification::Notification> ¬ification,
const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap)
{
BgTaskHiTraceChain traceChain(__func__);
if (notification == nullptr) {
BGTASK_LOGW("notification param is null");
return;
}
const Notification::NotificationRequest &request = notification->GetNotificationRequest();
int32_t creatorUid = request.GetCreatorUid();
if (creatorUid == continuousTaskMgr_->GetBgTaskUid()) {
return;
}
auto notificationType = request.GetNotificationType();
if (notificationType != Notification::NotificationContent::Type::LIVE_VIEW) {
return;
}
std::string eventName = "";
int32_t capsuleStatus = 0;
GetLiveViewExtraInfo(request, eventName, capsuleStatus);
if (capsuleStatus == CAPSULE_STATUS_ACTIVE && eventName == NAVIGATION) {
continuousTaskMgr_->SetLiveViewInfo(creatorUid, true, eventName);
continuousTaskMgr_->CancelBgTaskNotification(creatorUid);
}
nlohmann::json payload;
payload["uid"] = std::to_string(creatorUid);
payload["eventName"] = eventName;
uint32_t type = ResourceSchedule::ResType::RES_TYPE_LIVE_VIEW_EVENT;
int32_t value = capsuleStatus == CAPSULE_STATUS_ACTIVE ?
ResourceSchedule::ResType::LiveViewState::LIVE_VIEW_ENTER :
ResourceSchedule::ResType::LiveViewState::LIVE_VIEW_EXIT;
ReportDataInProcess(type, value, payload);
}
void TaskNotificationSubscriber::OnUpdate(
const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap) {}
void TaskNotificationSubscriber::OnDied() {}
void TaskNotificationSubscriber::OnDoNotDisturbDateChange(
const std::shared_ptr<Notification::NotificationDoNotDisturbDate> &date) {}
void TaskNotificationSubscriber::OnEnabledNotificationChanged(
const std::shared_ptr<Notification::EnabledNotificationCallbackData> &callbackData) {}
void TaskNotificationSubscriber::OnBadgeChanged(
const std::shared_ptr<Notification::BadgeNumberCallbackData> &badgeData) {}
void TaskNotificationSubscriber::OnBadgeEnabledChanged(
const sptr<Notification::EnabledNotificationCallbackData> &callbackData) {}
void TaskNotificationSubscriber::OnBatchCanceled(const std::vector<std::shared_ptr<Notification::Notification>>
&requestList, const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap, int32_t deleteReason) {}
std::vector<std::string> TaskNotificationSubscriber::StringSplit(const std::string &str, const char &delim)
{
std::vector<std::string> ret;
std::stringstream ss(str);
std::string tmp;
while (getline(ss, tmp, delim)) {
ret.push_back(tmp);
}
return ret;
}
void TaskNotificationSubscriber::CancelNotificationByBgTask(
const Notification::NotificationRequest &request, int32_t deleteReason)
{
std::string notificationLabel = request.GetLabel();
std::vector<std::string> labelSplits = StringSplit(notificationLabel, LABEL_SPLITER);
if (labelSplits.size() == LABEL_BANNER_SIZE &&
labelSplits[LABEL_BGMODE_PREFIX_POS] == BANNER_NOTIFICATION_PREFIX) {
if (continuousTaskMgr_->StopBannerContinuousTaskByUser(notificationLabel)) {
BGTASK_LOGI("remove banner notification, label: %{public}s", notificationLabel.c_str());
}
return;
}
if (labelSplits.empty() || labelSplits[LABEL_BGMODE_PREFIX_POS] != NOTIFICATION_PREFIX
|| labelSplits.size() > LABEL_SIZE + 1 || labelSplits.size() < LABEL_SIZE - 1) {
BGTASK_LOGW("callback notification label is invalid");
return;
}
if (deleteReason == Notification::NotificationConstant::APP_CANCEL_REASON_DELETE) {
BGTASK_LOGD("notification remove action is already triggered by cancel method.");
return;
}
std::shared_ptr<AAFwk::WantParams> extraInfo = request.GetAdditionalData();
if (extraInfo == nullptr) {
BGTASK_LOGE("notification extraInfo is null");
return;
}
BGTASK_LOGI("stop continuous task by user, the label is : %{public}s, the reason is %{public}d",
notificationLabel.c_str(), deleteReason);
if (deleteReason >= Notification::NotificationConstant::TRIGGER_EIGHT_HOUR_REASON_DELETE &&
deleteReason <= Notification::NotificationConstant::TRIGGER_THIRTY_MINUTES_REASON_DELETE) {
BGTASK_LOGI("more than 10 min not update notification, notification remove.");
}
std::string abilityName = AAFwk::String::Unbox(AAFwk::IString::Query(extraInfo->GetParam("abilityName")));
std::string taskInfoMapKey = labelSplits[LABEL_APP_UID_POS] + LABEL_SPLITER + abilityName +
LABEL_SPLITER + labelSplits[LABEL_ABILITYID_INDEX];
if (labelSplits.size() == LABEL_SIZE || labelSplits.size() == LABEL_SIZE + 1) {
taskInfoMapKey = taskInfoMapKey + LABEL_SPLITER + labelSplits[LABEL_TASKID_INDEX];
}
bool isSubNotification = false;
if (labelSplits.size() == LABEL_SIZE + 1) {
isSubNotification = true;
}
if (continuousTaskMgr_->StopContinuousTaskByUser(taskInfoMapKey, isSubNotification, deleteReason)) {
BGTASK_LOGI("remove continuous task record Key: %{public}s", taskInfoMapKey.c_str());
}
}
void TaskNotificationSubscriber::GetLiveViewExtraInfo(const Notification::NotificationRequest &request,
std::string &eventName, int32_t &capsuleStatus)
{
std::shared_ptr<Notification::NotificationContent> content = request.GetContent();
if (content == nullptr) {
BGTASK_LOGE("content is nullptr");
return;
}
std::shared_ptr<Notification::NotificationBasicContent> basicContent = content->GetNotificationContent();
if (basicContent == nullptr) {
BGTASK_LOGE("basicContent is nullptr");
return;
}
auto liveViewContent = std::static_pointer_cast<Notification::NotificationLiveViewContent>(basicContent);
if (liveViewContent == nullptr) {
BGTASK_LOGE("liveViewContent is nullptr");
return;
}
std::shared_ptr<AAFwk::WantParams> extraInfo = liveViewContent->GetExtraInfo();
if (extraInfo == nullptr) {
BGTASK_LOGE("notification extraInfo is null");
return;
}
eventName = AAFwk::String::Unbox(AAFwk::IString::Query(extraInfo->GetParam("event")));
capsuleStatus = AAFwk::Integer::Unbox(AAFwk::IInteger::Query(extraInfo->GetParam("CapsuleData.status")));
BGTASK_LOGD("liveView eventName: %{public}s, capsuleStatus: %{public}d", eventName.c_str(), capsuleStatus);
}
}
}