diff --git a/interfaces/inner_api/notification_constant.h b/interfaces/inner_api/notification_constant.h index de3e87263fe261d3e503d5d7c5d209a05ad056c4..3413024daca585f38d8c76e0f2c5a9cd910e9c55 100644 --- a/interfaces/inner_api/notification_constant.h +++ b/interfaces/inner_api/notification_constant.h @@ -62,6 +62,7 @@ public: CONTENT_INFORMATION, // the notificatin type is content information OTHER, // the notificatin type is other CUSTOM, // the notification type is custom + LIVE_VIEW, // the notification type is live view }; enum class VisiblenessType { diff --git a/interfaces/inner_api/notification_content.h b/interfaces/inner_api/notification_content.h index 41d1957f2909c196dc44c1609beafea888de48f2..fb44a421d0eb3ffc56861e65adcd6aba2065761a 100644 --- a/interfaces/inner_api/notification_content.h +++ b/interfaces/inner_api/notification_content.h @@ -24,6 +24,7 @@ #include "notification_multiline_content.h" #include "notification_normal_content.h" #include "notification_picture_content.h" +#include "notification_local_live_view_content.h" #include "parcel.h" namespace OHOS { @@ -63,7 +64,12 @@ public: * Indicates notifications that include a picture. * Such notifications are created using NotificationPictureContent. */ - PICTURE + PICTURE, + /** + * Indicates notifications that include system activity. + * Such notifications are created using NotificationLocalLiveViewContent. + */ + LOCAL_LIVE_VIEW }; /** @@ -120,6 +126,15 @@ public: */ explicit NotificationContent(const std::shared_ptr &mediaContent); + /** + * @brief A constructor used to create a NotificationLocalLiveViewContent instance (obtained by calling + * GetNotificationContent()) and set the content type to NotificationContent::Type::LOCAL_LIVE_VIEW (obtained by calling + * GetContentType()). + * + * @param mediaContent Indicates the NotificationLocalLiveViewContent object. + */ + explicit NotificationContent(const std::shared_ptr &localLiveViewContent); + virtual ~NotificationContent(); /** diff --git a/interfaces/inner_api/notification_helper.h b/interfaces/inner_api/notification_helper.h index fdff334760137a49e4ac74f6b846b3e671c55ca6..b0b119b20337a1815c23006ffb22ed14a91cfb84 100644 --- a/interfaces/inner_api/notification_helper.h +++ b/interfaces/inner_api/notification_helper.h @@ -17,12 +17,14 @@ #define BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_INTERFACES_INNER_API_NOTIFICATION_HELPER_H #include "notification_bundle_option.h" +#include "notification_button_option.h" #include "notification_do_not_disturb_date.h" #include "enabled_notification_callback_data.h" #include "notification_request.h" #include "notification_slot.h" #include "notification_sorting_map.h" #include "notification_subscriber.h" +#include "notification_local_live_view_subscriber.h" namespace OHOS { namespace Notification { @@ -319,6 +321,19 @@ public: static ErrCode SubscribeNotification( const NotificationSubscriber &subscriber, const NotificationSubscribeInfo &subscribeInfo); + /** + * @brief Subscribes the localLiveView button click. This method can be called only + * by applications with required system permissions. + * @note To subscribe to a button click, inherit the {NotificationLocalLiveViewSubscriber} class, override its + * callback methods and create a subscriber. The subscriber will be used as a parameter of this method. + * After the button is clicked, subscribers that meet the filter criteria can receive the response + * + * @param subscriber Indicates the subscribers to receive notifications. This parameter must be specified. + * For details, see {NotificationSubscriber}. + * @return Returns subscribe notification result. + */ + static ErrCode SubscribeLocalLiveViewNotification(const NotificationLocalLiveViewSubscriber &subscriber); + /** * @brief Unsubscribes from all notifications. This method can be called only by applications with required * system permissions. @@ -349,6 +364,18 @@ public: */ static ErrCode UnSubscribeNotification(NotificationSubscriber &subscriber, NotificationSubscribeInfo subscribeInfo); + /** + * @brief Trigger the local activity after the button has been clicked. + * @note Your application must have platform signature to use this method. + * + * @param bundleOption Indicates the bundle name and uid of the application whose notifications has been clicked. + * @param notificationId Indicates the id of the notification. + * @param buttonOption Indicates which button has been clicked. + * @return Returns trigger localLiveView result. + */ + static ErrCode TriggerLocalLiveView(const NotificationBundleOption &bundleOption, + const int32_t notificationId, const NotificationButtonOption &buttonOption); + /** * @brief Removes a specified removable notification of other applications. * @note Your application must have platform signature to use this method. diff --git a/services/ans/BUILD.gn b/services/ans/BUILD.gn index edc6d381abdb228c4ab2da819810d0a849e4f315..5b944341beb0de0c0c0671a14b85b550cc96503d 100644 --- a/services/ans/BUILD.gn +++ b/services/ans/BUILD.gn @@ -50,6 +50,7 @@ ohos_shared_library("libans") { "src/bundle_manager_helper.cpp", "src/event_report.cpp", "src/notification_dialog.cpp", + "src/notification_local_live_view_subscriber_manager.cpp", "src/notification_preferences.cpp", "src/notification_preferences_database.cpp", "src/notification_preferences_info.cpp", diff --git a/services/ans/include/advanced_notification_service.h b/services/ans/include/advanced_notification_service.h index c39458f3d7e94493f276a182e77543997e228bb9..b91f28598fe8e5685a5d25c5f1db3c74b6c35567 100644 --- a/services/ans/include/advanced_notification_service.h +++ b/services/ans/include/advanced_notification_service.h @@ -263,6 +263,18 @@ public: */ ErrCode HasNotificationPolicyAccessPermission(bool &granted) override; + /** + * @brief Trigger the local activity after the button has been clicked. + * @note Your application must have platform signature to use this method. + * + * @param bundleOption Indicates the bundle name and uid of the application whose notifications has been clicked. + * @param notificationId Indicates the id of the notification. + * @param buttonOption Indicates which button has been clicked. + * @return Returns trigger localLiveView result. + */ + ErrCode TriggerLocalLiveView(const sptr &bundleOption, + const int32_t notificationId, const sptr &buttonOption) override; + /** * @brief Delete notification. * @@ -401,6 +413,16 @@ public: ErrCode Subscribe(const sptr &subscriber, const sptr &info) override; + /** + * @brief Subscribes notifications. + * + * @param subscriber Indicates the subscriber. + * @param info Indicates the NotificationSubscribeInfo object. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode SubscribeLocalLiveView(const sptr &subscriber, + const sptr &info) override; + /** * @brief Unsubscribes notifications. * diff --git a/services/ans/src/advanced_notification_service.cpp b/services/ans/src/advanced_notification_service.cpp index 88bf369f2d0bbfb31318f8a332e71b8440254c6e..fae19ba780d7254c7287ec3963735b69adc5056d 100644 --- a/services/ans/src/advanced_notification_service.cpp +++ b/services/ans/src/advanced_notification_service.cpp @@ -45,6 +45,7 @@ #include "notification_slot.h" #include "notification_slot_filter.h" #include "notification_subscriber_manager.h" +#include "notification_local_live_view_subscriber_manager.h" #include "os_account_manager.h" #include "permission_filter.h" #include "push_callback_proxy.h" @@ -1512,6 +1513,41 @@ ErrCode AdvancedNotificationService::Subscribe( return errCode; } +ErrCode AdvancedNotificationService::SubscribeLocalLiveView( + const sptr &subscriber, const sptr &info) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + ANS_LOGD("%{public}s", __FUNCTION__); + + ErrCode errCode = ERR_OK; + do { + if (subscriber == nullptr) { + errCode = ERR_ANS_INVALID_PARAM; + break; + } + + bool isSubsystem = AccessTokenHelper::VerifyNativeToken(IPCSkeleton::GetCallingTokenID()); + if (!isSubsystem && !AccessTokenHelper::IsSystemApp()) { + ANS_LOGE("Client is not a system app or subsystem"); + errCode = ERR_ANS_NON_SYSTEM_APP; + break; + } + + if (!CheckPermission(OHOS_PERMISSION_NOTIFICATION_CONTROLLER)) { + errCode = ERR_ANS_PERMISSION_DENIED; + break; + } + + errCode = NotificationLocalLiveViewSubscriberManager::GetInstance()->AddLocalLiveViewSubscriber(subscriber, info); + if (errCode != ERR_OK) { + break; + } + } while (0); + + SendSubscribeHiSysEvent(IPCSkeleton::GetCallingPid(), IPCSkeleton::GetCallingUid(), info, errCode); + return errCode; +} + ErrCode AdvancedNotificationService::Unsubscribe( const sptr &subscriber, const sptr &info) { @@ -2573,6 +2609,49 @@ ErrCode AdvancedNotificationService::AddSlotByType(NotificationConstant::SlotTyp return result; } +ErrCode AdvancedNotificationService::TriggerLocalLiveView(const sptr &bundleOption, + const int32_t notificationId, const sptr &buttonOption) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + ANS_LOGD("%{public}s", __FUNCTION__); + + bool isSubsystem = AccessTokenHelper::VerifyNativeToken(IPCSkeleton::GetCallingTokenID()); + if (!isSubsystem && !AccessTokenHelper::IsSystemApp()) { + return ERR_ANS_NON_SYSTEM_APP; + } + + if (!CheckPermission(OHOS_PERMISSION_NOTIFICATION_CONTROLLER)) { + ANS_LOGD("CheckPermission is bogus."); + return ERR_ANS_PERMISSION_DENIED; + } + + sptr bundle = GenerateValidBundleOption(bundleOption); + if (bundle == nullptr) { + return ERR_ANS_INVALID_BUNDLE; + } + + ErrCode result = ERR_ANS_NOTIFICATION_NOT_EXISTS; + ffrt::task_handle handler = notificationSvrQueue_->submit_h(std::bind([&]() { + ANS_LOGD("ffrt enter!"); + sptr notification = nullptr; + + for (auto record : notificationList_) { + if ((record->bundleOption->GetBundleName() == bundle->GetBundleName()) && + (record->bundleOption->GetUid() == bundle->GetUid()) && + (record->notification->GetId() == notificationId)) { + notification = record->notification; + result = ERR_OK; + break; + } + } + + if (notification != nullptr) { + NotificationLocalLiveViewSubscriberManager::GetInstance()->NotifyTriggerResponse(notification, buttonOption); + } + })); + notificationSvrQueue_->wait(handler); + return result; +} ErrCode AdvancedNotificationService::RemoveNotification(const sptr &bundleOption, int32_t notificationId, const std::string &label, int32_t removeReason) { diff --git a/services/ans/src/notification_local_live_view_subscriber_manager.cpp b/services/ans/src/notification_local_live_view_subscriber_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54ac6ef23c993461378a9e4c29c54b9c61168394 --- /dev/null +++ b/services/ans/src/notification_local_live_view_subscriber_manager.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2021-2022 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 "notification_local_live_view_subscriber_manager.h" + +#include +#include +#include + +#include "ans_const_define.h" +#include "ans_inner_errors.h" +#include "ans_log_wrapper.h" +#include "ans_watchdog.h" +#include "hitrace_meter.h" +#include "ipc_skeleton.h" +#include "notification_bundle_option.h" +#include "notification_button_option.h" +#include "os_account_manager.h" +#include "remote_death_recipient.h" +#include "bundle_manager_helper.h" + +namespace OHOS { +namespace Notification { +struct NotificationLocalLiveViewSubscriberManager::LocalLiveViewSubscriberRecord { + sptr subscriber {nullptr}; + std::string bundleName {}; + int32_t userId {SUBSCRIBE_USER_INIT}; +}; + +NotificationLocalLiveViewSubscriberManager::NotificationLocalLiveViewSubscriberManager() +{ + ANS_LOGI("constructor"); + notificationButtonQueue_ = std::make_shared("NotificationLocalLiveViewMgr"); + recipient_ = new (std::nothrow) + RemoteDeathRecipient(std::bind(&NotificationLocalLiveViewSubscriberManager::OnRemoteDied, this, std::placeholders::_1)); + if (recipient_ == nullptr) { + ANS_LOGE("Failed to create RemoteDeathRecipient instance"); + } +} + +NotificationLocalLiveViewSubscriberManager::~NotificationLocalLiveViewSubscriberManager() +{ + ANS_LOGI("deconstructor"); + buttonRecordList_.clear(); +} + +void NotificationLocalLiveViewSubscriberManager::ResetFfrtQueue() +{ + if (notificationButtonQueue_ != nullptr) { + notificationButtonQueue_.reset(); + } +} + +ErrCode NotificationLocalLiveViewSubscriberManager::AddLocalLiveViewSubscriber( + const sptr &subscriber, const sptr &subscribeInfo) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + if (subscriber == nullptr) { + ANS_LOGE("subscriber is null."); + return ERR_ANS_INVALID_PARAM; + } + + sptr bundleOption; + std::string bundle; + int32_t callingUid = IPCSkeleton::GetCallingUid(); + std::shared_ptr bundleManager = BundleManagerHelper::GetInstance(); + if (bundleManager != nullptr) { + bundle = bundleManager->GetBundleNameByUid(callingUid); + } + bundleOption = new (std::nothrow) NotificationBundleOption(bundle, callingUid); + ErrCode result = ERR_ANS_TASK_ERR; + if (bundleOption == nullptr) { + ANS_LOGE("Failed to create NotificationBundleOption instance"); + return ERR_ANS_NO_MEMORY; + } + ANS_LOGD("Get userId succeeded, callingUid = <%{public}d> bundleName = <%{public}s>", callingUid, bundle.c_str()); + if (notificationButtonQueue_ == nullptr) { + ANS_LOGE("queue is nullptr"); + return result; + } + ANS_LOGE("ffrt start!"); + ffrt::task_handle handler = notificationButtonQueue_->submit_h(std::bind([this, &subscriber, &bundleOption, &result]() { + ANS_LOGE("ffrt enter!"); + result = this->AddSubscriberInner(subscriber, bundleOption); + })); + notificationButtonQueue_->wait(handler); + ANS_LOGE("ffrt end!"); + return result; +} + +ErrCode NotificationLocalLiveViewSubscriberManager::RemoveLocalLiveViewSubscriber( + const sptr &subscriber, const sptr &subscribeInfo) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + if (subscriber == nullptr) { + ANS_LOGE("subscriber is null."); + return ERR_ANS_INVALID_PARAM; + } + + ErrCode result = ERR_ANS_TASK_ERR; + if (notificationButtonQueue_ == nullptr) { + ANS_LOGE("queue is nullptr"); + return result; + } + ANS_LOGE("ffrt start!"); + ffrt::task_handle handler = notificationButtonQueue_->submit_h(std::bind([this, &subscriber, + &subscribeInfo, &result]() { + ANS_LOGE("ffrt enter!"); + result = this->RemoveSubscriberInner(subscriber, subscribeInfo); + })); + notificationButtonQueue_->wait(handler); + ANS_LOGE("ffrt end!"); + return result; +} + +void NotificationLocalLiveViewSubscriberManager::NotifyTriggerResponse(const sptr ¬ification, + const sptr &buttonOption) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + if (notificationButtonQueue_ == nullptr) { + ANS_LOGE("queue is nullptr"); + return; + } + AppExecFwk::EventHandler::Callback NotifyTriggerResponseFunc = + std::bind(&NotificationLocalLiveViewSubscriberManager::NotifyTriggerResponseInner, this, notification, buttonOption); + + ANS_LOGE("ffrt start!"); + notificationButtonQueue_->submit(NotifyTriggerResponseFunc); + ANS_LOGE("ffrt end!"); +} + +void NotificationLocalLiveViewSubscriberManager::OnRemoteDied(const wptr &object) +{ + ANS_LOGI("OnRemoteDied"); + if (notificationButtonQueue_ == nullptr) { + ANS_LOGE("queue is nullptr"); + return; + } + ffrt::task_handle handler = notificationButtonQueue_->submit_h(std::bind([this, object]() { + ANS_LOGE("ffrt enter!"); + std::shared_ptr record = FindSubscriberRecord(object); + if (record != nullptr) { + ANS_LOGW("subscriber removed."); + buttonRecordList_.remove(record); + } + })); + ANS_LOGE("ffrt start!"); + notificationButtonQueue_->wait(handler); + ANS_LOGE("ffrt end!"); +} + +std::shared_ptr NotificationLocalLiveViewSubscriberManager::FindSubscriberRecord( + const wptr &object) +{ + auto iter = buttonRecordList_.begin(); + + for (; iter != buttonRecordList_.end(); iter++) { + if ((*iter)->subscriber->AsObject() == object) { + return (*iter); + } + } + return nullptr; +} + +std::shared_ptr NotificationLocalLiveViewSubscriberManager::FindSubscriberRecord( + const sptr &subscriber) +{ + auto iter = buttonRecordList_.begin(); + + for (; iter != buttonRecordList_.end(); iter++) { + if ((*iter)->subscriber->AsObject() == subscriber->AsObject()) { + return (*iter); + } + } + return nullptr; +} + +std::shared_ptr NotificationLocalLiveViewSubscriberManager::CreateSubscriberRecord( + const sptr &subscriber, const sptr &bundleOption) +{ + std::shared_ptr record = std::make_shared(); + // set bundleName and uid + if (record != nullptr) { + record->subscriber = subscriber; + record->bundleName = bundleOption->GetBundleName(); + record->userId = bundleOption->GetUid(); + ANS_LOGD("Get userId succeeded, callingUid = <%{public}d> bundleName = <%{public}s>", record->userId, record->bundleName.c_str()); + } + return record; +} + + +ErrCode NotificationLocalLiveViewSubscriberManager::AddSubscriberInner( + const sptr &subscriber, const sptr &bundleOption) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + std::shared_ptr record = FindSubscriberRecord(subscriber); + if (record == nullptr) { + record = CreateSubscriberRecord(subscriber, bundleOption); + if (record == nullptr) { + ANS_LOGE("CreateSubscriberRecord failed."); + return ERR_ANS_NO_MEMORY; + } + buttonRecordList_.push_back(record); + + record->subscriber->AsObject()->AddDeathRecipient(recipient_); + + record->subscriber->OnConnected(); + ANS_LOGI("subscriber is connected."); + } + + return ERR_OK; +} + +ErrCode NotificationLocalLiveViewSubscriberManager::RemoveSubscriberInner( + const sptr &subscriber, const sptr &subscribeInfo) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + std::shared_ptr record = FindSubscriberRecord(subscriber); + + if (record == nullptr) { + ANS_LOGE("subscriber not found."); + return ERR_ANS_INVALID_PARAM; + } + + record->subscriber->AsObject()->RemoveDeathRecipient(recipient_); + + buttonRecordList_.remove(record); + + record->subscriber->OnDisconnected(); + ANS_LOGI("subscriber is disconnected."); + + return ERR_OK; +} + +void NotificationLocalLiveViewSubscriberManager::NotifyTriggerResponseInner(const sptr ¬ification, const sptr buttonOption) +{ + ANS_LOGE("ffrt enter!"); + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + ANS_LOGD("%{public}s notification->GetUserId <%{public}d>, bundlename <%{public}s>", __FUNCTION__, notification->GetUid(), + notification->GetBundleName().c_str()); + int32_t sendUserId = notification->GetUid(); + for (auto record : buttonRecordList_) { + ANS_LOGD("%{public}s record->userId = <%{public}d>, bundlename <%{public}s>", __FUNCTION__, record->userId, record->bundleName.c_str()); + auto bundleName = notification->GetBundleName(); + if (record->bundleName == bundleName && record->userId == sendUserId) { + record->subscriber->OnResponse(notification->GetId(), buttonOption); + } + } +} + +bool NotificationLocalLiveViewSubscriberManager::IsSystemUser(int32_t userId) +{ + return ((userId >= SUBSCRIBE_USER_SYSTEM_BEGIN) && (userId <= SUBSCRIBE_USER_SYSTEM_END)); +} + +} // namespace Notification +} // namespace OHOS