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