Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/notifications/notification_platform_bridge_win.h" | |
| 6 | |
| 7 #include <activation.h> | |
| 8 #include <d2d1_1.h> | |
| 9 #include <d3d11_1.h> | |
| 10 #include <roapi.h> | |
| 11 #include <stdio.h> | |
| 12 #include <wincodec.h> | |
| 13 #include <windows.h> | |
| 14 #include <windows.applicationModel.core.h> | |
| 15 #include <windows.applicationModel.datatransfer.h> | |
| 16 #include <windows.graphics.printing.h> | |
| 17 #include <windows.storage.pickers.h> | |
| 18 #include <windows.ui.notifications.h> | |
| 19 #include <wrl/implements.h> | |
| 20 #include <wrl/module.h> | |
| 21 #include <wrl/event.h> | |
| 22 #include <wrl/wrappers/corewrappers.h> | |
| 23 | |
| 24 #include "base/files/file_path.h" | |
| 25 #include "base/path_service.h" | |
| 26 #include "base/strings/string16.h" | |
| 27 #include "base/win/scoped_comptr.h" | |
| 28 #include "chrome/browser/notifications/notification.h" | |
| 29 #include "chrome/installer/util/browser_distribution.h" | |
| 30 #include "chrome/installer/util/install_util.h" | |
| 31 #include "chrome/installer/util/shell_util.h" | |
| 32 | |
| 33 namespace mswr = Microsoft::WRL; | |
| 34 namespace mswrw = Microsoft::WRL::Wrappers; | |
| 35 | |
| 36 namespace winapp = ABI::Windows::ApplicationModel; | |
| 37 namespace windata = ABI::Windows::Data; | |
| 38 namespace winxml = ABI::Windows::Data::Xml; | |
| 39 namespace windevs = ABI::Windows::Devices; | |
| 40 namespace winfoundtn = ABI::Windows::Foundation; | |
| 41 namespace wingfx = ABI::Windows::Graphics; | |
| 42 namespace winui = ABI::Windows::UI; | |
| 43 namespace winsys = ABI::Windows::System; | |
| 44 namespace winstorage = ABI::Windows::Storage; | |
| 45 | |
| 46 typedef winfoundtn::ITypedEventHandler< | |
| 47 winui::Notifications::ToastNotification*, IInspectable*> | |
| 48 ToastActivationHandler; | |
| 49 | |
| 50 typedef winfoundtn::ITypedEventHandler< | |
| 51 winui::Notifications::ToastNotification*, | |
| 52 winui::Notifications::ToastDismissedEventArgs*> ToastDismissedHandler; | |
| 53 | |
| 54 namespace { | |
| 55 | |
| 56 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
| |
| 57 if (FAILED(hr)) { | |
| 58 if (message) | |
| 59 PLOG(DFATAL) << message << ", hr = " << std::hex << hr; | |
| 60 else | |
| 61 PLOG(DFATAL) << "COM ERROR" << ", hr = " << std::hex << hr; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 template<unsigned int size, typename T> | |
| 66 HRESULT CreateActivationFactory(wchar_t const (&class_name)[size], T** object) { | |
| 67 mswrw::HStringReference ref_class_name(class_name); | |
| 68 return winfoundtn::GetActivationFactory(ref_class_name.Get(), object); | |
| 69 } | |
| 70 | |
| 71 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;
| |
| 72 HSTRING hstr; | |
| 73 if (FAILED(::WindowsCreateString(str.c_str(), static_cast<UINT32>(str.size()), | |
| 74 &hstr))) { | |
| 75 PLOG(DFATAL) << "Hstring creation failed"; | |
| 76 } | |
| 77 return hstr; | |
| 78 } | |
| 79 | |
| 80 | |
| 81 // Helper function to return the text node root identified by the index passed | |
| 82 // in. | |
| 83 HRESULT GetTextNodeRoot( | |
| 84 unsigned int index, | |
| 85 winxml::Dom::IXmlDocument* xml_doc, | |
| 86 winxml::Dom::IXmlNode** node) { | |
| 87 DCHECK(xml_doc); | |
| 88 DCHECK(node); | |
| 89 | |
| 90 mswr::ComPtr<winxml::Dom::IXmlElement> document_element; | |
| 91 HRESULT hr = xml_doc->get_DocumentElement(&document_element); | |
| 92 CheckHR(hr); | |
| 93 | |
| 94 mswr::ComPtr<winxml::Dom::IXmlNodeList> elements; | |
| 95 mswrw::HString tag_name; | |
| 96 tag_name.Attach(MakeHString(L"text")); | |
| 97 hr = document_element->GetElementsByTagName(tag_name.Get(), | |
| 98 &elements); | |
| 99 CheckHR(hr); | |
| 100 | |
| 101 unsigned int count = 0; | |
| 102 elements->get_Length(&count); | |
| 103 | |
| 104 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.
| |
| 105 DVLOG(1) << "Invalid text node index passed in : " << index; | |
| 106 return E_FAIL; | |
| 107 } | |
| 108 hr = elements->Item(index, node); | |
| 109 CheckHR(hr); | |
| 110 return hr; | |
| 111 } | |
| 112 | |
| 113 // Helper function to append a text element to the text section in the | |
| 114 // XML document passed in. | |
| 115 // The index parameter identifies which text node we append to. | |
| 116 HRESULT CreateTextNode(winxml::Dom::IXmlDocument* xml_doc, | |
| 117 int index, | |
| 118 const base::string16& text_string) { | |
| 119 DCHECK(xml_doc); | |
| 120 | |
| 121 mswr::ComPtr<winxml::Dom::IXmlElement> document_element; | |
| 122 HRESULT hr = xml_doc->get_DocumentElement(&document_element); | |
| 123 CheckHR(hr); | |
| 124 | |
| 125 mswr::ComPtr<winxml::Dom::IXmlText> xml_text_node; | |
| 126 mswrw::HString data_hstring; | |
| 127 data_hstring.Attach(MakeHString(text_string.c_str())); | |
| 128 hr = xml_doc->CreateTextNode(data_hstring.Get(), &xml_text_node); | |
| 129 CheckHR(hr); | |
| 130 | |
| 131 mswr::ComPtr<winxml::Dom::IXmlNode> created_node; | |
| 132 hr = xml_text_node.CopyTo( | |
| 133 winxml::Dom::IID_IXmlNode, | |
| 134 reinterpret_cast<void**>(created_node.GetAddressOf())); | |
| 135 CheckHR(hr); | |
| 136 | |
| 137 mswr::ComPtr<winxml::Dom::IXmlNode> text_node_root; | |
| 138 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
| |
| 139 CheckHR(hr); | |
| 140 | |
| 141 mswr::ComPtr<winxml::Dom::IXmlNode> appended_node; | |
| 142 hr = text_node_root->AppendChild(created_node.Get(), &appended_node); | |
| 143 CheckHR(hr); | |
| 144 return hr; | |
| 145 } | |
| 146 | |
| 147 } // namespace | |
| 148 | |
| 149 // static | |
| 150 NotificationPlatformBridge* NotificationPlatformBridge::Create() { | |
| 151 return new NotificationPlatformBridgeWin(); | |
| 152 } | |
| 153 | |
| 154 NotificationPlatformBridgeWin::NotificationPlatformBridgeWin() {} | |
| 155 | |
| 156 NotificationPlatformBridgeWin::~NotificationPlatformBridgeWin() {} | |
| 157 | |
| 158 void NotificationPlatformBridgeWin::Display(const std::string& notification_id, | |
| 159 const std::string& profile_id, | |
| 160 bool incognito, | |
| 161 const Notification& notification) { | |
| 162 mswr::ComPtr<winui::Notifications::IToastNotifier> notifier_; | |
| 163 mswr::ComPtr<winui::Notifications::IToastNotification> toast_notification_; | |
| 164 | |
| 165 DCHECK(notifier_.Get() == NULL); | |
| 166 DCHECK(toast_notification_.Get() == NULL); | |
| 167 | |
| 168 mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics> | |
| 169 toast_manager; | |
| 170 | |
| 171 HRESULT hr = CreateActivationFactory( | |
| 172 RuntimeClass_Windows_UI_Notifications_ToastNotificationManager, | |
| 173 toast_manager.GetAddressOf()); | |
| 174 CheckHR(hr); | |
| 175 | |
| 176 mswr::ComPtr<winxml::Dom::IXmlDocument> toast_xml; | |
| 177 hr = toast_manager->GetTemplateContent( | |
| 178 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
| |
| 179 &toast_xml); | |
| 180 CheckHR(hr); | |
| 181 | |
| 182 if (!toast_xml) | |
| 183 return; | |
| 184 | |
| 185 mswr::ComPtr<winxml::Dom::IXmlElement> document_element; | |
| 186 hr = toast_xml->get_DocumentElement(&document_element); | |
| 187 CheckHR(hr); | |
| 188 | |
| 189 if (!document_element) | |
| 190 return; | |
| 191 | |
| 192 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
| |
| 193 CheckHR(hr); | |
| 194 | |
| 195 hr = CreateTextNode(toast_xml.Get(), 1, notification.message()); | |
|
chrisha
2016/06/02 21:14:10
Ditto '1'? Maybe make these constants describing w
| |
| 196 CheckHR(hr); | |
| 197 | |
| 198 mswrw::HString duration_attribute_name; | |
| 199 duration_attribute_name.Attach(MakeHString(L"duration")); | |
| 200 mswrw::HString duration_attribute_value; | |
| 201 duration_attribute_value.Attach(MakeHString(L"long")); | |
| 202 | |
| 203 hr = document_element->SetAttribute(duration_attribute_name.Get(), | |
| 204 duration_attribute_value.Get()); | |
| 205 CheckHR(hr); | |
| 206 | |
| 207 // TODO(ananta) | |
| 208 // We should set the image and launch params attribute in the notification | |
| 209 // XNL as described here: http://msdn.microsoft.com/en-us/library/hh465448 | |
| 210 // To set the image we may have to extract the image and specify it in the | |
| 211 // following url form. ms-appx:///images/foo.png | |
| 212 // The launch params as described don't get passed back to us via the | |
| 213 // winapp::Activation::ILaunchActivatedEventArgs argument. Needs to be | |
| 214 // investigated. | |
| 215 mswr::ComPtr<winui::Notifications::IToastNotificationFactory> | |
| 216 toast_notification_factory; | |
| 217 hr = CreateActivationFactory( | |
| 218 RuntimeClass_Windows_UI_Notifications_ToastNotification, | |
| 219 toast_notification_factory.GetAddressOf()); | |
| 220 CheckHR(hr); | |
| 221 | |
| 222 hr = toast_notification_factory->CreateToastNotification( | |
| 223 toast_xml.Get(), &toast_notification_); | |
| 224 CheckHR(hr); | |
| 225 | |
| 226 base::FilePath chrome_path; | |
| 227 if (!PathService::Get(base::FILE_EXE, &chrome_path)) { | |
| 228 NOTREACHED() << "Failed to get chrome exe path"; | |
| 229 return; | |
| 230 } | |
| 231 | |
| 232 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 233 bool is_per_user_install = InstallUtil::IsPerUserInstall(chrome_path); | |
| 234 base::string16 appid = | |
| 235 ShellUtil::GetBrowserModelId(dist, is_per_user_install); | |
| 236 DVLOG(1) << "Chrome Appid is " << appid.c_str(); | |
| 237 | |
| 238 mswrw::HString app_user_model_id; | |
| 239 app_user_model_id.Attach(MakeHString(appid)); | |
| 240 | |
| 241 hr = toast_manager->CreateToastNotifierWithId(app_user_model_id.Get(), | |
| 242 ¬ifier_); | |
| 243 CheckHR(hr); | |
| 244 | |
| 245 EventRegistrationToken activated_token_; | |
| 246 hr = toast_notification_->add_Activated( | |
| 247 mswr::Callback<ToastActivationHandler>( | |
| 248 this, &NotificationPlatformBridgeWin::OnActivate).Get(), | |
| 249 &activated_token_); | |
| 250 CheckHR(hr); | |
| 251 | |
| 252 hr = notifier_->Show(toast_notification_.Get()); | |
| 253 CheckHR(hr); | |
| 254 } | |
| 255 | |
| 256 void NotificationPlatformBridgeWin::Close( | |
| 257 const std::string& profile_id, | |
| 258 const std::string& notification_id) { | |
| 259 // TODO(huangs): Implement. | |
| 260 } | |
| 261 | |
| 262 bool NotificationPlatformBridgeWin::GetDisplayed( | |
| 263 const std::string& profile_id, | |
| 264 bool incognito, | |
| 265 std::set<std::string>* notifications) const { | |
| 266 // TODO(huangs): Implement. | |
|
Peter Beverloo
2016/06/07 15:48:29
Do you expect any issues in supporting these two T
| |
| 267 return true; | |
| 268 } | |
| 269 | |
| 270 bool NotificationPlatformBridgeWin::SupportsNotificationCenter() const { | |
| 271 return true; | |
| 272 } | |
| 273 | |
| 274 HRESULT NotificationPlatformBridgeWin::OnActivate( | |
| 275 winui::Notifications::IToastNotification* notification, | |
| 276 IInspectable* inspectable) { | |
| 277 return S_OK; | |
| 278 } | |
| OLD | NEW |