Home | History | Annotate | Download | only in metro_driver
      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(), &notification_);
    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                                                 &notifier_);
    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