* Copyright (c) 2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "notification_shell_command.h"
#include <getopt.h>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <string>
#include <cstdint>
#include <memory>
#include "ans_const_define.h"
#include "ans_inner_errors.h"
#include "command_output.h"
#include "nativetoken_kit.h"
#include "notification_bundle_option.h"
#include "notification.h"
#include "notification_request.h"
#include "notification_content.h"
#include "notification_normal_content.h"
#include "notification_long_text_content.h"
#include "notification_multiline_content.h"
#include "notification_picture_content.h"
#include "notification_conversational_content.h"
#include "notification_conversational_message.h"
#include "message_user.h"
#include "notification_media_content.h"
#include "notification_live_view_content.h"
#include "notification_local_live_view_content.h"
#include "notification_action_button.h"
#include "notification_flags.h"
#include "notification_constant.h"
#include "notification_helper.h"
#include "want_params.h"
#include "want_params_wrapper.h"
#include "token_setproc.h"
using json = nlohmann::json;
namespace OHOS {
namespace Notification {
namespace {
constexpr size_t MAX_LABEL_LEN = 204;
constexpr size_t MAX_TITLE_LEN = 1024;
constexpr size_t MAX_CONTENT_TEXT_LEN = 3072;
constexpr uint32_t MAX_SLOT_FLAGS = 0b111111;
constexpr const char* PERM_CONTROLLER = "ohos.permission.NOTIFICATION_CONTROLLER";
constexpr const char* PERM_CONTROLLER_AND_AGENT =
"ohos.permission.NOTIFICATION_CONTROLLER 和 ohos.permission.NOTIFICATION_AGENT_CONTROLLER";
std::string TruncateString(const std::string &str, size_t maxLen)
{
return str.size() > maxLen ? str.substr(0, maxLen) : str;
}
constexpr char SHORT_OPTIONS_PUBLISH[] = "h";
const struct option LONG_OPTIONS_PUBLISH[] = {
{"notificationId", required_argument, nullptr, 1},
{"notificationContent", required_argument, nullptr, 2},
{"slotType", required_argument, nullptr, 3},
{"label", required_argument, nullptr, 4},
{"groupName", required_argument, nullptr, 5},
{"badgeNumber", required_argument, nullptr, 6},
{"updateOnly", no_argument, nullptr, 7},
{"appMessageId", required_argument, nullptr, 8},
{"priorityNotificationType", required_argument, nullptr, 9},
{"alertOneTime", no_argument, nullptr, 10},
{"sound", required_argument, nullptr, 11},
{"autoDeletedTime", required_argument, nullptr, 12},
{"notificationFlags", required_argument, nullptr, 13},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
constexpr char SHORT_OPTIONS_CANCEL_BY_ID[] = "o:i:h";
const struct option LONG_OPTIONS_CANCEL_BY_ID[] = {
{"bundleOption", required_argument, nullptr, 'o'},
{"notificationId", required_argument, nullptr, 'i'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
constexpr char SHORT_OPTIONS_ENABLE_NOTIFICATION[] = "o:e:h";
const struct option LONG_OPTIONS_ENABLE_NOTIFICATION[] = {
{"bundleOption", required_argument, nullptr, 'o'},
{"enabled", no_argument, nullptr, 'e'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
constexpr char SHORT_OPTIONS_SET_SLOT_FLAGS[] = "o:f:h";
const struct option LONG_OPTIONS_SET_SLOT_FLAGS[] = {
{"bundleOption", required_argument, nullptr, 'o'},
{"flags", required_argument, nullptr, 'f'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
constexpr char SHORT_OPTIONS_BATCH_CANCEL[] = "a:h";
const struct option LONG_OPTIONS_BATCH_CANCEL[] = {
{"hashcodes", required_argument, nullptr, 'a'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
constexpr char SHORT_OPTIONS_LIST_ALL_NOTIFICATION[] = "h";
const struct option LONG_OPTIONS_LIST_ALL_NOTIFICATION[] = {
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
constexpr char SHORT_OPTIONS_CANCEL_BY_BUNDLE[] = "o:h";
const struct option LONG_OPTIONS_CANCEL_BY_BUNDLE[] = {
{"bundleOption", required_argument, nullptr, 'o'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
constexpr char HELP_MSG[] =
"ohos-notificationManager - OpenHarmony 通知管理工具。用于通知的发布、取消、移除及查询活跃通知,"
"不支持通知订阅及交互式UI操作。\n"
"\n"
"Usage:\n"
" ohos-notificationManager <command> [options]\n"
"\n"
"Parameters:\n"
" --help 显示帮助信息\n"
"\n"
"SubCommands:\n"
" help 显示帮助信息\n"
" publish 发布通知到系统\n"
" cancelById 按bundle和通知ID取消通知\n"
" cancelByBundle 取消指定bundle的所有通知\n"
" batchCancel 按哈希码批量取消通知\n"
" enableNotification 设置bundle的通知启用/禁用状态\n"
" setSlotFlags 设置bundle的通知渠道标志\n"
" listAllNotification 列出所有活跃通知\n"
"\n"
"Examples:\n"
" ohos-notificationManager --help\n"
" ohos-notificationManager publish --help\n";
constexpr char PUBLISH_HELP_MSG[] =
"ohos-notificationManager publish - 发布通知。用于向系统发送通知,不支持订阅类通知。\n"
"\n"
"Usage:\n"
" ohos-notificationManager publish --notificationContent <json> [options]\n"
"\n"
"Parameters:\n"
" --notificationContent <json> 通知内容JSON字符串(必填)\n"
" 所有类型公共必填: title(≤1024B), text(≤3072B)\n"
" 公共可选: additionalText(≤3072B);所有属性超长截取\n"
" type仅支持basic、long_text、multiline:\n"
" basic示例: {\"type\":\"basic\",\"title\":\"通知标题\",\"text\":\"通知内容\",\"additionalText\":\"附加文本\"}\n"
" long_text: longText(≤3072B)、expandedTitle(≤1024B)、briefText(≤1024B),超长截取\n"
" 示例: {\"type\":\"long_text\",\"title\":\"通知标题\",\"text\":\"短内容\",\"longText\":\"长文本内容\","
"\"expandedTitle\":\"展开标题\",\"briefText\":\"摘要\",\"additionalText\":\"附加文本\"}\n"
" multiline: expandedTitle(≤1024B)、briefText(≤1024B)、lines(≤3个元素,每个≤1024B),超长截取\n"
" 示例: {\"type\":\"multiline\",\"title\":\"通知标题\",\"text\":\"通知内容\","
"\"expandedTitle\":\"展开标题\",\"briefText\":\"摘要\",\"lines\":[\"第一行\",\"第二行\",\"第三行\"],\"additionalText\":\"附加文本\"}\n"
" --notificationId <id> 通知ID(可选,默认: 0)\n"
" --slotType <type> 通知渠道类型(可选,默认: 3)\n"
" 0=社交通信, 1=服务提醒, 2=内容信息, 3=其他, 6=客服消息\n"
" 不支持4=自定义、5=实况通知、7=紧急信息\n"
" --updateOnly 仅更新已存在的通知,不创建新通知(可选,标志)\n"
" --appMessageId <id> 应用消息ID,用于标识特定消息(可选)\n"
" --priorityNotificationType <type> 优先级通知类型(可选)\n"
" 枚举值: OTHER(非优先级通知)、PRIMARY_CONTACT(重要联系人)、AT_ME(有人@我)、"
"URGENT_MESSAGE(紧急消息)、SCHEDULE_REMINDER(日程提醒)\n"
" --alertOneTime 仅提醒一次,后续更新不再提醒(可选,标志)\n"
" --sound <uri> 自定义通知声音URI(可选)\n"
" --badgeNumber <number> 通知角标增加数量(可选,必须>=0)\n"
" --autoDeletedTime <ms> 自动删除时间(毫秒,可选)\n"
" --label <label> 通知标签(可选,不超过204字节)\n"
" --groupName <name> 通知分组名称(可选,不超过204字节,超长截取)\n"
" --notificationFlags <json> 通知提醒标志JSON字符串(可选)\n"
" 支持字段: soundEnabled(声音)、vibrationEnabled(振动)、bannerEnabled(横幅)、lockScreenEnabled(锁屏)\n"
" 值枚举: 2=CLOSE(关闭)。示例: {\"soundEnabled\":2,\"vibrationEnabled\":2}\n"
" --help 显示帮助信息\n"
"\n"
"Examples:\n"
" # 发布基础通知\n"
" ohos-notificationManager publish --notificationContent \"{\\\"type\\\":\\\"basic\\\",\\\"title\\\":\\\"Test\\\",\\\"text\\\":\\\"Hello\\\"}\"\n"
" # 指定渠道类型发布\n"
" ohos-notificationManager publish --notificationContent \"{\\\"type\\\":\\\"basic\\\",\\\"title\\\":\\\"Alert\\\",\\\"text\\\":\\\"Content\\\"}\" --slotType 1\n";
constexpr char CANCEL_BY_ID_HELP_MSG[] =
"ohos-notificationManager cancelById - 按bundle和通知ID取消通知。用于管理指定应用的通知,"
"不支持无bundle信息的取消。\n"
"\n"
"Usage:\n"
" ohos-notificationManager cancelById --bundleOption <json> --notificationId <id>\n"
"\n"
"Parameters:\n"
" --bundleOption <json> 目标应用信息JSON字符串(必填),包含bundleName(应用包名)和uid(应用UID)两个属性\n"
" 示例: \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"\n"
" --notificationId <id> 待取消的通知ID(必填,整数)\n"
" --help 显示帮助信息\n"
"\n"
"Examples:\n"
" # 按bundle取消通知\n"
" ohos-notificationManager cancelById --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --notificationId 1\n";
constexpr char BATCH_CANCEL_HELP_MSG[] =
"ohos-notificationManager batchCancel - 按哈希码批量取消通知。用于取消由哈希码标识的指定通知。\n"
"\n"
"Usage:\n"
" ohos-notificationManager batchCancel --hashcodes <json>\n"
"\n"
"Parameters:\n"
" --hashcodes <json> 通知哈希码JSON数组字符串(必填),指定要移除的通知列表\n"
" 示例: [\"hash1\",\"hash2\",\"hash3\"]\n"
" --help 显示帮助信息\n"
"\n"
"Examples:\n"
" # 按哈希码批量取消通知\n"
" ohos-notificationManager batchCancel --hashcodes \"[\\\"hash1\\\",\\\"hash2\\\"]\"\n";
constexpr char CANCEL_BY_BUNDLE_HELP_MSG[] =
"ohos-notificationManager cancelByBundle - 取消指定bundle的所有通知。用于批量取消指定应用的通知。\n"
"\n"
"Usage:\n"
" ohos-notificationManager cancelByBundle --bundleOption <json>\n"
"\n"
"Parameters:\n"
" --bundleOption <json> 目标应用信息JSON字符串(必填),包含bundleName(应用包名)和uid(应用UID)两个属性\n"
" 示例: \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"\n"
" --help 显示帮助信息\n"
"\n"
"Examples:\n"
" # 取消指定bundle的所有通知\n"
" ohos-notificationManager cancelByBundle --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"";
constexpr char ENABLE_NOTIFICATION_HELP_MSG[] =
"ohos-notificationManager enableNotification - 设置bundle的通知启用/禁用状态。"
"用于控制应用的通知权限,不支持无bundle信息的设置。\n"
"\n"
"Usage:\n"
" ohos-notificationManager enableNotification --bundleOption <json> --enabled <true|false>\n"
"\n"
"Parameters:\n"
" --bundleOption <json> 目标应用信息JSON字符串(必填),包含bundleName(应用包名)和uid(应用UID)两个属性\n"
" 示例: \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"\n"
" --enabled <true|false> 通知开关状态(必填,true=启用, false=禁用)\n"
" --help 显示帮助信息\n"
"\n"
"Examples:\n"
" # 启用bundle的通知\n"
" ohos-notificationManager enableNotification --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --enabled true\n"
" # 禁用bundle的通知\n"
" ohos-notificationManager enableNotification --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --enabled false\n";
constexpr char SET_SLOT_FLAGS_HELP_MSG[] =
"ohos-notificationManager setSlotFlags - 设置bundle的通知渠道标志。"
"用于配置应用的通知提醒方式,不支持无bundle信息的设置。\n"
"\n"
"Usage:\n"
" ohos-notificationManager setSlotFlags --bundleOption <json> --flags <flags>\n"
"\n"
"Parameters:\n"
" --bundleOption <json> 目标应用信息JSON字符串(必填),包含bundleName(应用包名)和uid(应用UID)两个属性\n"
" 示例: \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"\n"
" --flags <flags> 渠道标志位掩码(必填,uint32,十进制或0x前缀十六进制)\n"
" 仅bit0-bit5有效:\n"
" bit0=声音, bit1=锁屏, bit2=横幅, bit3=亮屏, bit4=振动, bit5=状态栏图标\n"
" 必须>=0且不能大于0b111111(63)\n"
" 注意: 亮屏(bit3)和状态栏图标(bit5)设置关闭不会生效,服务端会强制保持开启\n"
" --help 显示帮助信息\n"
"\n"
"Examples:\n"
" # 设置所有提醒标志\n"
" ohos-notificationManager setSlotFlags --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --flags 63\n"
" # 使用十六进制格式设置标志\n"
" ohos-notificationManager setSlotFlags --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --flags 0x3F\n";
constexpr char LIST_ALL_NOTIFICATION_HELP_MSG[] =
"ohos-notificationManager listAllNotification - 列出所有活跃通知。"
"用于查询当前通知状态,不支持查询其他用户的通知。\n"
"\n"
"每条通知输出字段:\n"
" notificationId 通知ID\n"
" createTime 通知创建时间(毫秒时间戳)\n"
" ownerUid 通知创建者UID\n"
" ownerUserId 通知创建者UserId\n"
" ownerBundleName 通知创建者包名\n"
" label 通知标签\n"
" appInstanceKey 应用实例Key\n"
" slotType 渠道类型值\n"
" notificationContent 通知内容对象(按type字段区分不同类型):\n"
" 公共字段: type(类型名)、title(标题)、text(文本)、additionalText(附加文本,可选)\n"
" basic: 仅公共字段\n"
" long_text: +longText(长文本)、expandedTitle(展开标题)、briefText(摘要)\n"
" multiline: +expandedTitle(展开标题)、briefText(摘要)、lines(行文本数组)\n"
" picture: +expandedTitle(展开标题)、briefText(摘要)\n"
" conversation: +conversationTitle(会话标题)、isGroup(是否群聊)、messages(消息数组)\n"
" media: +shownActions(展示按钮序号数组)\n"
" live_view: +liveViewStatus(实况状态)、version(版本号)\n"
" local_live_view: +liveViewType(实况类型)\n"
" actionButtons 操作按钮列表(title)\n"
" notificationFlags 通知提醒标志(soundEnabled/vibrationEnabled/bannerEnabled/lockScreenEnabled)\n"
" hashCode 通知哈希码\n"
"\n"
"Parameters:\n"
" --help 显示帮助信息\n"
"\n"
"Examples:\n"
" # 列出所有活跃通知\n"
" ohos-notificationManager listAllNotification\n";
}
NotificationShellCommand::NotificationShellCommand(int argc, char *argv[]) : ShellCommand(argc, argv, "ohos-notificationManager")
{}
ErrCode NotificationShellCommand::CreateCommandMap()
{
commandMap_ = {
{"help", std::bind(&NotificationShellCommand::RunAsHelpCommand, this)},
{"publish", std::bind(&NotificationShellCommand::RunAsPublishCommand, this)},
{"cancelById", std::bind(&NotificationShellCommand::RunAsCancelByIdCommand, this)},
{"cancelByBundle", std::bind(&NotificationShellCommand::RunAsCancelByBundleCommand, this)},
{"batchCancel", std::bind(&NotificationShellCommand::RunAsBatchCancelCommand, this)},
{"enableNotification", std::bind(&NotificationShellCommand::RunAsEnableNotificationCommand, this)},
{"setSlotFlags", std::bind(&NotificationShellCommand::RunAsSetSlotFlagsCommand, this)},
{"listAllNotification", std::bind(&NotificationShellCommand::RunAsListAllNotificationCommand, this)},
};
return ERR_OK;
}
ErrCode NotificationShellCommand::Init()
{
ErrCode result = OHOS::ERR_OK;
if (!ans_) {
ans_ = AnsNotification::GetInstance();
}
if (!ans_) {
result = OHOS::ERR_INVALID_VALUE;
}
return result;
}
ErrCode NotificationShellCommand::RunAsHelpCommand()
{
if (!argList_.empty()) {
std::string subCmd = argList_[0];
if (subCmd == "publish") {
resultReceiver_.append(PUBLISH_HELP_MSG);
return ERR_OK;
} else if (subCmd == "cancelById") {
resultReceiver_.append(CANCEL_BY_ID_HELP_MSG);
return ERR_OK;
} else if (subCmd == "batchCancel") {
resultReceiver_.append(BATCH_CANCEL_HELP_MSG);
return ERR_OK;
} else if (subCmd == "cancelByBundle") {
resultReceiver_.append(CANCEL_BY_BUNDLE_HELP_MSG);
return ERR_OK;
} else if (subCmd == "enableNotification") {
resultReceiver_.append(ENABLE_NOTIFICATION_HELP_MSG);
return ERR_OK;
} else if (subCmd == "setSlotFlags") {
resultReceiver_.append(SET_SLOT_FLAGS_HELP_MSG);
return ERR_OK;
} else if (subCmd == "listAllNotification") {
resultReceiver_.append(LIST_ALL_NOTIFICATION_HELP_MSG);
return ERR_OK;
}
}
resultReceiver_.append(HELP_MSG);
return ERR_OK;
}
ErrCode NotificationShellCommand::ParseBundleOption(const std::string &jsonStr,
NotificationBundleOption &bundleOption)
{
std::string bundleName;
int32_t uid = -1;
if (!jsonStr.empty()) {
if (!json::accept(jsonStr)) {
OutputError("ERR_ARG_INVALID", "bundleOption参数解析失败: JSON格式无效",
"请提供有效的JSON字符串。示例: --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
auto bundleOptionJson = json::parse(jsonStr);
if (!bundleOptionJson.is_object()) {
OutputError("ERR_ARG_INVALID", "bundleOption必须是JSON对象",
"请提供JSON对象格式。示例: --bundleOption "
"\"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
if (bundleOptionJson.contains("bundleName") && bundleOptionJson["bundleName"].is_string()) {
bundleName = bundleOptionJson["bundleName"].get<std::string>();
}
if (bundleOptionJson.contains("uid") && bundleOptionJson["uid"].is_number_integer()) {
uid = bundleOptionJson["uid"].get<int32_t>();
}
}
if (bundleName.empty()) {
OutputError("ERR_ARG_MISSING", "bundleOption中bundleName缺失: 必须提供目标应用包名",
"请提供包含bundleName的JSON参数。示例: --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
if (uid < 0) {
OutputError("ERR_ARG_MISSING", "bundleOption中uid缺失或无效: 必须提供有效的应用UID",
"请提供包含uid的JSON参数。示例: --bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
bundleOption = NotificationBundleOption(bundleName, uid);
return ERR_OK;
}
ErrCode NotificationShellCommand::ParsePublishOptions(PublishOptions &opts)
{
optind = 0;
int option = getopt_long(argc_, argv_, SHORT_OPTIONS_PUBLISH, LONG_OPTIONS_PUBLISH, nullptr);
while (option != -1) {
switch (option) {
case 'h':
resultReceiver_.append(PUBLISH_HELP_MSG);
opts.helpRequested = true;
return ERR_OK;
case 1: opts.notificationId = atoi(optarg); break;
case 2: opts.contentJson = optarg; break;
case 3: opts.slotType = atoi(optarg); break;
case 4: opts.label = optarg; break;
case 5: opts.groupName = optarg; break;
case 6: opts.badgeNumber = static_cast<uint32_t>(atoi(optarg)); break;
case 7: opts.isUpdateOnly = true; break;
case 8: opts.appMessageId = optarg; break;
case 9: opts.priorityNotificationType = optarg; break;
case 10: opts.isAlertOneTime = true; break;
case 11: opts.sound = optarg; break;
case 12: opts.autoDeletedTime = static_cast<int64_t>(atoll(optarg)); break;
case 13: opts.flagsStr = optarg; break;
default:
OutputError("ERR_UNKNOWN_OPTION", "未知选项: publish命令不支持该选项",
"请使用 --help 查看可用选项。示例: ohos-notificationManager publish --help", resultReceiver_);
return ERR_INVALID_VALUE;
}
option = getopt_long(argc_, argv_, SHORT_OPTIONS_PUBLISH, LONG_OPTIONS_PUBLISH, nullptr);
}
return ERR_OK;
}
ErrCode NotificationShellCommand::ValidatePublishRequiredOptions(const PublishOptions &opts)
{
if (opts.contentJson.empty()) {
OutputError("ERR_ARG_MISSING", "通知内容(--notificationContent)缺失: 必须提供通知内容JSON",
"请提供通知内容参数。示例: ohos-notificationManager publish --notificationId 1 "
"--notificationContent \"{\\\"type\\\":\\\"basic\\\",\\\"title\\\":\\\"Test\\\",\\\"text\\\":\\\"Hello\\\"}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
if (opts.slotType < 0 || opts.slotType > 7 || opts.slotType == 4 || opts.slotType == 5 || opts.slotType == 7) {
OutputError("ERR_ARG_INVALID",
"渠道类型无效: 渠道类型必须在 0-7 范围内且不支持 4(CUSTOM)、5(LIVE_VIEW)、7(EMERGENCY_INFORMATION)",
"请使用有效的渠道类型值。示例: --slotType 3(OTHER类型)或 --slotType 6(CUSTOMER_SERVICE类型)",
resultReceiver_);
return ERR_INVALID_VALUE;
}
if (opts.badgeNumber > 0x7FFFFFFFu) {
OutputError("ERR_ARG_INVALID", "badgeNumber参数值无效: 必须为非负整数",
"请使用有效的非负整数。示例: --badgeNumber 1", resultReceiver_);
return ERR_INVALID_VALUE;
}
return ERR_OK;
}
void NotificationShellCommand::ApplySimplePublishFields(const PublishOptions &opts,
NotificationRequest &request)
{
if (opts.isUpdateOnly) {
request.SetUpdateOnly(true);
}
if (!opts.appMessageId.empty()) {
request.SetAppMessageId(opts.appMessageId);
}
if (!opts.priorityNotificationType.empty()) {
request.SetPriorityNotificationType(opts.priorityNotificationType);
}
if (opts.isAlertOneTime) {
request.SetAlertOneTime(true);
}
if (!opts.sound.empty()) {
request.SetSound(opts.sound);
}
if (opts.badgeNumber > 0) {
request.SetBadgeNumber(opts.badgeNumber);
}
if (opts.autoDeletedTime >= 0) {
request.SetAutoDeletedTime(opts.autoDeletedTime);
}
if (!opts.label.empty()) {
request.SetLabel(TruncateString(opts.label, MAX_LABEL_LEN));
}
if (!opts.groupName.empty()) {
request.SetGroupName(TruncateString(opts.groupName, MAX_LABEL_LEN));
}
}
ErrCode NotificationShellCommand::RunAsPublishCommand()
{
if (ans_ == nullptr) {
OutputApiError(ERR_ANS_SERVICE_NOT_CONNECTED, "发布通知", "", "", resultReceiver_);
return ERR_ANS_SERVICE_NOT_CONNECTED;
}
PublishOptions opts;
ErrCode ret = ParsePublishOptions(opts);
if (ret != ERR_OK) {
return ret;
}
if (opts.helpRequested) {
return ERR_OK;
}
ret = ValidatePublishRequiredOptions(opts);
if (ret != ERR_OK) {
return ret;
}
NotificationRequest request(opts.notificationId);
ret = ApplyPublishOptions(opts, request);
if (ret != ERR_OK) {
return ret;
}
ret = NotificationHelper::PublishNotification(request);
if (ret == ERR_OK) {
json data;
OutputSuccess(data, resultReceiver_);
return ERR_OK;
}
OutputApiError(ret, "发布通知",
"示例: ohos-notificationManager publish --notificationId 1 "
"--notificationContent \"{\\\"type\\\":\\\"basic\\\",\\\"title\\\":\\\"Test\\\",\\\"text\\\":\\\"Hello\\\"}\"",
"", resultReceiver_);
return ret;
}
ErrCode NotificationShellCommand::BuildNotificationContent(const std::string &contentJson,
NotificationRequest &request)
{
if (!json::accept(contentJson)) {
OutputError("ERR_ARG_INVALID", "通知内容JSON解析失败: JSON格式无效",
"请提供有效的JSON格式。示例: --notificationContent "
"\"{\\\"type\\\":\\\"basic\\\",\\\"title\\\":\\\"T\\\",\\\"text\\\":\\\"X\\\"}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
json contentObj = json::parse(contentJson, nullptr, false);
if (contentObj.is_discarded() || !contentObj.is_object()) {
OutputError("ERR_ARG_INVALID", "通知内容JSON解析失败: JSON不是有效对象",
"请提供有效的JSON对象。示例: --notificationContent "
"\"{\\\"type\\\":\\\"basic\\\",\\\"title\\\":\\\"T\\\",\\\"text\\\":\\\"X\\\"}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
std::string contentType;
if (contentObj.contains("type") && contentObj["type"].is_string()) {
contentType = contentObj["type"].get<std::string>();
}
if (contentType.empty()) {
OutputError("ERR_ARG_MISSING", "通知内容中 type 不能为空",
"请在 --notificationContent JSON中包含 type 字段(basic/long_text/multiline)", resultReceiver_);
return ERR_INVALID_VALUE;
}
std::string cTitle;
if (contentObj.contains("title") && contentObj["title"].is_string()) {
cTitle = TruncateString(contentObj["title"].get<std::string>(), MAX_TITLE_LEN);
}
if (cTitle.empty()) {
OutputError("ERR_ARG_INVALID", "通知内容中 title 不能为空",
"请在 --notificationContent JSON中包含 title 字段", resultReceiver_);
return ERR_INVALID_VALUE;
}
std::string cText;
if (contentObj.contains("text") && contentObj["text"].is_string()) {
cText = TruncateString(contentObj["text"].get<std::string>(), MAX_CONTENT_TEXT_LEN);
}
if (cText.empty()) {
OutputError("ERR_ARG_INVALID", "通知内容中 text 不能为空",
"请在 --notificationContent JSON中包含 text 字段", resultReceiver_);
return ERR_INVALID_VALUE;
}
std::string cAdditionalText;
if (contentObj.contains("additionalText") && contentObj["additionalText"].is_string()) {
cAdditionalText = TruncateString(contentObj["additionalText"].get<std::string>(), MAX_CONTENT_TEXT_LEN);
}
if (contentType == "basic") {
BuildBasicContent(cTitle, cText, cAdditionalText, request);
return ERR_OK;
}
if (contentType == "long_text") {
return BuildLongTextContent(contentObj, cTitle, cText, cAdditionalText, request);
}
if (contentType == "multiline") {
return BuildMultilineContent(contentObj, cTitle, cText, cAdditionalText, request);
}
OutputError("ERR_ARG_INVALID",
"通知内容类型 " + contentType + " 不支持: 仅支持 basic、long_text、multiline",
"请使用有效的内容类型。示例: --notificationContent "
"\"{\\\"type\\\":\\\"basic\\\",\\\"title\\\":\\\"T\\\",\\\"text\\\":\\\"X\\\"}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
void NotificationShellCommand::BuildBasicContent(const std::string &cTitle,
const std::string &cText, const std::string &cAdditionalText, NotificationRequest &request)
{
auto normalContent = std::make_shared<NotificationNormalContent>();
normalContent->SetTitle(cTitle);
normalContent->SetText(cText);
normalContent->SetContentType(static_cast<int32_t>(NotificationContent::Type::BASIC_TEXT));
if (!cAdditionalText.empty()) {
normalContent->SetAdditionalText(cAdditionalText);
}
auto content = std::make_shared<NotificationContent>(normalContent);
request.SetContent(content);
}
ErrCode NotificationShellCommand::BuildLongTextContent(const json &contentObj,
const std::string &cTitle, const std::string &cText,
const std::string &cAdditionalText, NotificationRequest &request)
{
if (!contentObj.contains("longText") || !contentObj["longText"].is_string()
|| contentObj["longText"].get<std::string>().empty()) {
OutputError("ERR_ARG_INVALID", "long_text类型通知内容中 longText 不能为空",
"请在 --notificationContent JSON中包含 longText 字段", resultReceiver_);
return ERR_INVALID_VALUE;
}
if (!contentObj.contains("briefText") || !contentObj["briefText"].is_string()
|| contentObj["briefText"].get<std::string>().empty()) {
OutputError("ERR_ARG_INVALID", "long_text类型通知内容中 briefText 不能为空",
"请在 --notificationContent JSON中包含 briefText 字段", resultReceiver_);
return ERR_INVALID_VALUE;
}
if (!contentObj.contains("expandedTitle") || !contentObj["expandedTitle"].is_string()
|| contentObj["expandedTitle"].get<std::string>().empty()) {
OutputError("ERR_ARG_INVALID", "long_text类型通知内容中 expandedTitle 不能为空",
"请在 --notificationContent JSON中包含 expandedTitle 字段", resultReceiver_);
return ERR_INVALID_VALUE;
}
std::string longText = TruncateString(contentObj["longText"].get<std::string>(), MAX_CONTENT_TEXT_LEN);
std::string expandedTitle = TruncateString(contentObj["expandedTitle"].get<std::string>(), MAX_TITLE_LEN);
std::string briefText = TruncateString(contentObj["briefText"].get<std::string>(), MAX_TITLE_LEN);
auto longContent = std::make_shared<NotificationLongTextContent>();
longContent->SetTitle(cTitle);
longContent->SetText(cText);
longContent->SetContentType(static_cast<int32_t>(NotificationContent::Type::LONG_TEXT));
longContent->SetLongText(longText);
longContent->SetExpandedTitle(expandedTitle);
longContent->SetBriefText(briefText);
if (!cAdditionalText.empty()) {
longContent->SetAdditionalText(cAdditionalText);
}
request.SetContent(std::make_shared<NotificationContent>(longContent));
return ERR_OK;
}
ErrCode NotificationShellCommand::BuildMultilineContent(const json &contentObj,
const std::string &cTitle, const std::string &cText,
const std::string &cAdditionalText, NotificationRequest &request)
{
if (!contentObj.contains("briefText") || !contentObj["briefText"].is_string()
|| contentObj["briefText"].get<std::string>().empty()) {
OutputError("ERR_ARG_INVALID", "multiline类型通知内容中 briefText 不能为空",
"请在 --notificationContent JSON中包含 briefText 字段", resultReceiver_);
return ERR_INVALID_VALUE;
}
if (!contentObj.contains("expandedTitle") || !contentObj["expandedTitle"].is_string()
|| contentObj["expandedTitle"].get<std::string>().empty()) {
OutputError("ERR_ARG_INVALID", "multiline类型通知内容中 expandedTitle 不能为空",
"请在 --notificationContent JSON中包含 expandedTitle 字段", resultReceiver_);
return ERR_INVALID_VALUE;
}
if (!contentObj.contains("lines") || !contentObj["lines"].is_array()
|| contentObj["lines"].empty()) {
OutputError("ERR_ARG_INVALID", "multiline类型通知内容中 lines 不能为空",
"请在 --notificationContent JSON中包含 lines 字段(数组,最多3行)", resultReceiver_);
return ERR_INVALID_VALUE;
}
std::string expandedTitle = TruncateString(contentObj["expandedTitle"].get<std::string>(), MAX_TITLE_LEN);
std::string briefText = TruncateString(contentObj["briefText"].get<std::string>(), MAX_TITLE_LEN);
auto multiContent = std::make_shared<NotificationMultiLineContent>();
multiContent->SetTitle(cTitle);
multiContent->SetText(cText);
multiContent->SetContentType(static_cast<int32_t>(NotificationContent::Type::MULTILINE));
multiContent->SetExpandedTitle(expandedTitle);
multiContent->SetBriefText(briefText);
if (!cAdditionalText.empty()) {
multiContent->SetAdditionalText(cAdditionalText);
}
int lineCount = 0;
for (const auto &line : contentObj["lines"]) {
if (line.is_string() && lineCount < 3) {
multiContent->AddSingleLine(TruncateString(line.get<std::string>(), MAX_TITLE_LEN));
lineCount++;
}
}
request.SetContent(std::make_shared<NotificationContent>(multiContent));
return ERR_OK;
}
ErrCode NotificationShellCommand::ApplyPublishOptions(const PublishOptions &opts,
NotificationRequest &request)
{
request.SetSlotType(static_cast<NotificationConstant::SlotType>(opts.slotType));
ApplySimplePublishFields(opts, request);
ErrCode ret = BuildNotificationContent(opts.contentJson, request);
if (ret != ERR_OK) {
return ret;
}
ret = ParseAndApplyNotificationFlags(opts.flagsStr, request);
if (ret != ERR_OK) {
return ret;
}
return ERR_OK;
}
ErrCode NotificationShellCommand::ParseAndApplyNotificationFlags(const std::string &jsonStr,
NotificationRequest &request)
{
if (jsonStr.empty()) {
return ERR_OK;
}
if (!json::accept(jsonStr)) {
OutputError("ERR_ARG_INVALID", "通知标志JSON解析失败: JSON格式无效",
"请提供有效的JSON格式。示例: --notificationFlags \"{\\\"soundEnabled\\\":2,\\\"vibrationEnabled\\\":2}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
json flagsObj = json::parse(jsonStr);
if (!flagsObj.is_object()) {
OutputError("ERR_ARG_INVALID", "通知标志必须是JSON对象",
"请提供JSON对象格式。示例: --notificationFlags \"{\\\"soundEnabled\\\":2}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
auto notificationFlags = std::make_shared<NotificationFlags>();
for (auto it = flagsObj.begin(); it != flagsObj.end(); ++it) {
if (!it.value().is_number() || it.value().get<int>() != 2) {
OutputError("ERR_ARG_INVALID", "通知标志字段 " + it.key() + " 的值仅支持2(关闭)",
"请将标志值设为2。示例: --notificationFlags \"{\\\"soundEnabled\\\":2}\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
if (it.key() == "soundEnabled") {
notificationFlags->SetSoundEnabled(NotificationConstant::FlagStatus::CLOSE);
} else if (it.key() == "vibrationEnabled") {
notificationFlags->SetVibrationEnabled(NotificationConstant::FlagStatus::CLOSE);
} else if (it.key() == "bannerEnabled") {
notificationFlags->SetBannerEnabled(NotificationConstant::FlagStatus::CLOSE);
} else if (it.key() == "lockScreenEnabled") {
notificationFlags->SetLockScreenEnabled(NotificationConstant::FlagStatus::CLOSE);
}
}
request.SetFlags(notificationFlags);
return ERR_OK;
}
ErrCode NotificationShellCommand::RunAsCancelByIdCommand()
{
if (ans_ == nullptr) {
OutputApiError(ERR_ANS_SERVICE_NOT_CONNECTED, "取消通知", "", PERM_CONTROLLER_AND_AGENT, resultReceiver_);
return ERR_ANS_SERVICE_NOT_CONNECTED;
}
std::string bundleOptionStr;
int32_t notificationId = 0;
bool hasNotificationId = false;
optind = 0;
int option = getopt_long(argc_, argv_, SHORT_OPTIONS_CANCEL_BY_ID, LONG_OPTIONS_CANCEL_BY_ID, nullptr);
while (option != -1) {
switch (option) {
case 'h':
resultReceiver_.append(CANCEL_BY_ID_HELP_MSG);
return ERR_OK;
case 'o':
bundleOptionStr = optarg;
break;
case 'i': {
hasNotificationId = true;
char *endPtr = nullptr;
long idVal = strtol(optarg, &endPtr, 10);
if (endPtr == optarg || *endPtr != '\0') {
OutputError("ERR_ARG_INVALID", "notificationId参数值无效: 必须为有效整数",
"请使用有效的整数。示例: --notificationId 1", resultReceiver_);
return ERR_INVALID_VALUE;
}
notificationId = static_cast<int32_t>(idVal);
break;
}
default:
OutputError("ERR_UNKNOWN_OPTION", "未知选项: cancelById命令不支持该选项",
"请使用 --help 查看可用选项。示例: ohos-notificationManager cancelById --help",
resultReceiver_);
return ERR_INVALID_VALUE;
}
option = getopt_long(argc_, argv_, SHORT_OPTIONS_CANCEL_BY_ID, LONG_OPTIONS_CANCEL_BY_ID, nullptr);
}
NotificationBundleOption bundleOption;
ErrCode ret = ParseBundleOption(bundleOptionStr, bundleOption);
if (ret != ERR_OK) {
return ret;
}
if (!hasNotificationId) {
OutputError("ERR_ARG_MISSING", "通知ID(--notificationId)缺失: 必须提供有效的通知ID",
"请提供通知ID参数。示例: ohos-notificationManager cancelById "
"--bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --notificationId 1",
resultReceiver_);
return ERR_INVALID_VALUE;
}
ret = NotificationHelper::CancelAsBundle(bundleOption, notificationId);
if (ret == ERR_OK) {
json data;
OutputSuccess(data, resultReceiver_);
return ERR_OK;
}
OutputApiError(ret, "取消通知",
"示例: ohos-notificationManager cancelById "
"--bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --notificationId 1",
PERM_CONTROLLER_AND_AGENT, resultReceiver_);
return ret;
}
ErrCode NotificationShellCommand::ParseHashcodes(const std::string &jsonStr,
std::vector<std::string> &hashcodes)
{
if (jsonStr.empty()) {
OutputError("ERR_ARG_MISSING", "hashcodes缺失或为空: 必须提供至少一个通知哈希码",
"请提供通知哈希码参数。示例: ohos-notificationManager remove "
"--hashcodes \"[\\\"hash1\\\",\\\"hash2\\\"]\"", resultReceiver_);
return ERR_INVALID_VALUE;
}
if (!json::accept(jsonStr)) {
OutputError("ERR_ARG_INVALID", "hashcodes参数解析失败: JSON格式无效",
"请提供有效的JSON数组字符串。示例: --hashcodes \"[\\\"hash1\\\",\\\"hash2\\\"]\"",
resultReceiver_);
return ERR_INVALID_VALUE;
}
auto hashcodesJson = json::parse(jsonStr);
if (!hashcodesJson.is_array() || hashcodesJson.empty()) {
OutputError("ERR_ARG_MISSING", "hashcodes缺失或为空: 必须提供至少一个通知哈希码",
"请提供通知哈希码参数。示例: ohos-notificationManager remove "
"--hashcodes \"[\\\"hash1\\\",\\\"hash2\\\"]\"", resultReceiver_);
return ERR_INVALID_VALUE;
}
for (const auto &item : hashcodesJson) {
if (item.is_string()) {
hashcodes.push_back(item.get<std::string>());
}
}
if (hashcodes.empty()) {
OutputError("ERR_ARG_MISSING", "hashcodes缺失或为空: 必须提供至少一个通知哈希码",
"请提供通知哈希码参数。示例: --hashcodes \"[\\\"hash1\\\"]\"", resultReceiver_);
return ERR_INVALID_VALUE;
}
return ERR_OK;
}
ErrCode NotificationShellCommand::RunAsBatchCancelCommand()
{
if (ans_ == nullptr) {
OutputApiError(ERR_ANS_SERVICE_NOT_CONNECTED, "批量取消通知", "", PERM_CONTROLLER, resultReceiver_);
return ERR_ANS_SERVICE_NOT_CONNECTED;
}
std::string hashcodesStr;
optind = 0;
int option = getopt_long(argc_, argv_, SHORT_OPTIONS_BATCH_CANCEL, LONG_OPTIONS_BATCH_CANCEL, nullptr);
while (option != -1) {
switch (option) {
case 'h':
resultReceiver_.append(BATCH_CANCEL_HELP_MSG);
return ERR_OK;
case 'a':
hashcodesStr = optarg;
break;
default:
OutputError("ERR_UNKNOWN_OPTION", "未知选项: batchCancel命令不支持该选项",
"请使用 --help 查看可用选项。示例: ohos-notificationManager batchCancel --help",
resultReceiver_);
return ERR_INVALID_VALUE;
}
option = getopt_long(argc_, argv_, SHORT_OPTIONS_BATCH_CANCEL, LONG_OPTIONS_BATCH_CANCEL, nullptr);
}
std::vector<std::string> hashcodes;
ErrCode ret = ParseHashcodes(hashcodesStr, hashcodes);
if (ret != ERR_OK) {
return ret;
}
ret = NotificationHelper::RemoveNotifications(hashcodes, NotificationConstant::SHELL_REASON_DELETE);
if (ret == ERR_OK) {
json data;
OutputSuccess(data, resultReceiver_);
return ERR_OK;
}
OutputApiError(ret, "批量取消通知",
"示例: ohos-notificationManager batchCancel --hashcodes \"[\\\"hash1\\\"]\"",
PERM_CONTROLLER, resultReceiver_);
return ret;
}
ErrCode NotificationShellCommand::RunAsCancelByBundleCommand()
{
if (ans_ == nullptr) {
OutputApiError(ERR_ANS_SERVICE_NOT_CONNECTED, "取消通知", "", PERM_CONTROLLER, resultReceiver_);
return ERR_ANS_SERVICE_NOT_CONNECTED;
}
std::string bundleOptionStr;
optind = 0;
int option = getopt_long(argc_, argv_, SHORT_OPTIONS_CANCEL_BY_BUNDLE, LONG_OPTIONS_CANCEL_BY_BUNDLE, nullptr);
while (option != -1) {
switch (option) {
case 'h':
resultReceiver_.append(CANCEL_BY_BUNDLE_HELP_MSG);
return ERR_OK;
case 'o':
bundleOptionStr = optarg;
break;
default:
OutputError("ERR_UNKNOWN_OPTION", "未知选项: cancelByBundle命令不支持该选项",
"请使用 --help 查看可用选项。示例: ohos-notificationManager cancelByBundle --help",
resultReceiver_);
return ERR_INVALID_VALUE;
}
option = getopt_long(argc_, argv_, SHORT_OPTIONS_CANCEL_BY_BUNDLE, LONG_OPTIONS_CANCEL_BY_BUNDLE, nullptr);
}
NotificationBundleOption bundleOption;
ErrCode ret = ParseBundleOption(bundleOptionStr, bundleOption);
if (ret != ERR_OK) {
return ret;
}
ret = NotificationHelper::RemoveNotificationsByBundle(bundleOption);
if (ret == ERR_OK) {
json data;
OutputSuccess(data, resultReceiver_);
return ERR_OK;
}
OutputApiError(ret, "取消通知",
"示例: ohos-notificationManager cancelByBundle "
"--bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\"",
PERM_CONTROLLER, resultReceiver_);
return ret;
}
ErrCode NotificationShellCommand::RunAsEnableNotificationCommand()
{
if (ans_ == nullptr) {
OutputApiError(ERR_ANS_SERVICE_NOT_CONNECTED, "设置通知开关", "", PERM_CONTROLLER, resultReceiver_);
return ERR_ANS_SERVICE_NOT_CONNECTED;
}
std::string bundleOptionStr;
bool enabled = false;
optind = 0;
int option = getopt_long(argc_, argv_,
SHORT_OPTIONS_ENABLE_NOTIFICATION, LONG_OPTIONS_ENABLE_NOTIFICATION, nullptr);
while (option != -1) {
switch (option) {
case 'h':
resultReceiver_.append(ENABLE_NOTIFICATION_HELP_MSG);
return ERR_OK;
case 'o':
bundleOptionStr = optarg;
break;
case 'e':
enabled = true;
break;
default:
OutputError("ERR_UNKNOWN_OPTION", "未知选项: enableNotification命令不支持该选项",
"请使用 --help 查看可用选项。示例: ohos-notificationManager enableNotification --help",
resultReceiver_);
return ERR_INVALID_VALUE;
}
option = getopt_long(argc_, argv_,
SHORT_OPTIONS_ENABLE_NOTIFICATION, LONG_OPTIONS_ENABLE_NOTIFICATION, nullptr);
}
NotificationBundleOption bundleOption;
ErrCode ret = ParseBundleOption(bundleOptionStr, bundleOption);
if (ret != ERR_OK) {
return ret;
}
std::string deviceId {""};
ret = NotificationHelper::SetNotificationsEnabledForSpecifiedBundle(bundleOption, deviceId, enabled);
if (ret == ERR_OK) {
json data;
OutputSuccess(data, resultReceiver_);
return ERR_OK;
}
OutputApiError(ret, "设置通知开关",
"示例: ohos-notificationManager enableNotification "
"--bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --enabled true",
PERM_CONTROLLER, resultReceiver_);
return ret;
}
ErrCode NotificationShellCommand::RunAsSetSlotFlagsCommand()
{
if (ans_ == nullptr) {
OutputApiError(ERR_ANS_SERVICE_NOT_CONNECTED, "设置渠道标志", "", PERM_CONTROLLER, resultReceiver_);
return ERR_ANS_SERVICE_NOT_CONNECTED;
}
std::string bundleOptionStr;
uint32_t slotFlags = 0;
bool hasFlags = false;
optind = 0;
int option = getopt_long(argc_, argv_, SHORT_OPTIONS_SET_SLOT_FLAGS, LONG_OPTIONS_SET_SLOT_FLAGS, nullptr);
while (option != -1) {
switch (option) {
case 'h':
resultReceiver_.append(SET_SLOT_FLAGS_HELP_MSG);
return ERR_OK;
case 'o': bundleOptionStr = optarg; break;
case 'f':
hasFlags = true;
slotFlags = (optarg != nullptr && strncmp(optarg, "0x", 2) == 0)
? static_cast<uint32_t>(strtoul(optarg, nullptr, 16))
: static_cast<uint32_t>(atoi(optarg));
break;
default:
OutputError("ERR_UNKNOWN_OPTION", "未知选项: setSlotFlags命令不支持该选项",
"请使用 --help 查看可用选项。示例: ohos-notificationManager setSlotFlags --help",
resultReceiver_);
return ERR_INVALID_VALUE;
}
option = getopt_long(argc_, argv_, SHORT_OPTIONS_SET_SLOT_FLAGS, LONG_OPTIONS_SET_SLOT_FLAGS, nullptr);
}
NotificationBundleOption bundleOption;
ErrCode ret = ParseBundleOption(bundleOptionStr, bundleOption);
if (ret != ERR_OK) {
return ret;
}
if (!hasFlags) {
OutputError("ERR_ARG_MISSING", "渠道标志(--flags)缺失: 必须提供渠道标志位掩码",
"请提供渠道标志参数。示例: ohos-notificationManager setSlotFlags "
"--bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --flags 1",
resultReceiver_);
return ERR_INVALID_VALUE;
}
if (slotFlags < 0 || slotFlags > MAX_SLOT_FLAGS) {
OutputError("ERR_ARG_INVALID", "渠道标志值无效: 不能小于0或者大于63(0b111111)",
"请使用有效的渠道标志值(0-63)。示例: --flags 63", resultReceiver_);
return ERR_INVALID_VALUE;
}
ret = NotificationHelper::SetNotificationSlotFlagsAsBundle(bundleOption, slotFlags);
if (ret == ERR_OK) {
json data;
OutputSuccess(data, resultReceiver_);
return ERR_OK;
}
OutputApiError(ret, "设置渠道标志",
"示例: ohos-notificationManager setSlotFlags "
"--bundleOption \"{\\\"bundleName\\\":\\\"com.example\\\",\\\"uid\\\":10100}\" --flags 63",
PERM_CONTROLLER, resultReceiver_);
return ret;
}
ErrCode NotificationShellCommand::RunAsListAllNotificationCommand()
{
if (ans_ == nullptr) {
OutputApiError(ERR_ANS_SERVICE_NOT_CONNECTED, "查询通知", "", PERM_CONTROLLER, resultReceiver_);
return ERR_ANS_SERVICE_NOT_CONNECTED;
}
optind = 0;
int option = getopt_long(argc_, argv_, SHORT_OPTIONS_LIST_ALL_NOTIFICATION,
LONG_OPTIONS_LIST_ALL_NOTIFICATION, nullptr);
if (option == 'h') {
resultReceiver_.append(LIST_ALL_NOTIFICATION_HELP_MSG);
return ERR_OK;
}
if (option == '?') {
OutputError("ERR_UNKNOWN_OPTION", "未知选项: list命令不支持额外选项",
"请使用 --help 查看可用选项。示例: ohos-notificationManager listAllNotification --help",
resultReceiver_);
return ERR_INVALID_VALUE;
}
std::vector<sptr<Notification>> notifications;
ErrCode ret = NotificationHelper::GetAllActiveNotifications(notifications);
if (ret != ERR_OK) {
OutputApiError(ret, "查询活跃通知",
"示例: ohos-notificationManager listAllNotification", PERM_CONTROLLER, resultReceiver_);
return ret;
}
json notificationList = json::array();
for (const auto ¬if : notifications) {
if (notif == nullptr) {
continue;
}
json item;
SerializeNotification(notif, item);
notificationList.push_back(item);
}
json data;
data["notifications"] = notificationList;
data["total"] = notificationList.size();
OutputSuccess(data, resultReceiver_);
return ERR_OK;
}
void NotificationShellCommand::SerializeNotification(const sptr<Notification> ¬if, json &item)
{
auto request = notif->GetNotificationRequestPoint();
if (request == nullptr) {
return;
}
item["notificationId"] = request->GetNotificationId();
item["createTime"] = request->GetCreateTime();
item["ownerUid"] = request->GetOwnerUid();
item["ownerUserId"] = request->GetOwnerUserId();
item["ownerBundleName"] = request->GetOwnerBundleName();
item["label"] = request->GetLabel();
item["appInstanceKey"] = request->GetAppInstanceKey();
item["slotType"] = static_cast<int32_t>(request->GetSlotType());
auto content = request->GetContent();
if (content != nullptr) {
json contentObj;
SerializeNotificationContent(content, contentObj);
item["notificationContent"] = contentObj;
}
auto actionButtons = request->GetActionButtons();
if (!actionButtons.empty()) {
json btnArray = json::array();
for (const auto &btn : actionButtons) {
if (btn != nullptr) {
btnArray.push_back(json{{"title", btn->GetTitle()}});
}
}
item["actionButtons"] = btnArray;
}
auto flags = request->GetFlags();
if (flags != nullptr) {
json flagsObj;
flagsObj["soundEnabled"] = static_cast<int32_t>(flags->IsSoundEnabled());
flagsObj["vibrationEnabled"] = static_cast<int32_t>(flags->IsVibrationEnabled());
flagsObj["bannerEnabled"] = static_cast<int32_t>(flags->IsBannerEnabled());
flagsObj["lockScreenEnabled"] = static_cast<int32_t>(flags->IsLockScreenEnabled());
item["notificationFlags"] = flagsObj;
}
item["hashCode"] = request->GetBaseKey("");
}
void NotificationShellCommand::SerializeNotificationContent(
const std::shared_ptr<NotificationContent> &content, json &contentObj)
{
auto contentType = content->GetContentType();
auto baseContent = content->GetNotificationContent();
switch (contentType) {
case NotificationContent::Type::BASIC_TEXT: contentObj["type"] = "basic"; break;
case NotificationContent::Type::LONG_TEXT: contentObj["type"] = "long_text"; break;
case NotificationContent::Type::MULTILINE: contentObj["type"] = "multiline"; break;
case NotificationContent::Type::PICTURE: contentObj["type"] = "picture"; break;
case NotificationContent::Type::CONVERSATION: contentObj["type"] = "conversation"; break;
case NotificationContent::Type::MEDIA: contentObj["type"] = "media"; break;
case NotificationContent::Type::LIVE_VIEW: contentObj["type"] = "live_view"; break;
case NotificationContent::Type::LOCAL_LIVE_VIEW: contentObj["type"] = "local_live_view"; break;
default: contentObj["type"] = "unknown"; break;
}
if (baseContent != nullptr) {
SerializeBasicContent(baseContent, contentObj);
}
if (contentType == NotificationContent::Type::LONG_TEXT) {
SerializeLongTextContent(baseContent, contentObj);
} else if (contentType == NotificationContent::Type::MULTILINE) {
SerializeMultilineContent(baseContent, contentObj);
} else if (contentType == NotificationContent::Type::PICTURE) {
SerializePictureContent(baseContent, contentObj);
} else if (contentType == NotificationContent::Type::CONVERSATION) {
SerializeConversationContent(baseContent, contentObj);
} else if (contentType == NotificationContent::Type::MEDIA) {
SerializeMediaContent(baseContent, contentObj);
} else if (contentType == NotificationContent::Type::LIVE_VIEW) {
SerializeLiveViewContent(baseContent, contentObj);
} else if (contentType == NotificationContent::Type::LOCAL_LIVE_VIEW) {
SerializeLocalLiveViewContent(baseContent, contentObj);
}
}
void NotificationShellCommand::SerializeBasicContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
contentObj["title"] = baseContent->GetTitle();
contentObj["text"] = baseContent->GetText();
if (!baseContent->GetAdditionalText().empty()) {
contentObj["additionalText"] = baseContent->GetAdditionalText();
}
}
void NotificationShellCommand::SerializeLongTextContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
auto longContent = std::static_pointer_cast<NotificationLongTextContent>(baseContent);
if (longContent != nullptr) {
contentObj["longText"] = longContent->GetLongText();
contentObj["expandedTitle"] = longContent->GetExpandedTitle();
contentObj["briefText"] = longContent->GetBriefText();
}
}
void NotificationShellCommand::SerializeMultilineContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
auto multiContent = std::static_pointer_cast<NotificationMultiLineContent>(baseContent);
if (multiContent != nullptr) {
contentObj["expandedTitle"] = multiContent->GetExpandedTitle();
contentObj["briefText"] = multiContent->GetBriefText();
contentObj["lines"] = multiContent->GetAllLines();
}
}
void NotificationShellCommand::SerializePictureContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
auto picContent = std::static_pointer_cast<NotificationPictureContent>(baseContent);
if (picContent != nullptr) {
contentObj["expandedTitle"] = picContent->GetExpandedTitle();
contentObj["briefText"] = picContent->GetBriefText();
}
}
void NotificationShellCommand::SerializeConversationContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
auto convContent = std::static_pointer_cast<NotificationConversationalContent>(baseContent);
if (convContent != nullptr) {
contentObj["conversationTitle"] = convContent->GetConversationTitle();
contentObj["isGroup"] = convContent->IsConversationGroup();
json messages = json::array();
for (const auto &msg : convContent->GetAllConversationalMessages()) {
if (msg == nullptr) {
continue;
}
json msgObj;
msgObj["text"] = msg->GetText();
msgObj["arrivedTime"] = msg->GetArrivedTime();
auto sender = msg->GetSender();
msgObj["senderName"] = sender.GetName();
msgObj["senderKey"] = sender.GetKey();
messages.push_back(msgObj);
}
contentObj["messages"] = messages;
}
}
void NotificationShellCommand::SerializeMediaContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
auto mediaContent = std::static_pointer_cast<NotificationMediaContent>(baseContent);
if (mediaContent != nullptr) {
contentObj["shownActions"] = mediaContent->GetShownActions();
}
}
void NotificationShellCommand::SerializeLiveViewContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
auto liveContent = std::static_pointer_cast<NotificationLiveViewContent>(baseContent);
if (liveContent != nullptr) {
contentObj["liveViewStatus"] = static_cast<int32_t>(liveContent->GetLiveViewStatus());
contentObj["version"] = liveContent->GetVersion();
}
}
void NotificationShellCommand::SerializeLocalLiveViewContent(
const std::shared_ptr<NotificationBasicContent> &baseContent, json &contentObj)
{
auto localLiveContent = std::static_pointer_cast<NotificationLocalLiveViewContent>(baseContent);
if (localLiveContent != nullptr) {
contentObj["liveViewType"] = static_cast<int32_t>(localLiveContent->GetLiveViewType());
}
}
}
}