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 #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 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 
     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(), &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 
    230 void ToastNotificationHandler::CancelNotification() {
    231   DVLOG(1) << __FUNCTION__;
    232 
    233   DCHECK(notifier_);
    234   DCHECK(notification_);
    235 
    236   notifier_->Hide(notification_.Get());
    237 }
    238 
    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