chromium/chrome/browser/notifications/win/notification_util.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/notifications/win/notification_util.h"

#include <wrl/client.h>

#include "base/logging.h"
#include "base/win/scoped_hstring.h"
#include "chrome/browser/notifications/win/notification_launch_id.h"
#include "chrome/browser/notifications/win/notification_metrics.h"
#include "chrome/browser/notifications/win/notification_template_builder.h"

namespace mswr = Microsoft::WRL;
namespace winfoundtn = ABI::Windows::Foundation;
namespace winui = ABI::Windows::UI;
namespace winxml = ABI::Windows::Data::Xml;

using notifications_uma::GetNotificationLaunchIdStatus;
using base::win::ScopedHString;

NotificationLaunchId GetNotificationLaunchId(
    winui::Notifications::IToastNotification* notification) {
  mswr::ComPtr<winxml::Dom::IXmlDocument> document;
  HRESULT hr = notification->get_Content(&document);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kNotificationGetContentFailed);
    DLOG(ERROR) << "Failed to get XML document";
    return NotificationLaunchId();
  }

  ScopedHString tag = ScopedHString::Create(kNotificationToastElement);
  mswr::ComPtr<winxml::Dom::IXmlNodeList> elements;
  hr = document->GetElementsByTagName(tag.get(), &elements);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetElementsByTagFailed);
    DLOG(ERROR) << "Failed to get <toast> elements from document";
    return NotificationLaunchId();
  }

  UINT32 length;
  hr = elements->get_Length(&length);
  if (FAILED(hr) || length == 0) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kMissingToastElementInDoc);
    DLOG(ERROR) << "No <toast> elements in document.";
    return NotificationLaunchId();
  }

  mswr::ComPtr<winxml::Dom::IXmlNode> node;
  hr = elements->Item(0, &node);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kItemAtFailed);
    DLOG(ERROR) << "Failed to get first <toast> element";
    return NotificationLaunchId();
  }

  mswr::ComPtr<winxml::Dom::IXmlNamedNodeMap> attributes;
  hr = node->get_Attributes(&attributes);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetAttributesFailed);
    DLOG(ERROR) << "Failed to get attributes of <toast>";
    return NotificationLaunchId();
  }

  mswr::ComPtr<winxml::Dom::IXmlNode> leaf;
  ScopedHString id = ScopedHString::Create(kNotificationLaunchAttribute);
  hr = attributes->GetNamedItem(id.get(), &leaf);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetNamedItemFailed);
    DLOG(ERROR) << "Failed to get launch attribute of <toast>";
    return NotificationLaunchId();
  }

  if (!leaf) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetNamedItemNull);
    DLOG(ERROR) << "GetNamedItem returned null querying for 'launch' attribute";
    return NotificationLaunchId();
  }

  mswr::ComPtr<winxml::Dom::IXmlNode> child;
  hr = leaf->get_FirstChild(&child);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetFirstChildFailed);
    DLOG(ERROR) << "Failed to get content of launch attribute";
    return NotificationLaunchId();
  }

  if (!child) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetFirstChildNull);
    DLOG(ERROR) << "Launch attribute is a null node";
    return NotificationLaunchId();
  }

  mswr::ComPtr<IInspectable> inspectable;
  hr = child->get_NodeValue(&inspectable);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetNodeValueFailed);
    DLOG(ERROR) << "Failed to get node value of launch attribute";
    return NotificationLaunchId();
  }

  mswr::ComPtr<winfoundtn::IPropertyValue> property_value;
  hr = inspectable.As<winfoundtn::IPropertyValue>(&property_value);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kConversionToPropValueFailed);
    DLOG(ERROR) << "Failed to convert node value of launch attribute";
    return NotificationLaunchId();
  }

  HSTRING value_hstring;
  hr = property_value->GetString(&value_hstring);
  if (FAILED(hr)) {
    LogGetNotificationLaunchIdStatus(
        GetNotificationLaunchIdStatus::kGetStringFailed);
    DLOG(ERROR) << "Failed to get string for launch attribute";
    return NotificationLaunchId();
  }

  LogGetNotificationLaunchIdStatus(GetNotificationLaunchIdStatus::kSuccess);

  ScopedHString value(value_hstring);
  return NotificationLaunchId(value.GetAsUTF8());
}