• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 <string>
6 
7 #include "win8/metro_driver/stdafx.h"
8 #include "win8/metro_driver/toast_notification_handler.h"
9 
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/installer/util/browser_distribution.h"
15 #include "chrome/installer/util/install_util.h"
16 #include "chrome/installer/util/shell_util.h"
17 
18 #include "win8/metro_driver/winrt_utils.h"
19 
20 typedef winfoundtn::ITypedEventHandler<
21     winui::Notifications::ToastNotification*, IInspectable*>
22     ToastActivationHandler;
23 
24 typedef winfoundtn::ITypedEventHandler<
25     winui::Notifications::ToastNotification*,
26     winui::Notifications::ToastDismissedEventArgs*> ToastDismissedHandler;
27 
28 namespace {
29 
30 // Helper function to return the text node root identified by the index passed
31 // in.
GetTextNodeRoot(unsigned int index,winxml::Dom::IXmlDocument * xml_doc,winxml::Dom::IXmlNode ** node)32 HRESULT GetTextNodeRoot(
33     unsigned int index,
34     winxml::Dom::IXmlDocument* xml_doc,
35     winxml::Dom::IXmlNode** node) {
36   DCHECK(xml_doc);
37   DCHECK(node);
38 
39   mswr::ComPtr<winxml::Dom::IXmlElement> document_element;
40   HRESULT hr = xml_doc->get_DocumentElement(&document_element);
41   CheckHR(hr);
42 
43   mswr::ComPtr<winxml::Dom::IXmlNodeList> elements;
44   mswrw::HString tag_name;
45   tag_name.Attach(MakeHString(L"text"));
46   hr = document_element->GetElementsByTagName(tag_name.Get(),
47                                               &elements);
48   CheckHR(hr);
49 
50   unsigned int count = 0;
51   elements->get_Length(&count);
52 
53   if (index > count) {
54     DVLOG(1) << "Invalid text node index passed in : " << index;
55     return E_FAIL;
56   }
57   hr = elements->Item(index, node);
58   CheckHR(hr);
59   return hr;
60 }
61 
62 // Helper function to append a text element to the text section in the
63 // XML document passed in.
64 // The index parameter identifies which text node we append to.
CreateTextNode(winxml::Dom::IXmlDocument * xml_doc,int index,const base::string16 & text_string)65 HRESULT CreateTextNode(winxml::Dom::IXmlDocument* xml_doc,
66                        int index,
67                        const base::string16& text_string) {
68   DCHECK(xml_doc);
69 
70   mswr::ComPtr<winxml::Dom::IXmlElement> document_element;
71   HRESULT hr = xml_doc->get_DocumentElement(&document_element);
72   CheckHR(hr);
73 
74   mswr::ComPtr<winxml::Dom::IXmlText> xml_text_node;
75   mswrw::HString data_hstring;
76   data_hstring.Attach(MakeHString(text_string.c_str()));
77   hr = xml_doc->CreateTextNode(data_hstring.Get(), &xml_text_node);
78   CheckHR(hr);
79 
80   mswr::ComPtr<winxml::Dom::IXmlNode> created_node;
81   hr = xml_text_node.CopyTo(
82       winxml::Dom::IID_IXmlNode,
83       reinterpret_cast<void**>(created_node.GetAddressOf()));
84   CheckHR(hr);
85 
86   mswr::ComPtr<winxml::Dom::IXmlNode> text_node_root;
87   hr = GetTextNodeRoot(index, xml_doc, &text_node_root);
88   CheckHR(hr);
89 
90   mswr::ComPtr<winxml::Dom::IXmlNode> appended_node;
91   hr = text_node_root->AppendChild(created_node.Get(), &appended_node);
92   CheckHR(hr);
93   return hr;
94 }
95 
96 }  // namespace
97 
DesktopNotification(const char * notification_origin,const char * notification_icon,const wchar_t * notification_title,const wchar_t * notification_body,const wchar_t * notification_display_source,const char * notification_id,base::win::MetroNotificationClickedHandler handler,const wchar_t * handler_context)98 ToastNotificationHandler::DesktopNotification::DesktopNotification(
99     const char* notification_origin,
100     const char* notification_icon,
101     const wchar_t* notification_title,
102     const wchar_t* notification_body,
103     const wchar_t* notification_display_source,
104     const char* notification_id,
105     base::win::MetroNotificationClickedHandler handler,
106     const wchar_t* handler_context)
107     : origin_url(notification_origin),
108       icon_url(notification_icon),
109       title(notification_title),
110       body(notification_body),
111       display_source(notification_display_source),
112       id(notification_id),
113       notification_handler(handler) {
114   if (handler_context)
115     notification_context = handler_context;
116 }
117 
DesktopNotification()118 ToastNotificationHandler::DesktopNotification::DesktopNotification()
119     : notification_handler(NULL) {
120 }
121 
ToastNotificationHandler()122 ToastNotificationHandler::ToastNotificationHandler() {
123   DVLOG(1) << __FUNCTION__;
124 }
125 
~ToastNotificationHandler()126 ToastNotificationHandler::~ToastNotificationHandler() {
127   DVLOG(1) << __FUNCTION__;
128 
129   if (notifier_ && notification_)
130     CancelNotification();
131 }
132 
DisplayNotification(const DesktopNotification & notification)133 void ToastNotificationHandler::DisplayNotification(
134     const DesktopNotification& notification) {
135   DVLOG(1) << __FUNCTION__;
136 
137   DCHECK(notifier_.Get() == NULL);
138   DCHECK(notification_.Get() == NULL);
139 
140   notification_info_ = notification;
141 
142   mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics>
143       toast_manager;
144 
145   HRESULT hr = winrt_utils::CreateActivationFactory(
146       RuntimeClass_Windows_UI_Notifications_ToastNotificationManager,
147       toast_manager.GetAddressOf());
148   CheckHR(hr);
149 
150   mswr::ComPtr<winxml::Dom::IXmlDocument> toast_xml;
151   hr = toast_manager->GetTemplateContent(
152       winui::Notifications::ToastTemplateType_ToastText02,
153       &toast_xml);
154   CheckHR(hr);
155 
156   if (!toast_xml)
157     return;
158 
159   mswr::ComPtr<winxml::Dom::IXmlElement> document_element;
160   hr = toast_xml->get_DocumentElement(&document_element);
161   CheckHR(hr);
162 
163   if (!document_element)
164     return;
165 
166   hr = CreateTextNode(toast_xml.Get(), 0, notification.title);
167   CheckHR(hr);
168 
169   hr = CreateTextNode(toast_xml.Get(), 1, notification.body);
170   CheckHR(hr);
171 
172   mswrw::HString duration_attribute_name;
173   duration_attribute_name.Attach(MakeHString(L"duration"));
174   mswrw::HString duration_attribute_value;
175   duration_attribute_value.Attach(MakeHString(L"long"));
176 
177   hr = document_element->SetAttribute(duration_attribute_name.Get(),
178                                       duration_attribute_value.Get());
179   CheckHR(hr);
180 
181   // TODO(ananta)
182   // We should set the image and launch params attribute in the notification
183   // XNL as described here: http://msdn.microsoft.com/en-us/library/hh465448
184   // To set the image we may have to extract the image and specify it in the
185   // following url form. ms-appx:///images/foo.png
186   // The launch params as described don't get passed back to us via the
187   // winapp::Activation::ILaunchActivatedEventArgs argument. Needs to be
188   // investigated.
189   mswr::ComPtr<winui::Notifications::IToastNotificationFactory>
190       toast_notification_factory;
191   hr = winrt_utils::CreateActivationFactory(
192       RuntimeClass_Windows_UI_Notifications_ToastNotification,
193       toast_notification_factory.GetAddressOf());
194   CheckHR(hr);
195 
196   hr = toast_notification_factory->CreateToastNotification(
197       toast_xml.Get(), &notification_);
198   CheckHR(hr);
199 
200   base::FilePath chrome_path;
201   if (!PathService::Get(base::FILE_EXE, &chrome_path)) {
202     NOTREACHED() << "Failed to get chrome exe path";
203     return;
204   }
205 
206   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
207   bool is_per_user_install = InstallUtil::IsPerUserInstall(
208       chrome_path.value().c_str());
209   base::string16 appid =
210       ShellUtil::GetBrowserModelId(dist, is_per_user_install);
211   DVLOG(1) << "Chrome Appid is " << appid.c_str();
212 
213   mswrw::HString app_user_model_id;
214   app_user_model_id.Attach(MakeHString(appid));
215 
216   hr = toast_manager->CreateToastNotifierWithId(app_user_model_id.Get(),
217                                                 &notifier_);
218   CheckHR(hr);
219 
220   hr = notification_->add_Activated(
221       mswr::Callback<ToastActivationHandler>(
222           this, &ToastNotificationHandler::OnActivate).Get(),
223       &activated_token_);
224   CheckHR(hr);
225 
226   hr = notifier_->Show(notification_.Get());
227   CheckHR(hr);
228 }
229 
CancelNotification()230 void ToastNotificationHandler::CancelNotification() {
231   DVLOG(1) << __FUNCTION__;
232 
233   DCHECK(notifier_);
234   DCHECK(notification_);
235 
236   notifier_->Hide(notification_.Get());
237 }
238 
OnActivate(winui::Notifications::IToastNotification * notification,IInspectable * inspectable)239 HRESULT ToastNotificationHandler::OnActivate(
240     winui::Notifications::IToastNotification* notification,
241     IInspectable* inspectable) {
242   // TODO(ananta)
243   // We should pass back information from the notification like the source url
244   // etc to ChromeAppView which would enable it to ensure that the
245   // correct tab in chrome is activated.
246   DVLOG(1) << __FUNCTION__;
247 
248   if (notification_info_.notification_handler) {
249     notification_info_.notification_handler(
250         notification_info_.notification_context.c_str());
251   }
252   return S_OK;
253 }
254