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 |