1// Copyright 2014 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 "chrome/browser/chromeos/net/network_portal_notification_controller.h"
6
7#include "ash/shell.h"
8#include "ash/system/system_notifier.h"
9#include "ash/system/tray/system_tray_notifier.h"
10#include "base/basictypes.h"
11#include "base/command_line.h"
12#include "base/compiler_specific.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/message_loop/message_loop.h"
15#include "base/metrics/histogram.h"
16#include "base/strings/string16.h"
17#include "base/strings/utf_string_conversions.h"
18#include "chrome/browser/chromeos/mobile/mobile_activator.h"
19#include "chrome/browser/profiles/profile_manager.h"
20#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
21#include "chrome/browser/ui/singleton_tabs.h"
22#include "chrome/grit/generated_resources.h"
23#include "chrome/grit/theme_resources.h"
24#include "chromeos/chromeos_switches.h"
25#include "chromeos/network/network_state.h"
26#include "components/captive_portal/captive_portal_detector.h"
27#include "ui/base/l10n/l10n_util.h"
28#include "ui/base/resource/resource_bundle.h"
29#include "ui/message_center/message_center.h"
30#include "ui/message_center/notification.h"
31#include "ui/message_center/notification_types.h"
32#include "ui/message_center/notifier_settings.h"
33
34using message_center::Notification;
35
36namespace chromeos {
37
38namespace {
39
40bool IsPortalNotificationEnabled() {
41  return !CommandLine::ForCurrentProcess()->HasSwitch(
42      switches::kDisableNetworkPortalNotification);
43}
44
45
46void CloseNotification() {
47  message_center::MessageCenter::Get()->RemoveNotification(
48      NetworkPortalNotificationController::kNotificationId, false);
49}
50
51class NetworkPortalNotificationControllerDelegate
52    : public message_center::NotificationDelegate {
53 public:
54  NetworkPortalNotificationControllerDelegate(): clicked_(false) {}
55
56  // Overridden from message_center::NotificationDelegate:
57  virtual void Display() OVERRIDE;
58  virtual void Error() OVERRIDE;
59  virtual void Close(bool by_user) OVERRIDE;
60  virtual void Click() OVERRIDE;
61
62 private:
63  virtual ~NetworkPortalNotificationControllerDelegate() {}
64
65  bool clicked_;
66
67  DISALLOW_COPY_AND_ASSIGN(NetworkPortalNotificationControllerDelegate);
68};
69
70void NetworkPortalNotificationControllerDelegate::Display() {
71  UMA_HISTOGRAM_ENUMERATION(
72      NetworkPortalNotificationController::kNotificationMetric,
73      NetworkPortalNotificationController::NOTIFICATION_METRIC_DISPLAYED,
74      NetworkPortalNotificationController::NOTIFICATION_METRIC_COUNT);
75}
76
77void NetworkPortalNotificationControllerDelegate::Error() {
78  UMA_HISTOGRAM_ENUMERATION(
79      NetworkPortalNotificationController::kNotificationMetric,
80      NetworkPortalNotificationController::NOTIFICATION_METRIC_ERROR,
81      NetworkPortalNotificationController::NOTIFICATION_METRIC_COUNT);
82}
83
84void NetworkPortalNotificationControllerDelegate::Close(bool by_user) {
85  if (clicked_)
86    return;
87  NetworkPortalNotificationController::UserActionMetric metric =
88      by_user
89      ? NetworkPortalNotificationController::USER_ACTION_METRIC_CLOSED
90      : NetworkPortalNotificationController::USER_ACTION_METRIC_IGNORED;
91  UMA_HISTOGRAM_ENUMERATION(
92      NetworkPortalNotificationController::kUserActionMetric,
93      metric,
94      NetworkPortalNotificationController::USER_ACTION_METRIC_COUNT);
95}
96
97void NetworkPortalNotificationControllerDelegate::Click() {
98  clicked_ = true;
99  UMA_HISTOGRAM_ENUMERATION(
100      NetworkPortalNotificationController::kUserActionMetric,
101      NetworkPortalNotificationController::USER_ACTION_METRIC_CLICKED,
102      NetworkPortalNotificationController::USER_ACTION_METRIC_COUNT);
103
104  Profile* profile = ProfileManager::GetActiveUserProfile();
105  if (!profile)
106    return;
107  chrome::ScopedTabbedBrowserDisplayer displayer(profile,
108                                                 chrome::HOST_DESKTOP_TYPE_ASH);
109  GURL url(captive_portal::CaptivePortalDetector::kDefaultURL);
110  chrome::ShowSingletonTab(displayer.browser(), url);
111
112  CloseNotification();
113}
114
115}  // namespace
116
117// static
118const char NetworkPortalNotificationController::kNotificationId[] =
119    "chrome://net/network_portal_detector";
120
121// static
122const char NetworkPortalNotificationController::kNotificationMetric[] =
123    "CaptivePortal.Notification.Status";
124
125// static
126const char NetworkPortalNotificationController::kUserActionMetric[] =
127    "CaptivePortal.Notification.UserAction";
128
129NetworkPortalNotificationController::NetworkPortalNotificationController() {}
130
131NetworkPortalNotificationController::~NetworkPortalNotificationController() {}
132
133void NetworkPortalNotificationController::OnPortalDetectionCompleted(
134    const NetworkState* network,
135    const NetworkPortalDetector::CaptivePortalState& state) {
136  if (!IsPortalNotificationEnabled())
137    return;
138
139  if (!network ||
140      state.status != NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL) {
141    last_network_path_.clear();
142    CloseNotification();
143    return;
144  }
145
146  // Don't do anything if we're currently activating the device.
147  if (MobileActivator::GetInstance()->RunningActivation())
148    return;
149
150  // Don't do anything if notification for |network| already was
151  // displayed.
152  if (network->path() == last_network_path_)
153    return;
154  last_network_path_ = network->path();
155
156  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
157  gfx::Image& icon = bundle.GetImageNamed(IDR_PORTAL_DETECTION_ALERT);
158  message_center::NotifierId notifier_id(
159      message_center::NotifierId::SYSTEM_COMPONENT,
160      ash::system_notifier::kNotifierNetworkPortalDetector);
161
162  scoped_ptr<Notification> notification(new Notification(
163      message_center::NOTIFICATION_TYPE_SIMPLE,
164      kNotificationId,
165      l10n_util::GetStringUTF16(IDS_PORTAL_DETECTION_NOTIFICATION_TITLE),
166      l10n_util::GetStringFUTF16(IDS_PORTAL_DETECTION_NOTIFICATION_MESSAGE,
167                                 base::UTF8ToUTF16(network->name())),
168      icon,
169      base::string16() /* display_source */,
170      notifier_id,
171      message_center::RichNotificationData(),
172      new NetworkPortalNotificationControllerDelegate()));
173  notification->SetSystemPriority();
174
175  if (ash::Shell::HasInstance()) {
176    ash::Shell::GetInstance()
177        ->system_tray_notifier()
178        ->NotifyOnCaptivePortalDetected(network->path());
179  }
180
181  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
182}
183
184}  // namespace chromeos
185