Index: chrome/browser/notifications/notification_platform_bridge_win.cc |
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..74389f95962343feb83e3a959b8d3619eafa610b |
--- /dev/null |
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc |
@@ -0,0 +1,278 @@ |
+// 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_platform_bridge_win.h" |
+ |
+#include <activation.h> |
+#include <d2d1_1.h> |
+#include <d3d11_1.h> |
+#include <roapi.h> |
+#include <stdio.h> |
+#include <wincodec.h> |
+#include <windows.h> |
+#include <windows.applicationModel.core.h> |
+#include <windows.applicationModel.datatransfer.h> |
+#include <windows.graphics.printing.h> |
+#include <windows.storage.pickers.h> |
+#include <windows.ui.notifications.h> |
+#include <wrl/implements.h> |
+#include <wrl/module.h> |
+#include <wrl/event.h> |
+#include <wrl/wrappers/corewrappers.h> |
+ |
+#include "base/files/file_path.h" |
+#include "base/path_service.h" |
+#include "base/strings/string16.h" |
+#include "base/win/scoped_comptr.h" |
+#include "chrome/browser/notifications/notification.h" |
+#include "chrome/installer/util/browser_distribution.h" |
+#include "chrome/installer/util/install_util.h" |
+#include "chrome/installer/util/shell_util.h" |
+ |
+namespace mswr = Microsoft::WRL; |
+namespace mswrw = Microsoft::WRL::Wrappers; |
+ |
+namespace winapp = ABI::Windows::ApplicationModel; |
+namespace windata = ABI::Windows::Data; |
+namespace winxml = ABI::Windows::Data::Xml; |
+namespace windevs = ABI::Windows::Devices; |
+namespace winfoundtn = ABI::Windows::Foundation; |
+namespace wingfx = ABI::Windows::Graphics; |
+namespace winui = ABI::Windows::UI; |
+namespace winsys = ABI::Windows::System; |
+namespace winstorage = ABI::Windows::Storage; |
+ |
+typedef winfoundtn::ITypedEventHandler< |
+ winui::Notifications::ToastNotification*, IInspectable*> |
+ ToastActivationHandler; |
+ |
+typedef winfoundtn::ITypedEventHandler< |
+ winui::Notifications::ToastNotification*, |
+ winui::Notifications::ToastDismissedEventArgs*> ToastDismissedHandler; |
+ |
+namespace { |
+ |
+void CheckHR(HRESULT hr, const char* message = nullptr) { |
chrisha
2016/06/02 21:14:10
Worth documenting that this is non-returning and c
Peter Beverloo
2016/06/07 15:48:29
I don't know if this is common for Windows code, b
huangs
2016/06/07 23:27:46
Done.
huangs
2016/06/07 23:27:46
From sample code, looks the style should be a chai
|
+ if (FAILED(hr)) { |
+ if (message) |
+ PLOG(DFATAL) << message << ", hr = " << std::hex << hr; |
+ else |
+ PLOG(DFATAL) << "COM ERROR" << ", hr = " << std::hex << hr; |
+ } |
+} |
+ |
+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); |
+} |
+ |
+HSTRING MakeHString(const base::string16& str) { |
Peter Beverloo
2016/06/07 15:48:29
Dito here, although as I understand it a NULL HSTR
huangs
2016/06/08 22:12:13
Done. Made the entire thing defensive in Patch #3;
|
+ HSTRING hstr; |
+ if (FAILED(::WindowsCreateString(str.c_str(), static_cast<UINT32>(str.size()), |
+ &hstr))) { |
+ PLOG(DFATAL) << "Hstring creation failed"; |
+ } |
+ return hstr; |
+} |
+ |
+ |
+// Helper function to return the text node root identified by the index passed |
+// in. |
+HRESULT GetTextNodeRoot( |
+ unsigned int index, |
+ winxml::Dom::IXmlDocument* xml_doc, |
+ winxml::Dom::IXmlNode** node) { |
+ DCHECK(xml_doc); |
+ DCHECK(node); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlElement> document_element; |
+ HRESULT hr = xml_doc->get_DocumentElement(&document_element); |
+ CheckHR(hr); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlNodeList> elements; |
+ mswrw::HString tag_name; |
+ tag_name.Attach(MakeHString(L"text")); |
+ hr = document_element->GetElementsByTagName(tag_name.Get(), |
+ &elements); |
+ CheckHR(hr); |
+ |
+ unsigned int count = 0; |
+ elements->get_Length(&count); |
+ |
+ if (index > count) { |
Peter Beverloo
2016/06/07 15:48:29
It sounds like the index to IXmlNode::Item() is ze
huangs
2016/06/14 01:12:35
Done.
|
+ DVLOG(1) << "Invalid text node index passed in : " << index; |
+ return E_FAIL; |
+ } |
+ hr = elements->Item(index, node); |
+ CheckHR(hr); |
+ return hr; |
+} |
+ |
+// Helper function to append a text element to the text section in the |
+// XML document passed in. |
+// The index parameter identifies which text node we append to. |
+HRESULT CreateTextNode(winxml::Dom::IXmlDocument* xml_doc, |
+ int index, |
+ const base::string16& text_string) { |
+ DCHECK(xml_doc); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlElement> document_element; |
+ HRESULT hr = xml_doc->get_DocumentElement(&document_element); |
+ CheckHR(hr); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlText> xml_text_node; |
+ mswrw::HString data_hstring; |
+ data_hstring.Attach(MakeHString(text_string.c_str())); |
+ hr = xml_doc->CreateTextNode(data_hstring.Get(), &xml_text_node); |
+ CheckHR(hr); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlNode> created_node; |
+ hr = xml_text_node.CopyTo( |
+ winxml::Dom::IID_IXmlNode, |
+ reinterpret_cast<void**>(created_node.GetAddressOf())); |
+ CheckHR(hr); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlNode> text_node_root; |
+ hr = GetTextNodeRoot(index, xml_doc, &text_node_root); |
Peter Beverloo
2016/06/07 15:48:29
nit: CreateTextNode takes |index| as an (int), but
huangs
2016/06/08 22:12:13
Refactoring removed this difference. Now using un
|
+ CheckHR(hr); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlNode> appended_node; |
+ hr = text_node_root->AppendChild(created_node.Get(), &appended_node); |
+ CheckHR(hr); |
+ return hr; |
+} |
+ |
+} // namespace |
+ |
+// static |
+NotificationPlatformBridge* NotificationPlatformBridge::Create() { |
+ return new NotificationPlatformBridgeWin(); |
+} |
+ |
+NotificationPlatformBridgeWin::NotificationPlatformBridgeWin() {} |
+ |
+NotificationPlatformBridgeWin::~NotificationPlatformBridgeWin() {} |
+ |
+void NotificationPlatformBridgeWin::Display(const std::string& notification_id, |
+ const std::string& profile_id, |
+ bool incognito, |
+ const Notification& notification) { |
+ mswr::ComPtr<winui::Notifications::IToastNotifier> notifier_; |
+ mswr::ComPtr<winui::Notifications::IToastNotification> toast_notification_; |
+ |
+ DCHECK(notifier_.Get() == NULL); |
+ DCHECK(toast_notification_.Get() == NULL); |
+ |
+ mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics> |
+ toast_manager; |
+ |
+ HRESULT hr = CreateActivationFactory( |
+ RuntimeClass_Windows_UI_Notifications_ToastNotificationManager, |
+ toast_manager.GetAddressOf()); |
+ CheckHR(hr); |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlDocument> toast_xml; |
+ hr = toast_manager->GetTemplateContent( |
+ winui::Notifications::ToastTemplateType_ToastText02, |
Peter Beverloo
2016/06/07 15:48:29
I agree with starting with ToastText02, but could
huangs
2016/06/08 22:12:13
Refactored code to shuffle ugliness in helper clas
|
+ &toast_xml); |
+ CheckHR(hr); |
+ |
+ if (!toast_xml) |
+ return; |
+ |
+ mswr::ComPtr<winxml::Dom::IXmlElement> document_element; |
+ hr = toast_xml->get_DocumentElement(&document_element); |
+ CheckHR(hr); |
+ |
+ if (!document_element) |
+ return; |
+ |
+ hr = CreateTextNode(toast_xml.Get(), 0, notification.title()); |
chrisha
2016/06/02 21:14:10
Where does the constant '0' come from?
huangs
2016/06/08 22:12:13
First <text> element in the template, which looks
|
+ CheckHR(hr); |
+ |
+ hr = CreateTextNode(toast_xml.Get(), 1, notification.message()); |
chrisha
2016/06/02 21:14:10
Ditto '1'? Maybe make these constants describing w
|
+ CheckHR(hr); |
+ |
+ mswrw::HString duration_attribute_name; |
+ duration_attribute_name.Attach(MakeHString(L"duration")); |
+ mswrw::HString duration_attribute_value; |
+ duration_attribute_value.Attach(MakeHString(L"long")); |
+ |
+ hr = document_element->SetAttribute(duration_attribute_name.Get(), |
+ duration_attribute_value.Get()); |
+ CheckHR(hr); |
+ |
+ // TODO(ananta) |
+ // We should set the image and launch params attribute in the notification |
+ // XNL as described here: http://msdn.microsoft.com/en-us/library/hh465448 |
+ // To set the image we may have to extract the image and specify it in the |
+ // following url form. ms-appx:///images/foo.png |
+ // The launch params as described don't get passed back to us via the |
+ // winapp::Activation::ILaunchActivatedEventArgs argument. Needs to be |
+ // investigated. |
+ mswr::ComPtr<winui::Notifications::IToastNotificationFactory> |
+ toast_notification_factory; |
+ hr = CreateActivationFactory( |
+ RuntimeClass_Windows_UI_Notifications_ToastNotification, |
+ toast_notification_factory.GetAddressOf()); |
+ CheckHR(hr); |
+ |
+ hr = toast_notification_factory->CreateToastNotification( |
+ toast_xml.Get(), &toast_notification_); |
+ CheckHR(hr); |
+ |
+ base::FilePath chrome_path; |
+ if (!PathService::Get(base::FILE_EXE, &chrome_path)) { |
+ NOTREACHED() << "Failed to get chrome exe path"; |
+ return; |
+ } |
+ |
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
+ bool is_per_user_install = InstallUtil::IsPerUserInstall(chrome_path); |
+ base::string16 appid = |
+ ShellUtil::GetBrowserModelId(dist, is_per_user_install); |
+ DVLOG(1) << "Chrome Appid is " << appid.c_str(); |
+ |
+ mswrw::HString app_user_model_id; |
+ app_user_model_id.Attach(MakeHString(appid)); |
+ |
+ hr = toast_manager->CreateToastNotifierWithId(app_user_model_id.Get(), |
+ ¬ifier_); |
+ CheckHR(hr); |
+ |
+ EventRegistrationToken activated_token_; |
+ hr = toast_notification_->add_Activated( |
+ mswr::Callback<ToastActivationHandler>( |
+ this, &NotificationPlatformBridgeWin::OnActivate).Get(), |
+ &activated_token_); |
+ CheckHR(hr); |
+ |
+ hr = notifier_->Show(toast_notification_.Get()); |
+ CheckHR(hr); |
+} |
+ |
+void NotificationPlatformBridgeWin::Close( |
+ const std::string& profile_id, |
+ const std::string& notification_id) { |
+ // TODO(huangs): Implement. |
+} |
+ |
+bool NotificationPlatformBridgeWin::GetDisplayed( |
+ const std::string& profile_id, |
+ bool incognito, |
+ std::set<std::string>* notifications) const { |
+ // TODO(huangs): Implement. |
Peter Beverloo
2016/06/07 15:48:29
Do you expect any issues in supporting these two T
|
+ return true; |
+} |
+ |
+bool NotificationPlatformBridgeWin::SupportsNotificationCenter() const { |
+ return true; |
+} |
+ |
+HRESULT NotificationPlatformBridgeWin::OnActivate( |
+ winui::Notifications::IToastNotification* notification, |
+ IInspectable* inspectable) { |
+ return S_OK; |
+} |