Chromium Code Reviews| 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; |
| +} |