diff --git a/frameworks/ans/BUILD.gn b/frameworks/ans/BUILD.gn index bd2d2f539e45067eecfa539761d23582a932b123..e6fbcc821c305fa963b01c528f3297f473954dc8 100644 --- a/frameworks/ans/BUILD.gn +++ b/frameworks/ans/BUILD.gn @@ -54,6 +54,8 @@ ohos_shared_library("ans_innerkits") { "${core_path}/src/ans_manager_proxy.cpp", "${core_path}/src/ans_manager_stub.cpp", "${core_path}/src/ans_notification.cpp", + "${core_path}/src/ans_subscriber_local_live_view_proxy.cpp", + "${core_path}/src/ans_subscriber_local_live_view_stub.cpp", "${core_path}/src/ans_subscriber_proxy.cpp", "${core_path}/src/ans_subscriber_stub.cpp", "${frameworks_module_ans_path}/src/badge_number_callback_data.cpp", @@ -63,6 +65,8 @@ ohos_shared_library("ans_innerkits") { "${frameworks_module_ans_path}/src/notification_action_button.cpp", "${frameworks_module_ans_path}/src/notification_basic_content.cpp", "${frameworks_module_ans_path}/src/notification_bundle_option.cpp", + "${frameworks_module_ans_path}/src/notification_button_option.cpp", + "${frameworks_module_ans_path}/src/notification_capsule.cpp", "${frameworks_module_ans_path}/src/notification_constant.cpp", "${frameworks_module_ans_path}/src/notification_content.cpp", "${frameworks_module_ans_path}/src/notification_conversational_content.cpp", @@ -71,11 +75,15 @@ ohos_shared_library("ans_innerkits") { "${frameworks_module_ans_path}/src/notification_do_not_disturb_date.cpp", "${frameworks_module_ans_path}/src/notification_flags.cpp", "${frameworks_module_ans_path}/src/notification_helper.cpp", + "${frameworks_module_ans_path}/src/notification_local_live_view_button.cpp", + "${frameworks_module_ans_path}/src/notification_local_live_view_content.cpp", + "${frameworks_module_ans_path}/src/notification_local_live_view_subscriber.cpp", "${frameworks_module_ans_path}/src/notification_long_text_content.cpp", "${frameworks_module_ans_path}/src/notification_media_content.cpp", "${frameworks_module_ans_path}/src/notification_multiline_content.cpp", "${frameworks_module_ans_path}/src/notification_normal_content.cpp", "${frameworks_module_ans_path}/src/notification_picture_content.cpp", + "${frameworks_module_ans_path}/src/notification_progress.cpp", "${frameworks_module_ans_path}/src/notification_request.cpp", "${frameworks_module_ans_path}/src/notification_slot.cpp", "${frameworks_module_ans_path}/src/notification_sorting.cpp", diff --git a/frameworks/ans/src/notification_button_option.cpp b/frameworks/ans/src/notification_button_option.cpp new file mode 100644 index 0000000000000000000000000000000000000000..677e070820f3470f2e8c924846c44e19ac76b751 --- /dev/null +++ b/frameworks/ans/src/notification_button_option.cpp @@ -0,0 +1,103 @@ +/* + * 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 "notification_button_option.h" + +#include // for basic_string, operator+, basic_string<>... +#include // for shared_ptr, shared_ptr<>::element_type + + +#include "ans_image_util.h" +#include "ans_log_wrapper.h" +#include "nlohmann/json.hpp" // for json, basic_json<>::object_t, basic_json +#include "parcel.h" // for Parcel + +namespace OHOS { +namespace Notification { + +void NotificationButtonOption::SetButtonName(const std::string &buttonName) +{ + buttonName_ = buttonName; +} + +std::string NotificationButtonOption::GetButtonName() const +{ + return buttonName_; +} + +std::string NotificationButtonOption::Dump() +{ + return "NotificationButtonOption{ " + "buttonName = " + buttonName_ + + " }"; +} + +bool NotificationButtonOption::ToJson(nlohmann::json &jsonObject) const +{ + jsonObject["buttonName"] = buttonName_; + return true; +} + +NotificationButtonOption *NotificationButtonOption::FromJson(const nlohmann::json &jsonObject) +{ + if (jsonObject.is_null() or !jsonObject.is_object()) { + ANS_LOGE("Invalid JSON object"); + return nullptr; + } + + NotificationButtonOption *button = new (std::nothrow) NotificationButtonOption(); + if (button == nullptr) { + ANS_LOGE("Failed to create button option instance"); + return nullptr; + } + + const auto &jsonEnd = jsonObject.cend(); + if (jsonObject.find("buttonName") != jsonEnd && jsonObject.at("buttonName").is_string()) { + button->buttonName_ = jsonObject.at("buttonName").get(); + } + + return button; +} + +bool NotificationButtonOption::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(buttonName_)) { + ANS_LOGE("Failed to write title"); + return false; + } + + return true; +} + +bool NotificationButtonOption::ReadFromParcel(Parcel &parcel) +{ + buttonName_ = parcel.ReadString(); + + return true; +} + +NotificationButtonOption *NotificationButtonOption::Unmarshalling(Parcel &parcel) +{ + NotificationButtonOption *button = new (std::nothrow) NotificationButtonOption(); + + if (button && !button->ReadFromParcel(parcel)) { + delete button; + button = nullptr; + } + + return button; +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ans/src/notification_capsule.cpp b/frameworks/ans/src/notification_capsule.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2cafc693af012f8f3c0866aa8e3f6f0cbff3448 --- /dev/null +++ b/frameworks/ans/src/notification_capsule.cpp @@ -0,0 +1,166 @@ +/* + * 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 "notification_capsule.h" + +#include // for basic_string, operator+, basic_string<>... +#include // for shared_ptr, shared_ptr<>::element_type + + +#include "ans_image_util.h" +#include "ans_log_wrapper.h" +#include "nlohmann/json.hpp" // for json, basic_json<>::object_t, basic_json +#include "parcel.h" // for Parcel +#include "pixel_map.h" // for PixelMap + +namespace OHOS { +namespace Notification { + +void NotificationCapsule::SetTitle(const std::string &title) +{ + title_ = title; +} + +std::string NotificationCapsule::GetTitle() const +{ + return title_; +} + +void NotificationCapsule::SetBackgroundColor(const std::string &color) +{ + backgroundColor_ = color; +} + +std::string NotificationCapsule::GetBackgroundColor() const +{ + return backgroundColor_; +} + +void NotificationCapsule::SetIcon(const std::shared_ptr &pixelMap) +{ + icon_ = pixelMap; +} + +const std::shared_ptr NotificationCapsule::GetIcon() const +{ + return icon_; +} + +std::string NotificationCapsule::Dump() +{ + return "Capsule{ " + "title = " + title_ + + ", backgroundColor = " + backgroundColor_ + + ", icon = " + (icon_ ? "not null" : "null") + + " }"; +} + +bool NotificationCapsule::ToJson(nlohmann::json &jsonObject) const +{ + jsonObject["title"] = title_; + jsonObject["backgroundColor"] = backgroundColor_; + jsonObject["icon"] = AnsImageUtil::PackImage(icon_); + + return true; +} + +NotificationCapsule *NotificationCapsule::FromJson(const nlohmann::json &jsonObject) +{ + if (jsonObject.is_null() or !jsonObject.is_object()) { + ANS_LOGE("Invalid JSON object"); + return nullptr; + } + + NotificationCapsule *capsule = new (std::nothrow) NotificationCapsule(); + if (capsule == nullptr) { + ANS_LOGE("Failed to create capsule instance"); + return nullptr; + } + + const auto &jsonEnd = jsonObject.cend(); + if (jsonObject.find("title") != jsonEnd && jsonObject.at("title").is_string()) { + capsule->title_ = jsonObject.at("title").get(); + } + + if (jsonObject.find("backgroundColor") != jsonEnd && jsonObject.at("backgroundColor").is_string()) { + capsule->backgroundColor_ = jsonObject.at("backgroundColor").get(); + } + + if (jsonObject.find("icon") != jsonEnd && jsonObject.at("icon").is_string()) { + auto pmStr = jsonObject.at("icon").get(); + capsule->icon_ = AnsImageUtil::UnPackImage(pmStr); + } + + return capsule; +} + +bool NotificationCapsule::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(title_)) { + ANS_LOGE("Failed to write title"); + return false; + } + + if (!parcel.WriteString(backgroundColor_)) { + ANS_LOGE("Failed to write backgroundColor"); + return false; + } + + bool valid = icon_ ? true : false; + if (!parcel.WriteBool(valid)) { + ANS_LOGE("Failed to write the flag which indicate whether icon pixelMap is null"); + return false; + } + + if (valid) { + if (!parcel.WriteParcelable(icon_.get())) { + ANS_LOGE("Failed to write icon"); + return false; + } + } + + return true; +} + +bool NotificationCapsule::ReadFromParcel(Parcel &parcel) +{ + title_ = parcel.ReadString(); + backgroundColor_ = parcel.ReadString(); + + bool valid = parcel.ReadBool(); + if (valid) { + icon_ = std::shared_ptr(parcel.ReadParcelable()); + if (!icon_) { + ANS_LOGE("Failed to read icon pixelMap"); + return false; + } + } + + return true; +} + +NotificationCapsule *NotificationCapsule::Unmarshalling(Parcel &parcel) +{ + NotificationCapsule *capsule = new (std::nothrow) NotificationCapsule(); + + if (capsule && !capsule->ReadFromParcel(parcel)) { + delete capsule; + capsule = nullptr; + } + + return capsule; +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ans/src/notification_content.cpp b/frameworks/ans/src/notification_content.cpp index 244982c2d5b12a41fe94764765430ab2bc8a20a4..886e58863be15a2dc0151ffc1e16477f7f9441e8 100644 --- a/frameworks/ans/src/notification_content.cpp +++ b/frameworks/ans/src/notification_content.cpp @@ -15,6 +15,7 @@ #include "notification_content.h" #include "ans_log_wrapper.h" +#include "notification_local_live_view_content.h" namespace OHOS { namespace Notification { @@ -84,6 +85,17 @@ NotificationContent::NotificationContent(const std::shared_ptr &localLiveViewContent) +{ + if (!localLiveViewContent) { + ANS_LOGE("NotificationLocalLiveViewContent can not be null"); + return; + } + + contentType_ = NotificationContent::Type::LOCAL_LIVE_VIEW; + content_ = localLiveViewContent; +} + NotificationContent::~NotificationContent() {} @@ -99,12 +111,13 @@ std::shared_ptr NotificationContent::GetNotificationCo std::string NotificationContent::Dump() { - std::string contentTypeStr = (contentType_ == NotificationContent::Type::BASIC_TEXT) ? "BASIC_TEXT" - : (contentType_ == NotificationContent::Type::CONVERSATION) ? "CONVERSATION" - : (contentType_ == NotificationContent::Type::LONG_TEXT) ? "LONG_TEXT" - : (contentType_ == NotificationContent::Type::MEDIA) ? "MEDIA" - : (contentType_ == NotificationContent::Type::MULTILINE) ? "MULTILINE" - : (contentType_ == NotificationContent::Type::PICTURE) ? "PICTURE" : "NONE"; + std::string contentTypeStr = (contentType_ == NotificationContent::Type::BASIC_TEXT) ? "BASIC_TEXT" + : (contentType_ == NotificationContent::Type::CONVERSATION) ? "CONVERSATION" + : (contentType_ == NotificationContent::Type::LONG_TEXT) ? "LONG_TEXT" + : (contentType_ == NotificationContent::Type::MEDIA) ? "MEDIA" + : (contentType_ == NotificationContent::Type::MULTILINE) ? "MULTILINE" + : (contentType_ == NotificationContent::Type::PICTURE) ? "PICTURE" + : (contentType_ == NotificationContent::Type::LOCAL_LIVE_VIEW) ? "LOCAL_LIVE_VIEW" : "NONE"; return "NotificationContent{ " "contentType = " + contentTypeStr + @@ -227,6 +240,10 @@ bool NotificationContent::ReadFromParcel(Parcel &parcel) content_ = std::static_pointer_cast( std::shared_ptr(parcel.ReadParcelable())); break; + case NotificationContent::Type::LOCAL_LIVE_VIEW: + content_ = std::static_pointer_cast( + std::shared_ptr(parcel.ReadParcelable())); + break; default: ANS_LOGE("Invalid contentType"); return false; @@ -277,6 +294,9 @@ bool NotificationContent::ConvertJsonToContent(NotificationContent *target, cons case NotificationContent::Type::PICTURE: pBasicContent = NotificationJsonConverter::ConvertFromJson(contentObj); break; + case NotificationContent::Type::LOCAL_LIVE_VIEW: + pBasicContent = NotificationJsonConverter::ConvertFromJson(contentObj); + break; default: ANS_LOGE("Invalid contentType"); break; diff --git a/frameworks/ans/src/notification_helper.cpp b/frameworks/ans/src/notification_helper.cpp index 2eac9228496e18e20a3a27c9e226c302b9f3c183..81a84f5b0258f2d17e8ed4abd56d08c50ecb65b9 100644 --- a/frameworks/ans/src/notification_helper.cpp +++ b/frameworks/ans/src/notification_helper.cpp @@ -164,6 +164,11 @@ ErrCode NotificationHelper::SubscribeNotification(const NotificationSubscriber & return DelayedSingleton::GetInstance()->SubscribeNotification(subscriber); } +ErrCode NotificationHelper::SubscribeLocalLiveViewNotification(const NotificationLocalLiveViewSubscriber &subscriber) +{ + return DelayedSingleton::GetInstance()->SubscribeLocalLiveViewNotification(subscriber); +} + ErrCode NotificationHelper::SubscribeNotification( const NotificationSubscriber &subscriber, const NotificationSubscribeInfo &subscribeInfo) { @@ -181,6 +186,12 @@ ErrCode NotificationHelper::UnSubscribeNotification( return DelayedSingleton::GetInstance()->UnSubscribeNotification(subscriber, subscribeInfo); } +ErrCode NotificationHelper::TriggerLocalLiveView(const NotificationBundleOption &bundleOption, + const int32_t notificationId, const NotificationButtonOption &buttonOption) +{ + return DelayedSingleton::GetInstance()->TriggerLocalLiveView(bundleOption, notificationId, buttonOption); +} + ErrCode NotificationHelper::RemoveNotification(const std::string &key, int32_t removeReason) { return DelayedSingleton::GetInstance()->RemoveNotification(key, removeReason); diff --git a/frameworks/ans/src/notification_local_live_view_button.cpp b/frameworks/ans/src/notification_local_live_view_button.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bf090ed4ef3e2bf1707e9cc22d6df2e558dc576 --- /dev/null +++ b/frameworks/ans/src/notification_local_live_view_button.cpp @@ -0,0 +1,181 @@ +/* + * 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 "notification_local_live_view_button.h" + +#include +#include // for basic_string, operator+, basic_string<>... +#include // for shared_ptr, shared_ptr<>::element_type +#include + + +#include "ans_image_util.h" +#include "ans_log_wrapper.h" +#include "nlohmann/json.hpp" // for json, basic_json<>::object_t, basic_json +#include "notification_button_option.h" +#include "notification_json_convert.h" +#include "parcel.h" // for Parcel +#include "pixel_map.h" // for PixelMap + +namespace OHOS { +namespace Notification { + +std::vector NotificationLocalLiveViewButton::GetAllButtonNames() const +{ + return buttonNames_; +} + +void NotificationLocalLiveViewButton::addSingleButtonName(const std::string &buttonName) +{ + if (buttonNames_.size() >= 3) { + ANS_LOGW("already added 3 buttonOption"); + return; + } + + buttonNames_.emplace_back(buttonName); +} + +std::vector> NotificationLocalLiveViewButton::GetAllButtonIcon() const +{ + return buttonIcons_; +} + +void NotificationLocalLiveViewButton::addSingleButtonIcon(std::shared_ptr &icon) +{ + if (buttonIcons_.size() >= 3) { + ANS_LOGW("already added 3 buttonIcon"); + return; + } + + buttonIcons_.emplace_back(icon); +} + +std::string NotificationLocalLiveViewButton::Dump() +{ + return ""; +} + +bool NotificationLocalLiveViewButton::ToJson(nlohmann::json &jsonObject) const +{ + nlohmann::json buttonsArr = nlohmann::json::array(); + + jsonObject["buttonNames"] = nlohmann::json(buttonNames_); + + nlohmann::json iconsArr = nlohmann::json::array(); + for (auto &btn : buttonIcons_) { + if (!btn) { + continue; + } + nlohmann::json btnObj = AnsImageUtil::PackImage(btn); + iconsArr.emplace_back(btnObj); + } + jsonObject["buttonIcons"] = iconsArr; + + return true; +} + +NotificationLocalLiveViewButton *NotificationLocalLiveViewButton::FromJson(const nlohmann::json &jsonObject) +{ + if (jsonObject.is_null() or !jsonObject.is_object()) { + ANS_LOGE("Invalid JSON object"); + return nullptr; + } + + NotificationLocalLiveViewButton *button = new (std::nothrow) NotificationLocalLiveViewButton(); + if (button == nullptr) { + ANS_LOGE("Failed to create capsule instance"); + return nullptr; + } + + const auto &jsonEnd = jsonObject.cend(); + + if (jsonObject.find("buttonNames") != jsonEnd && jsonObject.at("buttonNames").is_array()) { + button->buttonNames_ = jsonObject.at("buttonNames").get>(); + } + + if (jsonObject.find("buttonIcons") != jsonEnd) { + auto iconArr = jsonObject.at("buttonIcons"); + for (auto &iconObj : iconArr) { + auto pIcon = AnsImageUtil::UnPackImage(iconObj.get()); + + if (pIcon == nullptr) { + ANS_LOGE("Failed to parse button icon"); + return nullptr; + } + button->buttonIcons_.emplace_back(pIcon); + } + } + + return button; +} + +bool NotificationLocalLiveViewButton::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteStringVector(buttonNames_)) { + ANS_LOGE("Failed to write buttonNames"); + return false; + } + + if (!parcel.WriteUint64(buttonIcons_.size())) { + ANS_LOGE("Failed to write the size of buttonIcons"); + return false; + } + + for (auto it = buttonIcons_.begin(); it != buttonIcons_.end(); ++it) { + if (!parcel.WriteParcelable(it->get())) { + ANS_LOGE("Failed to write buttonIcons"); + return false; + } + } + + return true; +} + +bool NotificationLocalLiveViewButton::ReadFromParcel(Parcel &parcel) +{ + if (!parcel.ReadStringVector(&buttonNames_)) { + ANS_LOGE("Failed to read button names"); + return false; + } + + auto vsize = parcel.ReadUint64(); + vsize = (vsize < 3) ? vsize : 3; + for (uint64_t it = 0; it < vsize; ++it) { + auto member = std::shared_ptr(parcel.ReadParcelable()); + if (member == nullptr) { + buttonIcons_.clear(); + ANS_LOGE("Failed to read LocalLiveViewButton %llu, %llu",it, vsize); + return false; + } + + buttonIcons_.emplace_back(member); + } + + return true; +} + +NotificationLocalLiveViewButton *NotificationLocalLiveViewButton::Unmarshalling(Parcel &parcel) +{ + NotificationLocalLiveViewButton *button = new (std::nothrow) NotificationLocalLiveViewButton(); + + if (button && !button->ReadFromParcel(parcel)) { + delete button; + button = nullptr; + } + + return button; +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ans/src/notification_local_live_view_content.cpp b/frameworks/ans/src/notification_local_live_view_content.cpp new file mode 100644 index 0000000000000000000000000000000000000000..854d9d43dcdec67e5c1e58c7bba84196ced5ce38 --- /dev/null +++ b/frameworks/ans/src/notification_local_live_view_content.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2021-2023 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_content.h" + +#include +#include // for basic_string, operator+ +#include // for min + +#include "ans_log_wrapper.h" +#include "nlohmann/json.hpp" // for json, basic_json<>::obje... +#include "notification_action_button.h" +#include "notification_basic_content.h" // for NotificationBasicContent +#include "notification_capsule.h" +#include "notification_json_convert.h" +#include "notification_progress.h" +#include "notification_local_live_view_button.h" +#include "parcel.h" // for Parcel + +namespace OHOS { +namespace Notification { + +void NotificationLocalLiveViewContent::SetType(int32_t type) +{ + type_ = type; +} + +void NotificationLocalLiveViewContent::SetCapsule(NotificationCapsule capsule) +{ + capsule_ = capsule; +} + +void NotificationLocalLiveViewContent::SetButton(NotificationLocalLiveViewButton button) +{ + button_ = button; +} + +void NotificationLocalLiveViewContent::SetProgress(NotificationProgress progress) +{ + progress_ = progress; +} + +std::string NotificationLocalLiveViewContent::Dump() +{ + return "NotificationLocalLiveViewContent{ " + NotificationBasicContent::Dump() + + ", type = " + std::to_string(type_) + + ", capsule = " + capsule_.Dump() + + ", button = " + button_.Dump() + + ", progress = " + progress_.Dump() + + " }"; +} + +bool NotificationLocalLiveViewContent::ToJson(nlohmann::json &jsonObject) const +{ + if (!NotificationBasicContent::ToJson(jsonObject)) { + ANS_LOGE("Cannot convert basicContent to JSON"); + return false; + } + + nlohmann::json capsuleObj; + if (!NotificationJsonConverter::ConvertToJson(&capsule_, capsuleObj)) { + ANS_LOGE("Cannot convert capsule to JSON"); + return false; + } + + nlohmann::json buttonObj; + if (!NotificationJsonConverter::ConvertToJson(&button_, buttonObj)) { + ANS_LOGE("Cannot convert button to JSON"); + return false; + } + + nlohmann::json progressObj; + if (!NotificationJsonConverter::ConvertToJson(&progress_, progressObj)) { + ANS_LOGE("Cannot convert progress to JSON"); + return false; + } + + jsonObject["type"] = type_; + jsonObject["capsule"] = capsuleObj; + jsonObject["button"] = buttonObj; + jsonObject["progress"] = progressObj; + + return true; +} + +NotificationLocalLiveViewContent *NotificationLocalLiveViewContent::FromJson(const nlohmann::json &jsonObject) +{ + if (jsonObject.is_null() or !jsonObject.is_object()) { + ANS_LOGE("Invalid JSON object"); + return nullptr; + } + + auto pContent = new (std::nothrow) NotificationLocalLiveViewContent(); + if (pContent == nullptr) { + ANS_LOGE("Failed to create localLiveViewContent instance"); + return nullptr; + } + + pContent->ReadFromJson(jsonObject); + + const auto &jsonEnd = jsonObject.cend(); + if (jsonObject.find("type") != jsonEnd ) { + pContent->type_ = jsonObject.at("type").get(); + } + + if (jsonObject.find("capsule") != jsonEnd ) { + auto capsuleObj = jsonObject.at("capsule"); + auto pCapsule = NotificationJsonConverter::ConvertFromJson(capsuleObj); + if (pCapsule != nullptr) { + pContent->capsule_ = *pCapsule; + delete pCapsule; + pCapsule = nullptr; + } + } + + if (jsonObject.find("button") != jsonEnd ) { + auto buttonObj = jsonObject.at("button"); + auto pButton = NotificationJsonConverter::ConvertFromJson(buttonObj); + if (pButton != nullptr) { + pContent->button_ = *pButton; + delete pButton; + pButton = nullptr; + } + } + + if (jsonObject.find("progress") != jsonEnd ) { + auto progressObj = jsonObject.at("progress"); + auto pProgress = NotificationJsonConverter::ConvertFromJson(progressObj); + if (pProgress != nullptr) { + pContent->progress_ = *pProgress; + delete pProgress; + pProgress = nullptr; + } + } + + return pContent; +} + +bool NotificationLocalLiveViewContent::Marshalling(Parcel &parcel) const +{ + if (!NotificationBasicContent::Marshalling(parcel)) { + ANS_LOGE("Failed to write basic"); + return false; + } + + if (!parcel.WriteInt32(type_)) { + ANS_LOGE("Write type fail."); + return false; + } + + if (!parcel.WriteParcelable(&capsule_)) { + ANS_LOGE("Failed to write capsule"); + return false; + } + + if (!parcel.WriteParcelable(&button_)) { + ANS_LOGE("Failed to write button"); + return false; + } + + if (!parcel.WriteParcelable(&progress_)) { + ANS_LOGE("Failed to write progress"); + return false; + } + + return true; +} + +NotificationLocalLiveViewContent *NotificationLocalLiveViewContent::Unmarshalling(Parcel &parcel) +{ + auto pContent = new (std::nothrow) NotificationLocalLiveViewContent(); + if ((pContent != nullptr) && !pContent->ReadFromParcel(parcel)) { + delete pContent; + pContent = nullptr; + } + + return pContent; +} + +bool NotificationLocalLiveViewContent::ReadFromParcel(Parcel &parcel) +{ + if (!NotificationBasicContent::ReadFromParcel(parcel)) { + ANS_LOGE("Failed to read basic"); + return false; + } + + if (!parcel.ReadInt32(type_)) { + ANS_LOGE("Read type failed."); + return false; + } + + auto pCapsule = parcel.ReadParcelable(); + if (pCapsule == nullptr) { + ANS_LOGE("Failed to read capsule"); + return false; + } + capsule_ = *pCapsule; + delete pCapsule; + pCapsule = nullptr; + + auto pButton = parcel.ReadParcelable(); + if (pButton == nullptr) { + ANS_LOGE("Failed to read button"); + return false; + } + button_ = *pButton; + delete pButton; + pButton = nullptr; + + auto pProgress = parcel.ReadParcelable(); + if (pProgress == nullptr) { + ANS_LOGE("Failed to read capsule"); + return false; + } + progress_ = *pProgress; + delete pProgress; + pProgress = nullptr; + + return true; +} +} // namespace Notification +} // namespace OHOS diff --git a/frameworks/ans/src/notification_local_live_view_subscriber.cpp b/frameworks/ans/src/notification_local_live_view_subscriber.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5db0e166625ad4fa4503f1f451d409ede776f921 --- /dev/null +++ b/frameworks/ans/src/notification_local_live_view_subscriber.cpp @@ -0,0 +1,106 @@ +/* + * 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.h" + +#include "hitrace_meter.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace Notification { +NotificationLocalLiveViewSubscriber::NotificationLocalLiveViewSubscriber() +{ + impl_ = new (std::nothrow) SubscriberLocalLiveViewImpl(*this); +}; + +NotificationLocalLiveViewSubscriber::~NotificationLocalLiveViewSubscriber() +{} + +const sptr NotificationLocalLiveViewSubscriber::GetImpl() const +{ + return impl_; +} + +NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::SubscriberLocalLiveViewImpl(NotificationLocalLiveViewSubscriber &subscriber) : subscriber_(subscriber) +{ + recipient_ = new (std::nothrow) DeathRecipient(*this); +}; + +void NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::OnConnected() +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + if (GetAnsManagerProxy()) { + proxy_->AsObject()->AddDeathRecipient(recipient_); + ANS_LOGD("%s, Add death recipient.", __func__); + } + subscriber_.OnConnected(); +} + +void NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::OnDisconnected() +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + if (GetAnsManagerProxy()) { + proxy_->AsObject()->RemoveDeathRecipient(recipient_); + ANS_LOGD("%s, Remove death recipient.", __func__); + } + subscriber_.OnDisconnected(); +} + +void NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::OnResponse(int32_t notificationId, sptr buttonOption) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + subscriber_.OnResponse(notificationId, buttonOption); +} + +bool NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::GetAnsManagerProxy() +{ + if (proxy_ == nullptr) { + std::lock_guard lock(mutex_); + if (proxy_ == nullptr) { + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!systemAbilityManager) { + return false; + } + + sptr remoteObject = + systemAbilityManager->GetSystemAbility(ADVANCED_NOTIFICATION_SERVICE_ABILITY_ID); + if (!remoteObject) { + return false; + } + + proxy_ = iface_cast(remoteObject); + if ((proxy_ == nullptr) || (proxy_->AsObject() == nullptr)) { + return false; + } + } + } + + return true; +} + +NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::DeathRecipient::DeathRecipient(SubscriberLocalLiveViewImpl &subscriberImpl) + : subscriberImpl_(subscriberImpl) {}; + +NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::DeathRecipient::~DeathRecipient() {}; + +void NotificationLocalLiveViewSubscriber::SubscriberLocalLiveViewImpl::DeathRecipient::OnRemoteDied(const wptr &object) +{ + subscriberImpl_.proxy_ = nullptr; + subscriberImpl_.subscriber_.OnDied(); +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ans/src/notification_progress.cpp b/frameworks/ans/src/notification_progress.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b051c05ea028df52ebc74127a74b8453379db9a --- /dev/null +++ b/frameworks/ans/src/notification_progress.cpp @@ -0,0 +1,148 @@ +/* + * 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 "notification_progress.h" + +#include +#include // for basic_string, operator+, basic_string<>... +#include // for shared_ptr, shared_ptr<>::element_type + + +#include "ans_log_wrapper.h" +#include "nlohmann/json.hpp" // for json, basic_json<>::object_t, basic_json +#include "parcel.h" // for Parcel + +namespace OHOS { +namespace Notification { + +int32_t NotificationProgress::GetMaxValue() const +{ + return maxValue_; +} + +void NotificationProgress::SetMaxValue(int32_t maxValue) +{ + maxValue_ = maxValue; +} + +int32_t NotificationProgress::GetCurrentValue() const +{ + return currentValue_; +} + +void NotificationProgress::SetCurrentValue(int32_t curValue) +{ + currentValue_ = curValue; +} + +int32_t NotificationProgress::GetIsPercentage() const +{ + return isPercentage_; +} + +void NotificationProgress::SetIsPercentage(int32_t isPercentage) +{ + isPercentage_ = isPercentage; +} + + +std::string NotificationProgress::Dump() +{ + return "Progress{ " + "maxValue = " + std::to_string(maxValue_) + + ", currentValue = " + std::to_string(currentValue_) + + ", isPercentage = " + std::to_string(isPercentage_) + + " }"; +} + +bool NotificationProgress::ToJson(nlohmann::json &jsonObject) const +{ + jsonObject["maxValue"] = maxValue_; + jsonObject["currentValue"] = currentValue_; + jsonObject["isPercentage"] = isPercentage_; + + return true; +} + +NotificationProgress *NotificationProgress::FromJson(const nlohmann::json &jsonObject) +{ + if (jsonObject.is_null() or !jsonObject.is_object()) { + ANS_LOGE("Invalid JSON object"); + return nullptr; + } + + NotificationProgress *progress = new (std::nothrow) NotificationProgress(); + if (progress == nullptr) { + ANS_LOGE("Failed to create capsule instance"); + return nullptr; + } + + const auto &jsonEnd = jsonObject.cend(); + if (jsonObject.find("maxValue") != jsonEnd && jsonObject.at("maxValue").is_number_integer()) { + progress->maxValue_ = jsonObject.at("maxValue").get(); + } + + if (jsonObject.find("currentValue") != jsonEnd && jsonObject.at("currentValue").is_number_integer()) { + progress->currentValue_ = jsonObject.at("currentValue").get(); + } + + if (jsonObject.find("isPercentage") != jsonEnd && jsonObject.at("isPercentage").is_number_integer()) { + progress->isPercentage_ = jsonObject.at("isPercentage_").get(); + } + + return progress; +} + +bool NotificationProgress::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteInt32(maxValue_)) { + ANS_LOGE("Failed to write maxValue"); + return false; + } + + if (!parcel.WriteInt32(currentValue_)) { + ANS_LOGE("Failed to write currentValue"); + return false; + } + + if (!parcel.WriteInt32(isPercentage_)) { + ANS_LOGE("Failed to write isPercentage"); + return false; + } + return true; +} + +bool NotificationProgress::ReadFromParcel(Parcel &parcel) +{ + maxValue_ = parcel.ReadInt32(); + currentValue_ = parcel.ReadInt32(); + isPercentage_ = parcel.ReadInt32(); + + return true; +} + +NotificationProgress *NotificationProgress::Unmarshalling(Parcel &parcel) +{ + NotificationProgress *progress = new (std::nothrow) NotificationProgress(); + + if (progress && !progress->ReadFromParcel(parcel)) { + delete progress; + progress = nullptr; + } + + return progress; +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/core/include/ans_manager_interface.h b/frameworks/core/include/ans_manager_interface.h index 6159fd14580599269ed2dd1c2d6bf690eebae328..3a595b2cb80d2b8c0dcb114bd465de6dea2d5ee0 100644 --- a/frameworks/core/include/ans_manager_interface.h +++ b/frameworks/core/include/ans_manager_interface.h @@ -20,6 +20,7 @@ #include #include "ans_subscriber_interface.h" +#include "ans_subscriber_local_live_view_interface.h" #include "iremote_broker.h" #include "notification_bundle_option.h" #include "notification_constant.h" @@ -246,6 +247,18 @@ public: */ virtual ErrCode HasNotificationPolicyAccessPermission(bool &granted) = 0; + /** + * @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. + */ + virtual ErrCode TriggerLocalLiveView(const sptr &bundleOption, + const int32_t notificationId, const sptr &buttonOption) = 0; + /** * @brief Delete notification based on key. * @@ -384,6 +397,16 @@ public: virtual ErrCode Subscribe(const sptr &subscriber, const sptr &info) = 0; + /** + * @brief Subscribes system activity notifications. + * + * @param subscriber Indicates the subscriber. + * @param info Indicates the NotificationSubscribeInfo object. + * @return Returns ERR_OK on success, others on failure. + */ + virtual ErrCode SubscribeLocalLiveView(const sptr &subscriber, + const sptr &info) = 0; + /** * @brief Unsubscribes notifications. * diff --git a/frameworks/core/include/ans_manager_proxy.h b/frameworks/core/include/ans_manager_proxy.h index c31fc4330fe626cb8e212fbf9c78fca1d483f260..f938d548be71f5a05b76c569dadb84ff1aa9f803 100644 --- a/frameworks/core/include/ans_manager_proxy.h +++ b/frameworks/core/include/ans_manager_proxy.h @@ -235,6 +235,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. * @@ -373,6 +385,17 @@ 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/frameworks/core/include/ans_manager_stub.h b/frameworks/core/include/ans_manager_stub.h index e901da196d89702d4d499b4e7c0ee7faacf6f57a..2b1317a6c982cffc046c6a261cd8d273847e5c56 100644 --- a/frameworks/core/include/ans_manager_stub.h +++ b/frameworks/core/include/ans_manager_stub.h @@ -20,6 +20,7 @@ #include #include "ans_manager_interface.h" +#include "ans_subscriber_local_live_view_interface.h" #include "distributed_notification_service_ipc_interface_code.h" #include "iremote_stub.h" @@ -250,6 +251,18 @@ public: */ virtual 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. + */ + virtual ErrCode TriggerLocalLiveView(const sptr &bundleOption, + const int32_t notificationId, const sptr &buttonOption) override; + /** * @brief Delete notification. * @@ -391,6 +404,9 @@ public: virtual ErrCode Subscribe( const sptr &subscriber, const sptr &info) override; + virtual ErrCode SubscribeLocalLiveView( + const sptr &subscriber, const sptr &info) override; + /** * @brief Unsubscribes notifications. * @@ -760,6 +776,8 @@ private: ErrCode HandleSetBadgeNumber(MessageParcel &data, MessageParcel &reply); ErrCode HandleRegisterPushCallback(MessageParcel &data, MessageParcel &reply); ErrCode HandleUnregisterPushCallback(MessageParcel &data, MessageParcel &reply); + ErrCode HandleSubscribeLocalLiveView(MessageParcel &data, MessageParcel &reply); + ErrCode HandleTriggerLocalLiveView(MessageParcel &data, MessageParcel &reply); template bool WriteParcelableVector(const std::vector> &parcelableVector, MessageParcel &reply, ErrCode &result) diff --git a/frameworks/core/include/ans_notification.h b/frameworks/core/include/ans_notification.h index b91ea0decdfce3d490b700696a08cd2d7f8c3aad..3ea593bd3f4d138e9ec33a9ba4e25143756b8a77 100644 --- a/frameworks/core/include/ans_notification.h +++ b/frameworks/core/include/ans_notification.h @@ -21,6 +21,7 @@ #include "ans_manager_death_recipient.h" #include "ans_manager_interface.h" #include "notification_subscriber.h" +#include "notification_local_live_view_subscriber.h" namespace OHOS { namespace Notification { @@ -297,6 +298,22 @@ public: */ ErrCode SubscribeNotification(const NotificationSubscriber &subscriber); + /** + * @brief Subscribes to notifications from all applications. This method can be called only by applications + * with required system permissions. + * @note To subscribe to a notification, inherit the {NotificationSubscriber} class, override its + * callback methods and create a subscriber. The subscriber will be used as a parameter of this method. + * After the notification is published, subscribers that meet the filter criteria can receive the + * notification. To subscribe to notifications published only by specified sources, for example, notifications from + * certain applications, call the {SubscribeNotification(NotificationSubscriber, NotificationSubscribeInfo)} + * method. + * + * @param subscriber Indicates the {NotificationSubscriber} to receive notifications. + * This parameter must be specified. + * @return Returns subscribe notification result. + */ + ErrCode SubscribeLocalLiveViewNotification(const NotificationLocalLiveViewSubscriber &subscriber); + /** * @brief Subscribes to all notifications based on the filtering criteria. This method can be called only * by applications with required system permissions. @@ -347,6 +364,18 @@ public: */ 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. + */ + 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/frameworks/core/include/distributed_notification_service_ipc_interface_code.h b/frameworks/core/include/distributed_notification_service_ipc_interface_code.h index 959baaa8dee18a1778e8c36b3d114a71c78e6648..78f24ac5deb76ac191d1ecb0961967d5584d4087 100644 --- a/frameworks/core/include/distributed_notification_service_ipc_interface_code.h +++ b/frameworks/core/include/distributed_notification_service_ipc_interface_code.h @@ -117,6 +117,9 @@ namespace Notification { ON_BADGE_CHANGED, // push_callback_interface ON_CHECK_NOTIFICATION, + ON_RESPONSE, + SUBSCRIBE_LOCAL_LIVE_VIEW_NOTIFICATION, + TRIGGER_LOCAL_LIVE_VIEW_NOTIFICATION, }; } } diff --git a/frameworks/core/src/ans_manager_proxy.cpp b/frameworks/core/src/ans_manager_proxy.cpp index e50a8445fea619fec900f9a2191ff4ca252e945f..f2acb74e3e25a8269c2504996bcd77a735d2a99e 100644 --- a/frameworks/core/src/ans_manager_proxy.cpp +++ b/frameworks/core/src/ans_manager_proxy.cpp @@ -18,7 +18,9 @@ #include "ans_const_define.h" #include "ans_inner_errors.h" #include "ans_log_wrapper.h" +#include "ans_subscriber_local_live_view_interface.h" #include "distributed_notification_service_ipc_interface_code.h" +#include "errors.h" #include "message_option.h" #include "message_parcel.h" #include "parcel.h" @@ -739,6 +741,51 @@ ErrCode AnsManagerProxy::HasNotificationPolicyAccessPermission(bool &granted) return result; } +ErrCode AnsManagerProxy::TriggerLocalLiveView(const sptr &bundleOption, + const int32_t notificationId, const sptr &buttonOption) +{ + if (bundleOption == nullptr) { + ANS_LOGE("[TriggerLocalLiveView] fail: bundle is empty."); + return ERR_ANS_INVALID_PARAM; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(AnsManagerProxy::GetDescriptor())) { + ANS_LOGE("[TriggerLocalLiveView] fail:, write interface token failed."); + return ERR_ANS_PARCELABLE_FAILED; + } + + if (!data.WriteStrongParcelable(bundleOption)) { + ANS_LOGE("[TriggerLocalLiveView] fail:: write bundle failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + + if (!data.WriteInt32(notificationId)) { + ANS_LOGE("[TriggerLocalLiveView] fail: write notificationId failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + + if (!data.WriteStrongParcelable(buttonOption)) { + ANS_LOGE("[TriggerLocalLiveView] fail: write label failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + + MessageParcel reply; + MessageOption option = {MessageOption::TF_SYNC}; + ErrCode result = InnerTransact(NotificationInterfaceCode::TRIGGER_LOCAL_LIVE_VIEW_NOTIFICATION, option, data, reply); + if (result != ERR_OK) { + ANS_LOGE("[TriggerLocalLiveView] fail: transact ErrCode=%{public}d", result); + return ERR_ANS_TRANSACT_FAILED; + } + + if (!reply.ReadInt32(result)) { + ANS_LOGE("[TriggerLocalLiveView] fail: read result error."); + return ERR_ANS_PARCELABLE_FAILED; + } + + return result; +} + ErrCode AnsManagerProxy::RemoveNotification(const sptr &bundleOption, int32_t notificationId, const std::string &label, int32_t removeReason) { @@ -1358,6 +1405,53 @@ ErrCode AnsManagerProxy::Subscribe(const sptr &subscribe return result; } +ErrCode AnsManagerProxy::SubscribeLocalLiveView(const sptr &subscriber, const sptr &info) +{ + if (subscriber == nullptr) { + ANS_LOGE("[Subscribe] fail: subscriber is empty."); + return ERR_ANS_INVALID_PARAM; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(AnsManagerProxy::GetDescriptor())) { + ANS_LOGE("[Subscribe] fail: write interface token failed."); + return ERR_ANS_PARCELABLE_FAILED; + } + + bool ret = data.WriteRemoteObject(subscriber->AsObject()); + if (!ret) { + ANS_LOGE("[Subscribe] fail: write subscriber failed."); + return ERR_ANS_PARCELABLE_FAILED; + } + + if (!data.WriteBool(info != nullptr)) { + ANS_LOGE("[Subscribe] fail: write isSubcribeInfo failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + + if (info != nullptr) { + if (!data.WriteParcelable(info)) { + ANS_LOGE("[Subscribe] fail: write subcribeInfo failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + } + + MessageParcel reply; + MessageOption option = {MessageOption::TF_SYNC}; + ErrCode result = InnerTransact(NotificationInterfaceCode::SUBSCRIBE_LOCAL_LIVE_VIEW_NOTIFICATION, option, data, reply); + if (result != ERR_OK) { + ANS_LOGE("[Subscribe] fail: transact ErrCode=%{public}d", result); + return ERR_ANS_TRANSACT_FAILED; + } + + if (!reply.ReadInt32(result)) { + ANS_LOGE("[Subscribe] fail: read result failed."); + return ERR_ANS_PARCELABLE_FAILED; + } + + return result; +} + ErrCode AnsManagerProxy::Unsubscribe( const sptr &subscriber, const sptr &info) { diff --git a/frameworks/core/src/ans_manager_stub.cpp b/frameworks/core/src/ans_manager_stub.cpp index d34a92c4179968ae50c0687cc79111f4a6c7b890..2c7b5c090383538dc5597b2f10350395e5c8c509 100644 --- a/frameworks/core/src/ans_manager_stub.cpp +++ b/frameworks/core/src/ans_manager_stub.cpp @@ -17,8 +17,10 @@ #include "ans_const_define.h" #include "ans_inner_errors.h" #include "ans_log_wrapper.h" +#include "ans_subscriber_local_live_view_interface.h" #include "message_option.h" #include "message_parcel.h" +#include "notification_button_option.h" #include "parcel.h" #include "reminder_request_alarm.h" #include "reminder_request_calendar.h" @@ -251,6 +253,10 @@ const std::map bundleOption = data.ReadStrongParcelable(); + if (bundleOption == nullptr) { + ANS_LOGE("[HandleTriggerLocalLiveView] fail: read bundle failed."); + return ERR_ANS_PARCELABLE_FAILED; + } + + int32_t notificationId = 0; + if (!data.ReadInt32(notificationId)) { + ANS_LOGE("[HandleTriggerLocalLiveView] fail: read notificationId failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + + sptr buttonOption = data.ReadStrongParcelable(); + if (buttonOption == nullptr) { + ANS_LOGE("[HandleTriggerLocalLiveView] fail: read button failed."); + return ERR_ANS_PARCELABLE_FAILED; + } + + ErrCode result = TriggerLocalLiveView(bundleOption, notificationId, buttonOption); + if (!reply.WriteInt32(result)) { + ANS_LOGE("[HandleTriggerLocalLiveView] fail: write result failed, ErrCode=%{public}d", result); + return ERR_ANS_PARCELABLE_FAILED; + } + return ERR_OK; +} + ErrCode AnsManagerStub::HandleRemoveNotification(MessageParcel &data, MessageParcel &reply) { sptr bundleOption = data.ReadStrongParcelable(); @@ -1103,6 +1137,37 @@ ErrCode AnsManagerStub::HandleSubscribe(MessageParcel &data, MessageParcel &repl return ERR_OK; } +ErrCode AnsManagerStub::HandleSubscribeLocalLiveView(MessageParcel &data, MessageParcel &reply) +{ + sptr subscriber = data.ReadRemoteObject(); + if (subscriber == nullptr) { + ANS_LOGE("[HandleSubscribeLocalLiveView] fail: read subscriber failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + + bool subcribeInfo = false; + if (!data.ReadBool(subcribeInfo)) { + ANS_LOGE("[HandleSubscribeLocalLiveView] fail: read isSubcribeInfo failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + + sptr info = nullptr; + if (subcribeInfo) { + info = data.ReadParcelable(); + if (info == nullptr) { + ANS_LOGE("[HandleSubscribeLocalLiveView] fail: read info failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + } + + ErrCode result = SubscribeLocalLiveView(iface_cast(subscriber), info); + if (!reply.WriteInt32(result)) { + ANS_LOGE("[HandleSubscribeLocalLiveView] fail: write result failed, ErrCode=%{public}d", result); + return ERR_ANS_PARCELABLE_FAILED; + } + return ERR_OK; +} + ErrCode AnsManagerStub::HandleUnsubscribe(MessageParcel &data, MessageParcel &reply) { sptr subscriber = data.ReadRemoteObject(); @@ -1884,6 +1949,13 @@ ErrCode AnsManagerStub::HasNotificationPolicyAccessPermission(bool &granted) return ERR_INVALID_OPERATION; } +ErrCode AnsManagerStub::TriggerLocalLiveView(const sptr &bundleOption, + const int32_t notificationId, const sptr &buttonOption) +{ + ANS_LOGE("AnsManagerStub::TriggerLocalLiveView called!"); + return ERR_INVALID_OPERATION; +} + ErrCode AnsManagerStub::RemoveNotification(const sptr &bundleOption, int notificationId, const std::string &label, int32_t removeReason) { @@ -1985,6 +2057,13 @@ ErrCode AnsManagerStub::Subscribe(const sptr &subscriber return ERR_INVALID_OPERATION; } +ErrCode AnsManagerStub::SubscribeLocalLiveView(const sptr &subscriber, + const sptr &info) +{ + ANS_LOGE("AnsManagerStub::SubscribeLocalLiveView called!"); + return ERR_INVALID_OPERATION; +} + ErrCode AnsManagerStub::Unsubscribe(const sptr &subscriber, const sptr &info) { diff --git a/frameworks/core/src/ans_notification.cpp b/frameworks/core/src/ans_notification.cpp index c9b79d1533fa60a2cb32bffc79c49a34f74042bb..6aaf042c6094f35d8fc115a05e91518fd90c4524 100644 --- a/frameworks/core/src/ans_notification.cpp +++ b/frameworks/core/src/ans_notification.cpp @@ -19,6 +19,8 @@ #include "ans_log_wrapper.h" #include "hitrace_meter.h" #include "iservice_registry.h" +#include "notification_button_option.h" +#include "notification_local_live_view_subscriber.h" #include "reminder_request_alarm.h" #include "reminder_request_calendar.h" #include "reminder_request_timer.h" @@ -377,6 +379,22 @@ ErrCode AnsNotification::SubscribeNotification(const NotificationSubscriber &sub return ansManagerProxy_->Subscribe(subscriberSptr, nullptr); } +ErrCode AnsNotification::SubscribeLocalLiveViewNotification(const NotificationLocalLiveViewSubscriber &subscriber) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + if (!GetAnsManagerProxy()) { + ANS_LOGE("GetAnsManagerProxy fail."); + return ERR_ANS_SERVICE_NOT_CONNECTED; + } + + sptr subscriberSptr = subscriber.GetImpl(); + if (subscriberSptr == nullptr) { + ANS_LOGE("Failed to subscribe with SubscriberImpl null ptr."); + return ERR_ANS_INVALID_PARAM; + } + return ansManagerProxy_->SubscribeLocalLiveView(subscriberSptr, nullptr); +} + ErrCode AnsNotification::SubscribeNotification( const NotificationSubscriber &subscriber, const NotificationSubscribeInfo &subscribeInfo) { @@ -439,6 +457,30 @@ ErrCode AnsNotification::UnSubscribeNotification( return ansManagerProxy_->Unsubscribe(subscriberSptr, sptrInfo); } +ErrCode AnsNotification::TriggerLocalLiveView(const NotificationBundleOption &bundleOption, + const int32_t notificationId, const NotificationButtonOption &buttonOption) +{ + HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); + if (bundleOption.GetBundleName().empty()) { + ANS_LOGE("Invalid bundle name."); + return ERR_ANS_INVALID_PARAM; + } + + if (buttonOption.GetButtonName().empty()) { + ANS_LOGE("Invalid button name."); + return ERR_ANS_INVALID_PARAM; + } + + if (!GetAnsManagerProxy()) { + ANS_LOGE("Fail to GetAnsManagerProxy."); + return ERR_ANS_SERVICE_NOT_CONNECTED; + } + + sptr bo(new (std::nothrow) NotificationBundleOption(bundleOption)); + sptr button(new (std::nothrow) NotificationButtonOption(buttonOption)); + return ansManagerProxy_->TriggerLocalLiveView(bo, notificationId, button); +} + ErrCode AnsNotification::RemoveNotification(const std::string &key, int32_t removeReason) { HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__); diff --git a/frameworks/core/src/ans_subscriber_local_live_view_proxy.cpp b/frameworks/core/src/ans_subscriber_local_live_view_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a1cac44c554ca892a0926a010a40bd6fecdff58 --- /dev/null +++ b/frameworks/core/src/ans_subscriber_local_live_view_proxy.cpp @@ -0,0 +1,118 @@ +/* + * 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 "ans_subscriber_local_live_view_proxy.h" + +#include "ans_inner_errors.h" +#include "ans_log_wrapper.h" +#include "message_option.h" +#include "message_parcel.h" + +namespace OHOS { +namespace Notification { +AnsSubscriberLocalLiveViewProxy::AnsSubscriberLocalLiveViewProxy(const sptr &impl) : IRemoteProxy(impl) +{} + +AnsSubscriberLocalLiveViewProxy::~AnsSubscriberLocalLiveViewProxy() +{} + +ErrCode AnsSubscriberLocalLiveViewProxy::InnerTransact( + NotificationInterfaceCode code, MessageOption &flags, MessageParcel &data, MessageParcel &reply) +{ + auto remote = Remote(); + if (remote == nullptr) { + ANS_LOGE("[InnerTransact] fail: get Remote fail code %{public}u", code); + return ERR_DEAD_OBJECT; + } + + int32_t err = remote->SendRequest(static_cast(code), data, reply, flags); + switch (err) { + case NO_ERROR: { + return ERR_OK; + } + case DEAD_OBJECT: { + ANS_LOGE("[InnerTransact] fail: ipcErr=%{public}d code %{public}d", err, code); + return ERR_DEAD_OBJECT; + } + default: { + ANS_LOGE("[InnerTransact] fail: ipcErr=%{public}d code %{public}d", err, code); + return ERR_ANS_TRANSACT_FAILED; + } + } +} + +void AnsSubscriberLocalLiveViewProxy::OnConnected() +{ + MessageParcel data; + if (!data.WriteInterfaceToken(AnsSubscriberLocalLiveViewProxy::GetDescriptor())) { + ANS_LOGE("[OnConnected] fail: write interface token failed."); + return; + } + + MessageParcel reply; + MessageOption option = {MessageOption::TF_ASYNC}; + ErrCode result = InnerTransact(NotificationInterfaceCode::ON_CONNECTED, option, data, reply); + if (result != ERR_OK) { + ANS_LOGE("[OnConnected] fail: transact ErrCode=ERR_ANS_TRANSACT_FAILED"); + return; + } +} + +void AnsSubscriberLocalLiveViewProxy::OnDisconnected() +{ + MessageParcel data; + if (!data.WriteInterfaceToken(AnsSubscriberLocalLiveViewProxy::GetDescriptor())) { + ANS_LOGE("[OnDisconnected] fail: write interface token failed."); + return; + } + + MessageParcel reply; + MessageOption option = {MessageOption::TF_ASYNC}; + ErrCode result = InnerTransact(NotificationInterfaceCode::ON_DISCONNECTED, option, data, reply); + if (result != ERR_OK) { + ANS_LOGE("[OnDisconnected] fail: transact ErrCode=ERR_ANS_TRANSACT_FAILED"); + return; + } +} + + +void AnsSubscriberLocalLiveViewProxy::OnResponse(int32_t notificationId, sptr buttonOption) +{ + MessageParcel data; + if (!data.WriteInterfaceToken(AnsSubscriberLocalLiveViewProxy::GetDescriptor())) { + ANS_LOGE("[OnResponse] fail: write interface token failed."); + return; + } + + if (!data.WriteInt32(notificationId)) { + ANS_LOGE("[OnResponse] fail: write notificationId failed"); + return; + } + + if (!data.WriteParcelable(buttonOption)) { + ANS_LOGE("[OnResponse] fail: write buttonName failed"); + return; + } + + MessageParcel reply; + MessageOption option = {MessageOption::TF_ASYNC}; + ErrCode result = InnerTransact(NotificationInterfaceCode::ON_RESPONSE, option, data, reply); + if (result != ERR_OK) { + ANS_LOGE("[OnResponse] fail: transact ErrCode=ERR_ANS_TRANSACT_FAILED"); + return; + } +} +} // namespace Notification +} // namespace OHOS diff --git a/frameworks/core/src/ans_subscriber_local_live_view_stub.cpp b/frameworks/core/src/ans_subscriber_local_live_view_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4cdb5469ce94a24fd33d8a37ad743c91e736b5b --- /dev/null +++ b/frameworks/core/src/ans_subscriber_local_live_view_stub.cpp @@ -0,0 +1,131 @@ +/* + * 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_subscriber_local_live_view_stub.h" + +#include "ans_const_define.h" +#include "ans_inner_errors.h" +#include "ans_log_wrapper.h" +#include "message_option.h" +#include "message_parcel.h" +#include "notification_bundle_option.h" +#include "notification_button_option.h" +#include "parcel.h" +#include "refbase.h" +#include + +namespace OHOS { +namespace Notification { +AnsSubscriberLocalLiveViewStub::AnsSubscriberLocalLiveViewStub() +{ + interfaces_.emplace(NotificationInterfaceCode::ON_CONNECTED, + std::bind(&AnsSubscriberLocalLiveViewStub::HandleOnConnected, this, std::placeholders::_1, std::placeholders::_2)); + interfaces_.emplace(NotificationInterfaceCode::ON_DISCONNECTED, + std::bind(&AnsSubscriberLocalLiveViewStub::HandleOnDisconnected, this, std::placeholders::_1, std::placeholders::_2)); + interfaces_.emplace(NotificationInterfaceCode::ON_RESPONSE, + std::bind(&AnsSubscriberLocalLiveViewStub::HandleOnResponse, this, std::placeholders::_1, std::placeholders::_2)); +} + +AnsSubscriberLocalLiveViewStub::~AnsSubscriberLocalLiveViewStub() +{} + +int32_t AnsSubscriberLocalLiveViewStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &flags) +{ + std::u16string descriptor = AnsSubscriberLocalLiveViewStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + ANS_LOGW("[OnRemoteRequest] fail: invalid interface token!"); + return OBJECT_NULL; + } + + auto it = interfaces_.find(static_cast(code)); + if (it == interfaces_.end()) { + ANS_LOGW("[OnRemoteRequest] fail: unknown code!"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, flags); + } + + auto fun = it->second; + if (fun == nullptr) { + ANS_LOGW("[OnRemoteRequest] fail: not find function!"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, flags); + } + + fun(data, reply); + return NO_ERROR; +} + +ErrCode AnsSubscriberLocalLiveViewStub::HandleOnConnected(MessageParcel &data, MessageParcel &reply) +{ + OnConnected(); + return ERR_OK; +} + +ErrCode AnsSubscriberLocalLiveViewStub::HandleOnDisconnected(MessageParcel &data, MessageParcel &reply) +{ + OnDisconnected(); + return ERR_OK; +} + +template +bool AnsSubscriberLocalLiveViewStub::ReadParcelableVector(std::vector> &parcelableInfos, MessageParcel &data) +{ + int32_t infoSize = 0; + if (!data.ReadInt32(infoSize)) { + ANS_LOGE("read Parcelable size failed."); + return false; + } + + parcelableInfos.clear(); + infoSize = (infoSize < MAX_PARCELABLE_VECTOR_NUM) ? infoSize : MAX_PARCELABLE_VECTOR_NUM; + for (int32_t index = 0; index < infoSize; index++) { + sptr info = data.ReadStrongParcelable(); + if (info == nullptr) { + ANS_LOGE("read Parcelable infos failed."); + return false; + } + parcelableInfos.emplace_back(info); + } + + return true; +} + +ErrCode AnsSubscriberLocalLiveViewStub::HandleOnResponse(MessageParcel &data, MessageParcel &reply) +{ + int32_t notificationId = 0; + if (!data.ReadInt32(notificationId)) { + ANS_LOGE("[HandleOnResponse] fail : read notificationId failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + sptr buttonOption = nullptr; + buttonOption = data.ReadParcelable(); + if (buttonOption == nullptr) { + ANS_LOGE("[HandleOnResponse] fail : read buttonOption failed"); + return ERR_ANS_PARCELABLE_FAILED; + } + OnResponse(notificationId, buttonOption); + return ERR_OK; +} + +void AnsSubscriberLocalLiveViewStub::OnConnected() +{} + +void AnsSubscriberLocalLiveViewStub::OnDisconnected() +{} + +void AnsSubscriberLocalLiveViewStub::OnResponse(int32_t notificationId, sptr buttonOption) +{} +} // namespace Notification +} // namespace OHOS diff --git a/frameworks/core/test/unittest/ans_notification_branch_test/ans_notification_branch_test.cpp b/frameworks/core/test/unittest/ans_notification_branch_test/ans_notification_branch_test.cpp index d0457ea46473555dc06e51ef8fd64a11090d87dd..293c96ff2c9733a6ffcc6622239a71e5ad333dcb 100755 --- a/frameworks/core/test/unittest/ans_notification_branch_test/ans_notification_branch_test.cpp +++ b/frameworks/core/test/unittest/ans_notification_branch_test/ans_notification_branch_test.cpp @@ -246,6 +246,12 @@ public: return ERR_ANS_INVALID_PARAM; } + ErrCode SubscribeLocalLiveView(const sptr &subscriber, + const sptr &info) override + { + return ERR_ANS_INVALID_PARAM; + } + ErrCode Unsubscribe( const sptr &subscriber, const sptr &info) override { @@ -425,6 +431,12 @@ public: { return ERR_ANS_INVALID_PARAM; } + + ErrCode TriggerLocalLiveView(const sptr &bundleOption, + const int32_t notificationId, const sptr &buttonOption) override + { + return ERR_ANS_INVALID_PARAM; + } }; class AnsNotificationBranchTest : public testing::Test { diff --git a/frameworks/js/napi/include/common.h b/frameworks/js/napi/include/common.h index d7bb8acf9cc4c1ea95dca333bbd9d77c7c95ca8e..a050c3c4078bc8799df4e593654fca220f5ebf35 100644 --- a/frameworks/js/napi/include/common.h +++ b/frameworks/js/napi/include/common.h @@ -19,6 +19,7 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "notification_helper.h" +#include "notification_local_live_view_button.h" namespace OHOS { namespace NotificationNapi { @@ -38,7 +39,8 @@ enum class ContentType { NOTIFICATION_CONTENT_LONG_TEXT, NOTIFICATION_CONTENT_PICTURE, NOTIFICATION_CONTENT_CONVERSATION, - NOTIFICATION_CONTENT_MULTILINE + NOTIFICATION_CONTENT_MULTILINE, + NOTIFICATION_CONTENT_LOCAL_LIVE_VIEW }; enum class SlotType { @@ -46,6 +48,7 @@ enum class SlotType { SOCIAL_COMMUNICATION = 1, SERVICE_INFORMATION = 2, CONTENT_INFORMATION = 3, + LIVE_VIEW = 4, OTHER_TYPES = 0xFFFF, }; @@ -226,6 +229,16 @@ public: static void SetCallback( const napi_env &env, const napi_ref &callbackIn, const napi_value &result); + /** + * @brief Calls the callback with the result + * + * @param env Indicates the environment that the API is invoked under + * @param callbackIn Indicates the callback to be called + * @param result Indicates the result returned by the callback + */ + static void SetCallbackArg2( + const napi_env &env, const napi_ref &callbackIn, const napi_value &result0, const napi_value &result1); + /** * @brief Processes the promise with the result and error code * @@ -1203,6 +1216,72 @@ public: const napi_env &env, const napi_value &contentResult, std::shared_ptr &pictureContent); + /** + * @brief Gets a NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param result Indicates a js object to be converted + * @param request Indicates a NotificationLocalLiveViewContent object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewContent( + const napi_env &env, const napi_value &result, NotificationRequest &request); + + /** + * @brief Gets a capsule of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a capsule object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewCapsule( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a button of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a button object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewButton( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a time of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a time object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewTime( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a progress of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a progress object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewProgress( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + + /** + * @brief Gets a NotificationPictureContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param pictureContent Indicates a NotificationPictureContent object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewContentDetailed( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + /** * @brief Gets a conversational content of NotificationRequest object from specified js object * @@ -1369,6 +1448,16 @@ public: */ static napi_value GetBundleOption(const napi_env &env, const napi_value &value, NotificationBundleOption &option); + /** + * @brief Gets a NotificationButtonOption object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param value Indicates a js object to be converted + * @param option Indicates a NotificationButtonOption object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetButtonOption(const napi_env &env, const napi_value &value, NotificationButtonOption &option); + static napi_value GetHashCodes(const napi_env &env, const napi_value &value, std::vector &hashCodes); /** diff --git a/frameworks/js/napi/src/common.cpp b/frameworks/js/napi/src/common.cpp index f1614d2dd29435215cfd69a1f0d6e20e63e2837d..c8eb4ffa5a1b4a1bc587fc53b8edd8ba120c6de6 100644 --- a/frameworks/js/napi/src/common.cpp +++ b/frameworks/js/napi/src/common.cpp @@ -16,6 +16,9 @@ #include "common.h" #include "ans_inner_errors.h" #include "napi_common.h" +#include "notification_action_button.h" +#include "notification_capsule.h" +#include "notification_progress.h" #include "pixel_map_napi.h" namespace OHOS { @@ -169,6 +172,21 @@ void Common::SetCallback( ANS_LOGI("end"); } +void Common::SetCallbackArg2( + const napi_env &env, const napi_ref &callbackIn, const napi_value &result0, const napi_value &result1) +{ + ANS_LOGI("enter"); + napi_value result[ARGS_TWO] = {result0, result1}; + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + + napi_value callback = nullptr; + napi_value resultout = nullptr; + napi_get_reference_value(env, callbackIn, &callback); + NAPI_CALL_RETURN_VOID(env, napi_call_function(env, undefined, callback, ARGS_TWO, result, &resultout)); + ANS_LOGI("end"); +} + void Common::SetPromise(const napi_env &env, const napi_deferred &deferred, const int32_t &errorCode, const napi_value &result, bool newType) { @@ -1794,6 +1812,11 @@ napi_value Common::GetNotificationContent(const napi_env &env, const napi_value return nullptr; } break; + case NotificationContent::Type::LOCAL_LIVE_VIEW: + if (GetNotificationLocalLiveViewContent(env, result, request) == nullptr) { + return nullptr; + } + break; default: return nullptr; } @@ -3976,6 +3999,307 @@ napi_value Common::GetNotificationMultiLineContentLines(const napi_env &env, con return NapiGetNull(env); } +napi_value Common::GetNotificationLocalLiveViewContent( + const napi_env &env, const napi_value &result, NotificationRequest &request) +{ + ANS_LOGI("enter"); + + napi_valuetype valuetype = napi_undefined; + napi_value contentResult = nullptr; + bool hasProperty = false; + NAPI_CALL(env, napi_has_named_property(env, result, "localLiveView", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property localLiveView expected."); + return nullptr; + } + napi_get_named_property(env, result, "localLiveView", &contentResult); + NAPI_CALL(env, napi_typeof(env, contentResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + std::shared_ptr localLiveViewContent = std::make_shared(); + if (localLiveViewContent == nullptr) { + ANS_LOGE("localLiveViewContent is null"); + return nullptr; + } + + if (GetNotificationLocalLiveViewContentDetailed(env, contentResult, localLiveViewContent) == nullptr) { + return nullptr; + } + + request.SetContent(std::make_shared(localLiveViewContent)); + + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewCapsule( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content) +{ + napi_value capsuleResult = nullptr; + napi_valuetype valuetype = napi_undefined; + bool hasProperty = false; + size_t strLen = 0; + char str[STR_MAX_SIZE] = {0}; + std::shared_ptr pixelMap = nullptr; + napi_value result = nullptr; + + ANS_LOGI("enter"); + + NAPI_CALL(env, napi_has_named_property(env, contentResult, "capsule", &hasProperty)); + + napi_get_named_property(env, contentResult, "capsule", &capsuleResult); + NAPI_CALL(env, napi_typeof(env, capsuleResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + NotificationCapsule capsule; + + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "title", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "title", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + capsule.SetTitle(str); + ANS_LOGD("capsule title = %{public}s", str); + } + + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "backgroundColor", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "backgroundColor", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + capsule.SetBackgroundColor(str); + ANS_LOGD("capsule backgroundColor = %{public}s", str); + } + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "icon", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "icon", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + pixelMap = Media::PixelMapNapi::GetPixelMap(env, result); + if (pixelMap == nullptr) { + ANS_LOGE("Invalid object pixelMap"); + return nullptr; + } + capsule.SetIcon(pixelMap); + ANS_LOGD("capsule icon = %{public}s", str); + } + + content->SetCapsule(capsule); + + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewButton( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content) +{ + napi_value result = nullptr; + napi_valuetype valuetype = napi_undefined; + bool isArray = false; + uint32_t length = 0; + napi_value buttonResult = nullptr; + bool hasProperty = false; + char str[STR_MAX_SIZE] = {0}; + size_t strLen = 0; + + ANS_LOGI("enter"); + + napi_get_named_property(env, contentResult, "button", &buttonResult); + NAPI_CALL(env, napi_typeof(env, buttonResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + NotificationLocalLiveViewButton button; + + NAPI_CALL(env, napi_has_named_property(env, buttonResult, "buttonNames", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, buttonResult, "buttonNames", &result); + napi_is_array(env, result, &isArray); + if (!isArray) { + ANS_LOGE("Property buttonNames is expected to be an array."); + return nullptr; + } + napi_get_array_length(env, result, &length); + for (size_t i = 0; i < length; i++) { + napi_value buttonName = nullptr; + napi_get_element(env, result, i, &buttonName); + NAPI_CALL(env, napi_typeof(env, buttonName, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, buttonName, str, STR_MAX_SIZE - 1, &strLen)); + button.addSingleButtonName(str); + ANS_LOGD("button buttonName = %{public}s.", str); + } + } + + NAPI_CALL(env, napi_has_named_property(env, buttonResult, "buttonIcons", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, buttonResult, "buttonIcons", &result); + napi_is_array(env, result, &isArray); + if (!isArray) { + ANS_LOGE("Property buttonIcons is expected to be an array."); + return nullptr; + } + napi_get_array_length(env, result, &length); + for (size_t i = 0; i < length; i++) { + napi_value buttonIcon = nullptr; + std::shared_ptr pixelMap = nullptr; + napi_get_element(env, result, i, &buttonIcon); + NAPI_CALL(env, napi_typeof(env, buttonIcon, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + pixelMap = Media::PixelMapNapi::GetPixelMap(env, buttonIcon); + if (pixelMap == nullptr) { + ANS_LOGE("Invalid object pixelMap"); + return nullptr; + } + button.addSingleButtonIcon(pixelMap); + } + } + ANS_LOGD("button buttonIcon = %{public}s", str); + + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewProgress(const napi_env &env, + const napi_value &contentResult, std::shared_ptr content) +{ + napi_value result = nullptr; + napi_valuetype valuetype = napi_undefined; + bool hasProperty = false; + int32_t intValue = -1; + napi_value progressResult = nullptr; + + ANS_LOGI("enter"); + + napi_get_named_property(env, contentResult, "progress", &progressResult); + NAPI_CALL(env, napi_typeof(env, progressResult, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + + NotificationProgress progress; + + NAPI_CALL(env, napi_has_named_property(env, progressResult, "maxValue", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, progressResult, "maxValue", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &intValue); + progress.SetMaxValue(intValue); + ANS_LOGD("progress intValue = %{public}d", intValue); + } + + NAPI_CALL(env, napi_has_named_property(env, progressResult, "currentValue", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, progressResult, "currentValue", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &intValue); + progress.SetCurrentValue(intValue); + ANS_LOGD("progress currentValue = %{public}d", intValue); + } + + NAPI_CALL(env, napi_has_named_property(env, progressResult, "isPercentage", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, progressResult, "isPercentage", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &intValue); + progress.SetIsPercentage(intValue); + ANS_LOGD("progress isPercentage = %{public}d", intValue); + } + + content->SetProgress(progress); + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewContentDetailed( + const napi_env &env, const napi_value &contentResult, std::shared_ptr content) +{ + bool hasProperty = false; + int32_t type = -1; + napi_value result = nullptr; + napi_valuetype valuetype = napi_undefined; + + ANS_LOGI("enter"); + + //title, text + if (GetNotificationBasicContentDetailed(env, contentResult, content) == nullptr) { + ANS_LOGE("Basic content get fail."); + return nullptr; + } + + //type + NAPI_CALL(env, napi_has_named_property(env, contentResult, "type", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property type expected."); + return nullptr; + } + napi_get_named_property(env, contentResult, "type", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &type); + content->SetType(type); + ANS_LOGD("localLiveView type = %{public}d", type); + + + //capsule? + NAPI_CALL(env, napi_has_named_property(env, contentResult, "capsule", &hasProperty)); + if (hasProperty && GetNotificationLocalLiveViewCapsule(env, contentResult, content) == nullptr) { + return nullptr; + } + + //button? + NAPI_CALL(env, napi_has_named_property(env, contentResult, "button", &hasProperty)); + if (hasProperty && GetNotificationLocalLiveViewButton(env, contentResult, content) == nullptr) { + return nullptr; + } + + //progess? + NAPI_CALL(env, napi_has_named_property(env, contentResult, "progress", &hasProperty)); + if (hasProperty && GetNotificationLocalLiveViewProgress(env, contentResult, content) == nullptr) { + return nullptr; + } + + return NapiGetNull(env); +} + napi_value Common::GetNotificationSlot(const napi_env &env, const napi_value &value, NotificationSlot &slot) { ANS_LOGI("enter"); @@ -4280,6 +4604,34 @@ napi_value Common::GetBundleOption(const napi_env &env, const napi_value &value, return NapiGetNull(env); } +napi_value Common::GetButtonOption(const napi_env &env, const napi_value &value, NotificationButtonOption &option) +{ + ANS_LOGI("enter"); + + bool hasProperty {false}; + napi_valuetype valuetype = napi_undefined; + napi_value result = nullptr; + + char str[STR_MAX_SIZE] = {0}; + size_t strLen = 0; + // buttonName: string + NAPI_CALL(env, napi_has_named_property(env, value, "buttonName", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property buttonName expected."); + return nullptr; + } + napi_get_named_property(env, value, "buttonName", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + option.SetButtonName(str); + + return NapiGetNull(env); +} + napi_value Common::GetHashCodes(const napi_env &env, const napi_value &value, std::vector &hashCodes) { ANS_LOGD("enter"); @@ -4365,6 +4717,9 @@ bool Common::ContentTypeJSToC(const ContentType &inType, NotificationContent::Ty case ContentType::NOTIFICATION_CONTENT_CONVERSATION: outType = NotificationContent::Type::CONVERSATION; break; + case ContentType::NOTIFICATION_CONTENT_LOCAL_LIVE_VIEW: + outType = NotificationContent::Type::LOCAL_LIVE_VIEW; + break; default: ANS_LOGE("ContentType %{public}d is an invalid value", inType); return false; @@ -4390,6 +4745,9 @@ bool Common::ContentTypeCToJS(const NotificationContent::Type &inType, ContentTy case NotificationContent::Type::CONVERSATION: outType = ContentType::NOTIFICATION_CONTENT_CONVERSATION; break; + case NotificationContent::Type::LOCAL_LIVE_VIEW: + outType = ContentType::NOTIFICATION_CONTENT_LOCAL_LIVE_VIEW; + break; default: ANS_LOGE("ContentType %{public}d is an invalid value", inType); return false; diff --git a/frameworks/js/napi/src/manager/BUILD.gn b/frameworks/js/napi/src/manager/BUILD.gn index aabb6277b4007ad6ff45ca9e1a332c346f6212b0..76398444a0e085faa6e15be6451a3abf10bc69ff 100644 --- a/frameworks/js/napi/src/manager/BUILD.gn +++ b/frameworks/js/napi/src/manager/BUILD.gn @@ -72,6 +72,8 @@ ohos_shared_library("notificationmanager") { "napi_remove_group.cpp", "napi_slot.cpp", "napi_template.cpp", + "napi_local_live_view.cpp", + "local_live_view_subscribe.cpp", ] deps = [ "${frameworks_module_ans_path}:ans_innerkits" ] diff --git a/frameworks/js/napi/src/manager/init_module.cpp b/frameworks/js/napi/src/manager/init_module.cpp index 232d2d689013626ec192cbdcdfad3ef30e80b449..1c0cc8e0f28f8aabd9feb09330547619cc18206e 100644 --- a/frameworks/js/napi/src/manager/init_module.cpp +++ b/frameworks/js/napi/src/manager/init_module.cpp @@ -30,6 +30,7 @@ #include "napi_template.h" #include "pixel_map_napi.h" #include "napi_push.h" +#include "napi_local_live_view.h" namespace OHOS { namespace NotificationNapi { @@ -101,6 +102,8 @@ napi_value NotificationManagerInit(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("getDeviceRemindType", NapiGetDeviceRemindType), DECLARE_NAPI_FUNCTION("setSyncNotificationEnabledWithoutApp", NapiSetSyncNotificationEnabledWithoutApp), DECLARE_NAPI_FUNCTION("getSyncNotificationEnabledWithoutApp", NapiGetSyncNotificationEnabledWithoutApp), + DECLARE_NAPI_FUNCTION("subscribeLocalLiveView", NapiSubscriteLocalAcitvity), + DECLARE_NAPI_FUNCTION("trigger", NapiTriggerLocalLiveView), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); diff --git a/frameworks/js/napi/src/manager/local_live_view_subscribe.cpp b/frameworks/js/napi/src/manager/local_live_view_subscribe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..156fc0ca5cad099aee8554fd72c7f8b4658ca1d8 --- /dev/null +++ b/frameworks/js/napi/src/manager/local_live_view_subscribe.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2021-2023 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 "local_live_view_subscribe.h" +#include "notification_button_option.h" + +#include +#include + +namespace OHOS { +namespace NotificationNapi { +const int32_t SUBSRIBE_MAX_PARA = 2; +const std::string RESPONSE = "onResponse"; + +struct LocalLiveViewReceiveDataWorker { + napi_env env = nullptr; + napi_ref ref = nullptr; + int32_t notificationId; + sptr buttonOption; + LocalLiveViewSubscriberInstance *subscriber = nullptr; +}; + +LocalLiveViewSubscriberInstance::LocalLiveViewSubscriberInstance() +{} + +LocalLiveViewSubscriberInstance::~LocalLiveViewSubscriberInstance() +{ + if (responseCallbackInfo_.ref != nullptr) { + napi_delete_reference(responseCallbackInfo_.env, responseCallbackInfo_.ref); + } +} + +void LocalLiveViewSubscriberInstance::OnDied() +{ + ANS_LOGI("enter"); +} + +void LocalLiveViewSubscriberInstance::OnConnected() +{ + ANS_LOGI("enter"); +} + +void LocalLiveViewSubscriberInstance::OnDisconnected() +{ + ANS_LOGI("enter"); +} + +void UvQueueWorkOnResponse(uv_work_t *work, int status) +{ + ANS_LOGI("OnResponse uv_work_t start"); + + if (work == nullptr) { + ANS_LOGE("work is nullptr"); + return; + } + + auto dataWorkerData = reinterpret_cast(work->data); + if (dataWorkerData == nullptr) { + ANS_LOGD("dataWorkerData is null."); + delete work; + work = nullptr; + return; + } + napi_value buttonOption = nullptr; + napi_value buttonName = nullptr; + napi_handle_scope scope; + napi_value notificationId = nullptr; + napi_open_handle_scope(dataWorkerData->env, &scope); + + // notificationId: number + napi_create_int32(dataWorkerData->env, dataWorkerData->notificationId, ¬ificationId); + + napi_create_object(dataWorkerData->env, &buttonOption); + napi_create_string_utf8(dataWorkerData->env, dataWorkerData->buttonOption->GetButtonName().c_str(), + NAPI_AUTO_LENGTH, &buttonName); + napi_set_named_property(dataWorkerData->env, buttonOption, "buttonName", buttonName); + + Common::SetCallbackArg2(dataWorkerData->env, dataWorkerData->ref, notificationId, buttonOption); + napi_close_handle_scope(dataWorkerData->env, scope); + + delete dataWorkerData; + dataWorkerData = nullptr; + delete work; +} + +void LocalLiveViewSubscriberInstance::OnResponse(int32_t notificationId, sptr buttonOption) +{ + ANS_LOGI("enter"); + + if (responseCallbackInfo_.ref == nullptr) { + ANS_LOGI("response callback unset"); + return; + } + + if (buttonOption == nullptr) { + ANS_LOGE("buttonOption is null"); + return; + } + + ANS_LOGI("OnResponse NotificationId = %{public}d", notificationId); + ANS_LOGI("OnResponse buttonOption size = %{public}s", buttonOption->GetButtonName().c_str()); + + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(responseCallbackInfo_.env, &loop); + if (loop == nullptr) { + ANS_LOGE("loop instance is nullptr"); + return; + } + + LocalLiveViewReceiveDataWorker *dataWorker = new (std::nothrow) LocalLiveViewReceiveDataWorker(); + if (dataWorker == nullptr) { + ANS_LOGE("DataWorker is nullptr."); + return; + } + + dataWorker->notificationId = notificationId; + dataWorker->buttonOption = buttonOption; + dataWorker->env = responseCallbackInfo_.env; + dataWorker->ref = responseCallbackInfo_.ref; + + uv_work_t *work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + ANS_LOGE("new work failed"); + delete dataWorker; + dataWorker = nullptr; + return; + } + + work->data = reinterpret_cast(dataWorker); + + int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {}, + UvQueueWorkOnResponse, uv_qos_user_initiated); + if (ret != 0) { + delete dataWorker; + dataWorker = nullptr; + delete work; + work = nullptr; + } +} + +void LocalLiveViewSubscriberInstance::SetResponseCallbackInfo(const napi_env &env, const napi_ref &ref) +{ + responseCallbackInfo_.env = env; + responseCallbackInfo_.ref = ref; +} + +void LocalLiveViewSubscriberInstance::SetCallbackInfo(const napi_env &env, const std::string &type, const napi_ref &ref) +{ + if (type == RESPONSE) { + SetResponseCallbackInfo(env, ref); + } else { + ANS_LOGW("type is error"); + } +} + +bool HasNotificationSubscriber(const napi_env &env, const napi_value &value, LocalLiveViewSubscriberInstancesInfo &subscriberInfo) +{ + std::lock_guard lock(mutex_); + for (auto vec : subscriberInstances_) { + napi_value callback = nullptr; + napi_get_reference_value(env, vec.ref, &callback); + bool isEquals = false; + napi_strict_equals(env, value, callback, &isEquals); + if (isEquals) { + subscriberInfo = vec; + return true; + } + } + return false; +} + +napi_value GetNotificationSubscriber( + const napi_env &env, const napi_value &value, LocalLiveViewSubscriberInstancesInfo &subscriberInfo) +{ + ANS_LOGI("enter"); + bool hasProperty = false; + napi_valuetype valuetype = napi_undefined; + napi_ref result = nullptr; + + subscriberInfo.subscriber = new (std::nothrow) LocalLiveViewSubscriberInstance(); + if (subscriberInfo.subscriber == nullptr) { + ANS_LOGE("subscriber is null"); + return nullptr; + } + + napi_create_reference(env, value, 1, &subscriberInfo.ref); + + // onResponse? + NAPI_CALL(env, napi_has_named_property(env, value, "onResponse", &hasProperty)); + if (hasProperty) { + napi_value onResponse = nullptr; + napi_get_named_property(env, value, "onResponse", &onResponse); + NAPI_CALL(env, napi_typeof(env, onResponse, &valuetype)); + if (valuetype != napi_function) { + ANS_LOGE("Wrong argument type. Function expected."); + return nullptr; + } + napi_create_reference(env, onResponse, 1, &result); + subscriberInfo.subscriber->SetCallbackInfo(env, RESPONSE, result); + } + + return Common::NapiGetNull(env); +} + +bool AddSubscriberInstancesInfo(const napi_env &env, const LocalLiveViewSubscriberInstancesInfo &subscriberInfo) +{ + ANS_LOGI("enter"); + if (subscriberInfo.ref == nullptr) { + ANS_LOGE("subscriberInfo.ref is null"); + return false; + } + if (subscriberInfo.subscriber == nullptr) { + ANS_LOGE("subscriberInfo.subscriber is null"); + return false; + } + std::lock_guard lock(mutex_); + subscriberInstances_.emplace_back(subscriberInfo); + + return true; +} + +bool DelSubscriberInstancesInfo(const napi_env &env, const LocalLiveViewSubscriberInstance *subscriber) +{ + ANS_LOGI("enter"); + if (subscriber == nullptr) { + ANS_LOGE("subscriber is null"); + return false; + } + + std::lock_guard lock(mutex_); + for (auto it = subscriberInstances_.begin(); it != subscriberInstances_.end(); ++it) { + if ((*it).subscriber == subscriber) { + if ((*it).ref != nullptr) { + napi_delete_reference(env, (*it).ref); + } + DelDeletingSubscriber((*it).subscriber); + delete (*it).subscriber; + (*it).subscriber = nullptr; + subscriberInstances_.erase(it); + return true; + } + } + return false; +} +napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, + LocalLiveViewSubscriberInstance *&subscriber, napi_ref &callback) +{ + ANS_LOGI("enter"); + + size_t argc = SUBSRIBE_MAX_PARA; + napi_value argv[SUBSRIBE_MAX_PARA] = {nullptr}; + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL)); + if (argc < 1) { + ANS_LOGE("Wrong number of arguments"); + return nullptr; + } + + napi_valuetype valuetype = napi_undefined; + + // argv[0]:LocalLiveViewButton + NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type for arg0. LocalLiveViewButton object expected."); + return nullptr; + } + + LocalLiveViewSubscriberInstancesInfo subscriberInstancesInfo; + if (!HasNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo)) { + if (GetNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo) == nullptr) { + ANS_LOGE("LocalLiveViewButton parse failed"); + if (subscriberInstancesInfo.subscriber) { + delete subscriberInstancesInfo.subscriber; + subscriberInstancesInfo.subscriber = nullptr; + } + return nullptr; + } + if (!AddSubscriberInstancesInfo(env, subscriberInstancesInfo)) { + ANS_LOGE("AddSubscriberInstancesInfo add failed"); + if (subscriberInstancesInfo.subscriber) { + delete subscriberInstancesInfo.subscriber; + subscriberInstancesInfo.subscriber = nullptr; + } + return nullptr; + } + } + subscriber = subscriberInstancesInfo.subscriber; + + // argv[1]:callback + if (argc >= SUBSRIBE_MAX_PARA) { + NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype)); + if (valuetype != napi_function) { + ANS_LOGE("Callback is not function enforce promise."); + return Common::NapiGetNull(env); + } + napi_create_reference(env, argv[PARAM1], 1, &callback); + } + + return Common::NapiGetNull(env); +} + +bool AddDeletingSubscriber(LocalLiveViewSubscriberInstance *subscriber) +{ + std::lock_guard lock(delMutex_); + auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber); + if (iter != DeletingSubscriber.end()) { + return false; + } + + DeletingSubscriber.push_back(subscriber); + return true; +} + +void DelDeletingSubscriber(LocalLiveViewSubscriberInstance *subscriber) +{ + std::lock_guard lock(delMutex_); + auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber); + if (iter != DeletingSubscriber.end()) { + DeletingSubscriber.erase(iter); + } +} + +} // namespace NotificationNapi +} // namespace OHOS diff --git a/frameworks/js/napi/src/manager/napi_local_live_view.cpp b/frameworks/js/napi/src/manager/napi_local_live_view.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7110e2c472764542677d9322f85983ffdcd0e35c --- /dev/null +++ b/frameworks/js/napi/src/manager/napi_local_live_view.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2022-2023 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 "napi_local_live_view.h" + #include "local_live_view_subscribe.h" + #include "ans_inner_errors.h" + #include "common.h" + +namespace OHOS { +namespace NotificationNapi { +//const int32_t SUBSRIBE_MAX_PARA = 1; +const int32_t TRIGGER_PARA = 3; + +napi_value NapiSubscriteLocalAcitvity(napi_env env, napi_callback_info info) +{ + ANS_LOGI("enter"); + napi_ref callback = nullptr; + LocalLiveViewSubscriberInstance *objectInfo = nullptr; + if (ParseParameters(env, info, objectInfo, callback) == nullptr) { + if (objectInfo) { + delete objectInfo; + objectInfo = nullptr; + } + Common::NapiThrow(env, ERROR_PARAM_INVALID); + return Common::NapiGetUndefined(env); + } + + AsyncCallbackInfoSubscribeLocalLiveView *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoSubscribeLocalLiveView { + .env = env, .asyncWork = nullptr, .objectInfo = objectInfo + }; + if (!asynccallbackinfo) { + if (objectInfo) { + delete objectInfo; + objectInfo = nullptr; + } + return Common::JSParaError(env, callback); + } + napi_value promise = nullptr; + Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise); + + napi_value resourceName = nullptr; + napi_create_string_latin1(env, "subscribeLocalLiveViewNotification", NAPI_AUTO_LENGTH, &resourceName); + // Asynchronous function call + napi_create_async_work(env, + nullptr, + resourceName, + [](napi_env env, void *data) { + ANS_LOGI("NapiSubscribeLocalLiveView work excute."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + + asynccallbackinfo->info.errorCode = + NotificationHelper::SubscribeLocalLiveViewNotification(*(asynccallbackinfo->objectInfo)); + + }, + [](napi_env env, napi_status status, void *data) { + ANS_LOGI("NapiSubscribeLocalLiveView work complete."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + if (asynccallbackinfo) { + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + ANS_LOGD("NapiSubscribeLocalLiveView work complete end."); + }, + (void *)asynccallbackinfo, + &asynccallbackinfo->asyncWork); + + bool isCallback = asynccallbackinfo->info.isCallback; + napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated); + if (status != napi_ok) { + ANS_LOGE("Queue napiSubscribeLocalLiveView work failed return: %{public}d", status); + asynccallbackinfo->info.errorCode = ERROR_INTERNAL_ERROR; + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + + if (isCallback) { + ANS_LOGD("napiSubscribeLocalLiveView callback is nullptr."); + return Common::NapiGetNull(env); + } else { + return promise; + } +} + +napi_value NapiUnsubscriteLocalLiveView(napi_env env, napi_callback_info info) +{ + return nullptr; +} + +napi_value ParseTriggerParameters(const napi_env &env, const napi_callback_info &info, + AsyncCallbackInfoSubscribeLocalLiveView *asynccallbackinfo, napi_ref &callback) +{ + ANS_LOGI("enter"); + + size_t argc = TRIGGER_PARA; + napi_value argv[TRIGGER_PARA] = {nullptr, nullptr}; + napi_value thisVar = nullptr; + + int32_t notificationId = -1; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL)); + if (argc != TRIGGER_PARA) { + ANS_LOGE("Wrong number of arguments"); + return nullptr; + } + + napi_valuetype valuetype = napi_undefined; + + // argv[0]:BundleOption + auto retValue = Common::GetBundleOption(env, argv[PARAM0], asynccallbackinfo->bundleOption); + if (retValue == nullptr) { + ANS_LOGE("GetBundleOption failed"); + return nullptr; + } + + // argv[1]:notificationId + NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, argv[PARAM1], ¬ificationId); + ANS_LOGI("notificationId = %{public}d", notificationId); + asynccallbackinfo->notificationId = notificationId; + + // argv[2]:buttonOption + retValue = Common::GetButtonOption(env, argv[PARAM2], asynccallbackinfo->buttonOption); + if (retValue == nullptr) { + ANS_LOGE("GetButtonOption failed"); + return nullptr; + } + return Common::NapiGetNull(env); +} + +napi_value NapiTriggerLocalLiveView(napi_env env, napi_callback_info info) +{ + ANS_LOGI("enter"); + napi_ref callback = nullptr; + + AsyncCallbackInfoSubscribeLocalLiveView *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoSubscribeLocalLiveView { + .env = env, .asyncWork = nullptr, + }; + if (!asynccallbackinfo) { + return Common::JSParaError(env, callback); + } + + if (ParseTriggerParameters(env, info, asynccallbackinfo, callback) == nullptr) { + Common::NapiThrow(env, ERROR_PARAM_INVALID); + return Common::NapiGetUndefined(env); + } + + napi_value promise = nullptr; + Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise); + + napi_value resourceName = nullptr; + napi_create_string_latin1(env, "triggerLocalLiveView", NAPI_AUTO_LENGTH, &resourceName); + // Asynchronous function call + napi_create_async_work(env, + nullptr, + resourceName, + [](napi_env env, void *data) { + ANS_LOGI("NapiTriggerLocalLiveView work excute."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + + asynccallbackinfo->info.errorCode = + NotificationHelper::TriggerLocalLiveView(asynccallbackinfo->bundleOption, + asynccallbackinfo->notificationId, asynccallbackinfo->buttonOption); + + }, + [](napi_env env, napi_status status, void *data) { + ANS_LOGI("NapiSubscribeLocalLiveView work complete."); + if (!data) { + ANS_LOGE("Invalid asynccallbackinfo!"); + return; + } + auto asynccallbackinfo = reinterpret_cast(data); + if (asynccallbackinfo) { + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + ANS_LOGD("NapiSubscribeLocalLiveView work complete end."); + }, + (void *)asynccallbackinfo, + &asynccallbackinfo->asyncWork); + + bool isCallback = asynccallbackinfo->info.isCallback; + napi_status status = napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated); + if (status != napi_ok) { + ANS_LOGE("Queue napiSubscribeLocalLiveView work failed return: %{public}d", status); + asynccallbackinfo->info.errorCode = ERROR_INTERNAL_ERROR; + Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env)); + if (asynccallbackinfo->info.callback != nullptr) { + ANS_LOGD("Delete napiSubscribeLocalLiveView callback reference."); + napi_delete_reference(env, asynccallbackinfo->info.callback); + } + napi_delete_async_work(env, asynccallbackinfo->asyncWork); + delete asynccallbackinfo; + asynccallbackinfo = nullptr; + } + + if (isCallback) { + ANS_LOGD("napiSubscribeLocalLiveView callback is nullptr."); + return Common::NapiGetNull(env); + } else { + return promise; + } +} + +} // namespace NotificationNapi +} // namespace OHOS 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 a836f95b8884300dc647204c5bfb65723a298615..79eff3d7a1bbc0075048fa91099ae4b0281396fb 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 6d47e9660d82571d9e1fec4fae60f45008075306..be5ba6083b8e9ba7373244a6595e3ef66bec4e62 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 e571129316485559869f735a63f1cf45a0df169b..72ff531054978438af46726899b7689ac05875bb 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" @@ -1515,6 +1516,42 @@ 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) { @@ -2673,6 +2710,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