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. 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. 65 HRESULT CreateTextNode(winxml::Dom::IXmlDocument* xml_doc, 66 int index, 67 const 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 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 118 ToastNotificationHandler::DesktopNotification::DesktopNotification() 119 : notification_handler(NULL) { 120 } 121 122 ToastNotificationHandler::ToastNotificationHandler() { 123 DVLOG(1) << __FUNCTION__; 124 } 125 126 ToastNotificationHandler::~ToastNotificationHandler() { 127 DVLOG(1) << __FUNCTION__; 128 129 if (notifier_ && notification_) 130 CancelNotification(); 131 } 132 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(), ¬ification_); 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 string16 appid = ShellUtil::GetBrowserModelId(dist, is_per_user_install); 210 DVLOG(1) << "Chrome Appid is " << appid.c_str(); 211 212 mswrw::HString app_user_model_id; 213 app_user_model_id.Attach(MakeHString(appid)); 214 215 hr = toast_manager->CreateToastNotifierWithId(app_user_model_id.Get(), 216 ¬ifier_); 217 CheckHR(hr); 218 219 hr = notification_->add_Activated( 220 mswr::Callback<ToastActivationHandler>( 221 this, &ToastNotificationHandler::OnActivate).Get(), 222 &activated_token_); 223 CheckHR(hr); 224 225 hr = notifier_->Show(notification_.Get()); 226 CheckHR(hr); 227 } 228 229 void ToastNotificationHandler::CancelNotification() { 230 DVLOG(1) << __FUNCTION__; 231 232 DCHECK(notifier_); 233 DCHECK(notification_); 234 235 notifier_->Hide(notification_.Get()); 236 } 237 238 HRESULT ToastNotificationHandler::OnActivate( 239 winui::Notifications::IToastNotification* notification, 240 IInspectable* inspectable) { 241 // TODO(ananta) 242 // We should pass back information from the notification like the source url 243 // etc to ChromeAppView which would enable it to ensure that the 244 // correct tab in chrome is activated. 245 DVLOG(1) << __FUNCTION__; 246 247 if (notification_info_.notification_handler) { 248 notification_info_.notification_handler( 249 notification_info_.notification_context.c_str()); 250 } 251 return S_OK; 252 } 253