Index: chrome/browser/notifications/notification_toast_helper_win.cc |
diff --git a/chrome/browser/notifications/notification_toast_helper_win.cc b/chrome/browser/notifications/notification_toast_helper_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d8ae1eb9a349fcfa9f6309e4e1fd9d02853fe584 |
--- /dev/null |
+++ b/chrome/browser/notifications/notification_toast_helper_win.cc |
@@ -0,0 +1,321 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/notifications/notification_toast_helper_win.h" |
+ |
+#include <vector> |
+ |
+#include "base/files/file_path.h" |
+#include "chrome/installer/util/install_util.h" |
+#include "chrome/installer/util/shell_util.h" |
+ |
+namespace { |
+ |
+// Templated wrapper for winfoundtn::GetActivationFactory(). |
+template<unsigned int size, typename T> |
+HRESULT CreateActivationFactory(wchar_t const (&class_name)[size], T** object) { |
+ mswrw::HStringReference ref_class_name(class_name); |
+ return winfoundtn::GetActivationFactory(ref_class_name.Get(), object); |
+} |
+ |
+// Returns Chrome's AppId on success, and empty string on failure. |
+base::string16 GetChromeAppId() { |
+ bool is_per_user_install = InstallUtil::IsPerUserInstall(); |
+ base::string16 appid = ShellUtil::GetBrowserModelId(is_per_user_install); |
+ DVLOG(1) << "Chrome Appid is " << appid.c_str(); |
+ return appid; |
+} |
+ |
+} // namespace |
+ |
+void NotificationToastHelperWin::CreateToastManager() { |
+ if (HasFailed()) |
+ return; |
+ hr_ = CreateActivationFactory( |
+ RuntimeClass_Windows_UI_Notifications_ToastNotificationManager, |
+ toast_manager_.GetAddressOf()); |
+} |
+ |
+void NotificationToastHelperWin::LoadXMLFromTemplate( |
+ winui::Notifications::ToastTemplateType type) { |
+ if (HasFailed()) |
+ return; |
+ hr_ = toast_manager_->GetTemplateContent(type, &toast_xml_); |
+ if (!toast_xml_) { |
+ hr_ = E_FAIL; |
+ return; |
+ } |
+ hr_ = toast_xml_->get_DocumentElement(&document_element_); |
+ if (!document_element_) |
+ hr_ = E_FAIL; |
+} |
+ |
+void NotificationToastHelperWin::LoadXMLFromString( |
+ const base::string16& xml_str) { |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlDocumentIO> xml_document; |
+ |
+ mswrw::HStringReference ref_class_name( |
+ RuntimeClass_Windows_Data_Xml_Dom_XmlDocument); |
+ hr_ = Windows::Foundation::ActivateInstance(ref_class_name.Get(), |
+ &xml_document); |
+ // hr_ = CreateActivationFactory( |
+ // RuntimeClass_Windows_Data_Xml_Dom_XmlDocument, |
+ // xml_document.GetAddressOf()); |
+ if (HasFailed()) |
+ return; |
+ |
+ mswrw::HString xml_hs; |
+ xml_hs.Attach(MakeHString(xml_str)); |
+ hr_ = xml_document->LoadXml(xml_hs.Get()); |
+ if (HasFailed()) |
+ return; |
+ |
+ winxml::Dom::IXmlDocument** xml = &toast_xml_; |
+ hr_ = xml_document.CopyTo(xml); |
+ if (!document_element_) |
+ hr_ = E_FAIL; |
+ |
+ hr_ = toast_xml_->get_DocumentElement(&document_element_); |
+} |
+ |
+// For debugging. |
+// TODO(huangs): Remove. |
+void NotificationToastHelperWin::AlertToastXml() { |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<ABI::Windows::Data::Xml::Dom::IXmlNodeSerializer> s; |
+ toast_xml_.As(&s); |
+ HSTRING xml_string; |
+ hr_ = s->GetXml(&xml_string); |
+ if (StillOkay()) { |
+ PCWSTR str = WindowsGetStringRawBuffer(xml_string, NULL); |
+ ::MessageBox(NULL, str, L"Title", MB_OK); |
+ } |
+} |
+ |
+void NotificationToastHelperWin::SelectDocument() { |
+ if (HasFailed()) |
+ return; |
+ if (document_element_) |
+ cur_element_ = document_element_; |
+ else |
+ hr_ = E_FAIL; |
+} |
+ |
+void NotificationToastHelperWin::SelectElementByTagNameAndIndex( |
+ const base::string16& tag_name, unsigned int index) { |
+ if (HasFailed()) |
+ return; |
+ mswrw::HString hs_tag_name; |
+ hs_tag_name.Attach(MakeHString(tag_name)); |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlNodeList> elements; |
+ hr_ = document_element_->GetElementsByTagName(hs_tag_name.Get(), &elements); |
+ if (HasFailed()) |
+ return; |
+ unsigned int count = 0; |
+ elements->get_Length(&count); |
+ if (index >= count) { |
+ DVLOG(1) << "Requesting nonexistent node with tag_name " << tag_name |
+ << " and index " << index; |
+ hr_ = E_FAIL; |
+ return; |
+ } |
+ mswr::ComPtr<winxml::Dom::IXmlNode> cur_node; |
+ hr_ = elements->Item(index, &cur_node); |
+ if (StillOkay()) |
+ hr_ = cur_node.As(&cur_element_); |
+} |
+ |
+// Converts a file path, e.g., "C:\\User\\test\\AppData\\Local\\Temp\\a.tmp" |
+// to a file URL, e.g., "file:///C:/User/test/AppData/Local/Temp/a.tmp". |
+base::string16 NotificationToastHelperWin::FilePathToFileUrl( |
+ const base::FilePath& file_path) { |
+ if (HasFailed()) |
+ return L""; |
+ const size_t kFileUrlExtraSize = 10; // Acommodates L"file:///". and L'\0'. |
+ base::string16 file_str = file_path.AsUTF16Unsafe(); |
+ DWORD size = static_cast<DWORD>(file_str.size() + kFileUrlExtraSize); |
+ std::vector<base::char16> buffer(size); |
+ hr_ = ::UrlCreateFromPathW(file_str.c_str(), &buffer[0], &size, NULL); |
+ if (HasFailed()) |
+ return L""; |
+ return base::string16(&buffer[0]); |
+} |
+ |
+void NotificationToastHelperWin::RemoveElement() { |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlNode> cur_node; |
+ hr_ = cur_element_.As(&cur_node); |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlNode> parent_node; |
+ hr_ = cur_node->get_ParentNode(&parent_node); |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlNode> removed_node; |
+ hr_ = parent_node->RemoveChild(cur_node.Get(), &removed_node); |
+ if (HasFailed()) |
+ return; |
+ hr_ = parent_node.As(&cur_element_); |
+} |
+ |
+void NotificationToastHelperWin::AppendText(const base::string16& text) { |
+ if (HasFailed()) |
+ return; |
+ if (!cur_element_) { |
+ hr_ = E_FAIL; |
+ return; |
+ } |
+ mswr::ComPtr<winxml::Dom::IXmlNode> text_node; |
+ CreateTextNode(text, &text_node); |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlNode> cur_node; |
+ hr_ = cur_element_.As(&cur_node); |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlNode> appended_node; |
+ hr_ = cur_node->AppendChild(text_node.Get(), &appended_node); |
+} |
+ |
+void NotificationToastHelperWin::SetAttribute(const base::string16& name, |
+ const base::string16& value) { |
+ if (HasFailed()) |
+ return; |
+ if (!cur_element_) { |
+ hr_ = E_FAIL; |
+ return; |
+ } |
+ mswrw::HString name_hs; |
+ name_hs.Attach(MakeHString(name)); |
+ if (HasFailed()) |
+ return; |
+ mswrw::HString value_hs; |
+ value_hs.Attach(MakeHString(value)); |
+ if (HasFailed()) |
+ return; |
+ hr_ = cur_element_->SetAttribute(name_hs.Get(), value_hs.Get()); |
+} |
+ |
+base::string16 NotificationToastHelperWin::GetAttribute( |
+ const base::string16& name) { |
+ if (HasFailed()) |
+ return L""; |
+ if (!cur_element_) { |
+ hr_ = E_FAIL; |
+ return L""; |
+ } |
+ mswrw::HString name_hs; |
+ name_hs.Attach(MakeHString(name)); |
+ if (HasFailed()) |
+ return L""; |
+ HSTRING value; |
+ hr_ = cur_element_->GetAttribute(name_hs.Get(), &value); |
+ if (HasFailed()) |
+ return L""; |
+ PCWSTR str = WindowsGetStringRawBuffer(value, NULL); |
+ return base::string16(str); |
+} |
+ |
+void NotificationToastHelperWin::CreateToastNotifier() { |
+ if (HasFailed()) |
+ return; |
+ base::string16 appid = GetChromeAppId(); |
+ if (appid.empty()) { |
+ hr_ = E_FAIL; |
+ return; |
+ } |
+ mswrw::HString app_user_model_id; |
+ app_user_model_id.Attach(MakeHString(appid)); |
+ if (HasFailed()) |
+ return; |
+ hr_ = toast_manager_->CreateToastNotifierWithId(app_user_model_id.Get(), |
+ ¬ifier_); |
+} |
+ |
+void NotificationToastHelperWin::CreateToastNotification() { |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winui::Notifications::IToastNotificationFactory> |
+ toast_notification_factory; |
+ hr_ = CreateActivationFactory( |
+ RuntimeClass_Windows_UI_Notifications_ToastNotification, |
+ toast_notification_factory.GetAddressOf()); |
+ if (HasFailed()) |
+ return; |
+ hr_ = toast_notification_factory->CreateToastNotification( |
+ toast_xml_.Get(), &toast_notification_); |
+} |
+ |
+void NotificationToastHelperWin::LoadNotificationAndXml( |
+ winui::Notifications::IToastNotification* toast_notification) { |
+ if (HasFailed()) |
+ return; |
+ toast_notification_ = toast_notification; |
+ hr_ = toast_notification_->get_Content(&toast_xml_); |
+ if (HasFailed()) |
+ return; |
+ hr_ = toast_xml_->get_DocumentElement(&document_element_); |
+ if (!document_element_) |
+ hr_ = E_FAIL; |
+} |
+ |
+void NotificationToastHelperWin::Show( |
+ mswr::ComPtr<ToastActivatedHandler> activated_handler, |
+ mswr::ComPtr<ToastDismissedHandler> dismissed_handler, |
+ mswr::ComPtr<ToastFailedHandler> failed_handler, |
+ EventRegistrationToken* activated_token, |
+ EventRegistrationToken* dismissed_token, |
+ EventRegistrationToken* failed_token) { |
+ if (HasFailed()) |
+ return; |
+ hr_ = toast_notification_->add_Activated(activated_handler.Get(), |
+ activated_token); |
+ if (HasFailed()) |
+ return; |
+ hr_ = toast_notification_->add_Dismissed(dismissed_handler.Get(), |
+ dismissed_token); |
+ if (HasFailed()) |
+ return; |
+ hr_ = toast_notification_->add_Failed(failed_handler.Get(), failed_token); |
+ if (HasFailed()) |
+ return; |
+ hr_ = notifier_->Show(toast_notification_.Get()); |
+} |
+ |
+// Returned HSTRING should be deallocated by ::WindowsDeleteString(). This can |
+// be done by attaching the return value to mswrw::HString. |
+HSTRING NotificationToastHelperWin::MakeHString(const base::string16& str) { |
+ if (HasFailed()) |
+ return NULL; |
+ HSTRING hstr; |
+ hr_ = ::WindowsCreateString(str.c_str(), |
+ static_cast<UINT32>(str.size()), |
+ &hstr); |
+ if (HasFailed()) { |
+ DVLOG(1) << "HString creation failed."; |
+ return NULL; |
+ } |
+ return hstr; |
+} |
+ |
+void NotificationToastHelperWin::CreateTextNode(const base::string16& text, |
+ mswr::ComPtr<winxml::Dom::IXmlNode>* node) { |
+ if (HasFailed()) |
+ return; |
+ mswrw::HString text_hs; |
+ text_hs.Attach(MakeHString(text)); |
+ if (HasFailed()) |
+ return; |
+ mswr::ComPtr<winxml::Dom::IXmlText> text_xml; |
+ hr_ = toast_xml_->CreateTextNode(text_hs.Get(), &text_xml); |
+ if (HasFailed()) |
+ return; |
+ hr_ = text_xml.As(node); |
+} |