From af01fa70638bfd609df61e095c4c84475d5ba6eb Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Fri, 6 Sep 2019 14:08:25 -0700 Subject: [PATCH] implement on windows --- docs/api/notification.md | 6 +- shell/browser/api/atom_api_notification.cc | 2 +- .../linux/libnotify_notification.cc | 2 +- .../win/windows_toast_notification.cc | 63 ++++++++++++++++++- .../win/windows_toast_notification.h | 2 + 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/docs/api/notification.md b/docs/api/notification.md index 90a7eab0a928a..32a24a0d0fe9d 100644 --- a/docs/api/notification.md +++ b/docs/api/notification.md @@ -35,7 +35,7 @@ Returns `Boolean` - Whether or not desktop notifications are supported on the cu * `silent` Boolean (optional) - Whether or not to emit an OS notification noise when showing the notification. * `icon` (String | [NativeImage](native-image.md)) (optional) - An icon to use in the notification. * `hasReply` Boolean (optional) _macOS_ - Whether or not to add an inline reply option to the notification. - * `timeoutType` String (optional) _Linux_ - The timeout duration of the notification. + * `timeoutType` String (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'. * `replyPlaceholder` String (optional) _macOS_ - The placeholder to write in the inline reply input field. * `sound` String (optional) _macOS_ - The name of the sound file to play when the notification is shown. * `urgency` String (optional) _Linux_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'. @@ -152,11 +152,11 @@ A `String` property representing the urgency level of the notification. Can be ' Default is 'low' - see [NotifyUrgency](https://developer.gnome.org/notification-spec/#urgency-levels) for more information. -#### `notification.timeoutType` _Linux_ +#### `notification.timeoutType` _Linux_ _Windows_ A `String` property representing the type of timeout duration for the notification. Can be 'default' or 'never'. -If 'never' is set, the notification never expires. It stays open until closed by the calling API or the user. +If `timeoutType` is set to 'never', the notification never expires. It stays open until closed by the calling API or the user. #### `notification.actions` diff --git a/shell/browser/api/atom_api_notification.cc b/shell/browser/api/atom_api_notification.cc index c9f89bfd34fc0..8a2f98943b7bf 100644 --- a/shell/browser/api/atom_api_notification.cc +++ b/shell/browser/api/atom_api_notification.cc @@ -157,7 +157,7 @@ void Notification::SetHasReply(bool new_has_reply) { has_reply_ = new_has_reply; } -void Notification::SetTimeoutType(bool new_timeout_type) { +void Notification::SetTimeoutType(const base::string16& new_timeout_type) { timeout_type_ = new_timeout_type; } diff --git a/shell/browser/notifications/linux/libnotify_notification.cc b/shell/browser/notifications/linux/libnotify_notification.cc index ed43bdc6ee758..dc52fa5af5b1f 100644 --- a/shell/browser/notifications/linux/libnotify_notification.cc +++ b/shell/browser/notifications/linux/libnotify_notification.cc @@ -118,7 +118,7 @@ void LibnotifyNotification::Show(const NotificationOptions& options) { } // Set the timeout duration for the notification - bool neverTimeout = options.timeoutType == base::ASCIIToUTF16("never"); + bool neverTimeout = options.timeout_type == base::ASCIIToUTF16("never"); int timeout = (neverTimeout) ? NOTIFY_EXPIRES_NEVER : NOTIFY_EXPIRES_DEFAULT; libnotify_loader_.notify_notification_set_timeout(notification_, timeout); diff --git a/shell/browser/notifications/win/windows_toast_notification.cc b/shell/browser/notifications/win/windows_toast_notification.cc index c73cdf39c8a4d..b5ca4dc62853f 100644 --- a/shell/browser/notifications/win/windows_toast_notification.cc +++ b/shell/browser/notifications/win/windows_toast_notification.cc @@ -94,7 +94,8 @@ void WindowsToastNotification::Show(const NotificationOptions& options) { ComPtr toast_xml; if (FAILED(GetToastXml(toast_manager_.Get(), options.title, options.msg, - icon_path, options.silent, &toast_xml))) { + icon_path, options.timeout_type, options.silent, + &toast_xml))) { NotificationFailed(); return; } @@ -149,6 +150,7 @@ bool WindowsToastNotification::GetToastXml( const std::wstring& title, const std::wstring& msg, const std::wstring& icon_path, + const std::wstring& timeout_type, bool silent, IXmlDocument** toast_xml) { ABI::Windows::UI::Notifications::ToastTemplateType template_type; @@ -183,6 +185,15 @@ bool WindowsToastNotification::GetToastXml( } } + // Configure the toast's timeout settings + if (timeout_type == base::ASCIIToUTF16("never")) { + if (FAILED(SetXmlScenarioReminder(*toast_xml))) { + if (IsDebuggingNotifications()) + LOG(INFO) << "Setting \"scenario\" option on notification failed"; + return false; + } + } + // Configure the toast's notification sound if (silent) { if (FAILED(SetXmlAudioSilent(*toast_xml))) { @@ -201,6 +212,56 @@ bool WindowsToastNotification::GetToastXml( return true; } +bool WindowsToastNotification::SetXmlScenarioReminder(IXmlDocument* doc) { + ScopedHString tag(L"toast"); + if (!tag.success()) + return false; + + ComPtr node_list; + if (FAILED(doc->GetElementsByTagName(tag, &node_list))) + return false; + + // Check that root "toast" node exists + ComPtr root; + if (FAILED(node_list->Item(0, &root))) + return false; + + // get attributes of root "toast" node + ComPtr attributes; + if (FAILED(root->get_Attributes(&attributes))) + return false; + + ComPtr scenario_attribute; + ScopedHString scenario_str(L"scenario"); + if (FAILED(doc->CreateAttribute(scenario_str, &scenario_attribute))) + return false; + + ComPtr scenario_attribute_node; + if (FAILED(scenario_attribute.As(&scenario_attribute_node))) + return false; + + ScopedHString scenario_value(L"reminder"); + if (!scenario_value.success()) + return false; + + ComPtr scenario_text; + if (FAILED(doc->CreateTextNode(scenario_value, &scenario_text))) + return false; + + ComPtr scenario_node; + if (FAILED(scenario_text.As(&scenario_node))) + return false; + + ComPtr child_node; + if (FAILED(scenario_attribute_node->AppendChild(scenario_node.Get(), + &child_node))) + return false; + + ComPtr scenario_attribute_pnode; + return SUCCEEDED(attributes.Get()->SetNamedItem(scenario_attribute_node.Get(), + &scenario_attribute_pnode)); +} + bool WindowsToastNotification::SetXmlAudioSilent(IXmlDocument* doc) { ScopedHString tag(L"toast"); if (!tag.success()) diff --git a/shell/browser/notifications/win/windows_toast_notification.h b/shell/browser/notifications/win/windows_toast_notification.h index 10c378480782e..eed2e2bed5d08 100644 --- a/shell/browser/notifications/win/windows_toast_notification.h +++ b/shell/browser/notifications/win/windows_toast_notification.h @@ -63,9 +63,11 @@ class WindowsToastNotification : public Notification { const std::wstring& title, const std::wstring& msg, const std::wstring& icon_path, + const std::wstring& timeout_type, const bool silent, ABI::Windows::Data::Xml::Dom::IXmlDocument** toastXml); bool SetXmlAudioSilent(ABI::Windows::Data::Xml::Dom::IXmlDocument* doc); + bool SetXmlScenarioReminder(ABI::Windows::Data::Xml::Dom::IXmlDocument* doc); bool SetXmlText(ABI::Windows::Data::Xml::Dom::IXmlDocument* doc, const std::wstring& text); bool SetXmlText(ABI::Windows::Data::Xml::Dom::IXmlDocument* doc,