network_state_notifier.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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 "ash/system/chromeos/network/network_state_notifier.h"
6
7#include "ash/shell.h"
8#include "ash/system/chromeos/network/network_connect.h"
9#include "ash/system/system_notifier.h"
10#include "ash/system/tray/system_tray_delegate.h"
11#include "base/strings/string16.h"
12#include "base/strings/string_util.h"
13#include "base/strings/utf_string_conversions.h"
14#include "chromeos/network/network_configuration_handler.h"
15#include "chromeos/network/network_connection_handler.h"
16#include "chromeos/network/network_event_log.h"
17#include "chromeos/network/network_state.h"
18#include "chromeos/network/network_state_handler.h"
19#include "grit/ash_resources.h"
20#include "grit/ash_strings.h"
21#include "third_party/cros_system_api/dbus/service_constants.h"
22#include "ui/base/l10n/l10n_util.h"
23#include "ui/base/resource/resource_bundle.h"
24#include "ui/message_center/message_center.h"
25#include "ui/message_center/notification.h"
26
27using chromeos::NetworkConnectionHandler;
28using chromeos::NetworkHandler;
29using chromeos::NetworkState;
30using chromeos::NetworkStateHandler;
31
32namespace {
33
34const char kNetworkOutOfCreditsNotificationId[] =
35    "chrome://settings/internet/out-of-credits";
36
37const int kMinTimeBetweenOutOfCreditsNotifySeconds = 10 * 60;
38
39// Error messages based on |error_name|, not network_state->error().
40string16 GetConnectErrorString(const std::string& error_name) {
41  if (error_name == NetworkConnectionHandler::kErrorNotFound)
42    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED);
43  if (error_name == NetworkConnectionHandler::kErrorConfigureFailed)
44    return l10n_util::GetStringUTF16(
45        IDS_CHROMEOS_NETWORK_ERROR_CONFIGURE_FAILED);
46  if (error_name == NetworkConnectionHandler::kErrorActivateFailed)
47    return l10n_util::GetStringUTF16(
48        IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
49  return string16();
50}
51
52void ShowErrorNotification(const std::string& notification_id,
53                           const std::string& network_type,
54                           const base::string16& title,
55                           const base::string16& message,
56                           const base::Closure& callback) {
57  int icon_id = (network_type == flimflam::kTypeCellular) ?
58      IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED :
59      IDR_AURA_UBER_TRAY_NETWORK_FAILED;
60  const gfx::Image& icon =
61      ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
62  message_center::MessageCenter::Get()->AddNotification(
63      message_center::Notification::CreateSystemNotification(
64          notification_id,
65          title,
66          message,
67          icon,
68          ash::NOTIFIER_NETWORK_ERROR,
69          callback));
70}
71
72void ConfigureNetwork(const std::string& service_path) {
73  ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork(
74      service_path);
75}
76
77}  // namespace
78
79namespace ash {
80
81NetworkStateNotifier::NetworkStateNotifier()
82    : did_show_out_of_credits_(false),
83      weak_ptr_factory_(this) {
84  if (!NetworkHandler::IsInitialized())
85    return;
86  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
87  handler->AddObserver(this, FROM_HERE);
88  UpdateDefaultNetwork(handler->DefaultNetwork());
89}
90
91NetworkStateNotifier::~NetworkStateNotifier() {
92  if (!NetworkHandler::IsInitialized())
93    return;
94  NetworkHandler::Get()->network_state_handler()->RemoveObserver(
95      this, FROM_HERE);
96}
97
98void NetworkStateNotifier::DefaultNetworkChanged(const NetworkState* network) {
99  if (!UpdateDefaultNetwork(network))
100    return;
101  // If the default network changes to another network, allow the out of
102  // credits notification to be shown again. A delay prevents the notification
103  // from being shown too frequently (see below).
104  if (network)
105    did_show_out_of_credits_ = false;
106}
107
108void NetworkStateNotifier::NetworkPropertiesUpdated(
109    const NetworkState* network) {
110  if (network->type() != flimflam::kTypeCellular)
111    return;
112  UpdateCellularOutOfCredits(network);
113  UpdateCellularActivating(network);
114}
115
116bool NetworkStateNotifier::UpdateDefaultNetwork(const NetworkState* network) {
117  std::string default_network_path;
118  if (network)
119    default_network_path = network->path();
120  if (default_network_path != last_default_network_) {
121    last_default_network_ = default_network_path;
122    return true;
123  }
124  return false;
125}
126
127void NetworkStateNotifier::UpdateCellularOutOfCredits(
128    const NetworkState* cellular) {
129  // Only display a notification if we are out of credits and have not already
130  // shown a notification (or have since connected to another network type).
131  if (!cellular->cellular_out_of_credits() || did_show_out_of_credits_)
132    return;
133
134  // Only display a notification if not connected, connecting, or waiting to
135  // connect to another network.
136  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
137  const NetworkState* default_network = handler->DefaultNetwork();
138  if (default_network && default_network != cellular)
139    return;
140  if (handler->ConnectingNetworkByType(
141          NetworkStateHandler::kMatchTypeNonVirtual) ||
142      NetworkHandler::Get()->network_connection_handler()
143          ->HasPendingConnectRequest())
144    return;
145
146  did_show_out_of_credits_ = true;
147  base::TimeDelta dtime = base::Time::Now() - out_of_credits_notify_time_;
148  if (dtime.InSeconds() > kMinTimeBetweenOutOfCreditsNotifySeconds) {
149    out_of_credits_notify_time_ = base::Time::Now();
150    string16 error_msg = l10n_util::GetStringFUTF16(
151        IDS_NETWORK_OUT_OF_CREDITS_BODY,
152        UTF8ToUTF16(cellular->name()));
153    ShowErrorNotification(
154        kNetworkOutOfCreditsNotificationId,
155        cellular->type(),
156        l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE),
157        error_msg,
158        base::Bind(&ConfigureNetwork, cellular->path()));
159  }
160}
161
162void NetworkStateNotifier::UpdateCellularActivating(
163    const NetworkState* cellular) {
164  // Keep track of any activating cellular network.
165  std::string activation_state = cellular->activation_state();
166  if (activation_state == flimflam::kActivationStateActivating) {
167    cellular_activating_.insert(cellular->path());
168    return;
169  }
170  // Only display a notification if this network was activating and is now
171  // activated.
172  if (!cellular_activating_.count(cellular->path()) ||
173      activation_state != flimflam::kActivationStateActivated)
174    return;
175
176  cellular_activating_.erase(cellular->path());
177  int icon_id;
178  if (cellular->network_technology() == flimflam::kNetworkTechnologyLte)
179    icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_LTE;
180  else
181    icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_3G;
182  const gfx::Image& icon =
183      ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
184  message_center::MessageCenter::Get()->AddNotification(
185      message_center::Notification::CreateSystemNotification(
186          ash::network_connect::kNetworkActivateNotificationId,
187          l10n_util::GetStringUTF16(IDS_NETWORK_CELLULAR_ACTIVATED_TITLE),
188          l10n_util::GetStringFUTF16(IDS_NETWORK_CELLULAR_ACTIVATED,
189                                     UTF8ToUTF16((cellular->name()))),
190          icon,
191          NOTIFIER_NETWORK,
192          base::Bind(&ash::network_connect::ShowNetworkSettings,
193                     cellular->path())));
194}
195
196void NetworkStateNotifier::ShowNetworkConnectError(
197    const std::string& error_name,
198    const std::string& service_path) {
199  if (service_path.empty()) {
200    base::DictionaryValue shill_properties;
201    ShowConnectErrorNotification(error_name, service_path, shill_properties);
202    return;
203  }
204  // Get the up-to-date properties for the network and display the error.
205  NetworkHandler::Get()->network_configuration_handler()->GetProperties(
206      service_path,
207      base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesSucceeded,
208                 weak_ptr_factory_.GetWeakPtr(), error_name),
209      base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesFailed,
210                 weak_ptr_factory_.GetWeakPtr(), error_name, service_path));
211}
212
213void NetworkStateNotifier::ConnectErrorPropertiesSucceeded(
214    const std::string& error_name,
215    const std::string& service_path,
216    const base::DictionaryValue& shill_properties) {
217  ShowConnectErrorNotification(error_name, service_path, shill_properties);
218}
219
220void NetworkStateNotifier::ConnectErrorPropertiesFailed(
221    const std::string& error_name,
222    const std::string& service_path,
223    const std::string& shill_error_name,
224    scoped_ptr<base::DictionaryValue> shill_error_data) {
225  base::DictionaryValue shill_properties;
226  ShowConnectErrorNotification(error_name, service_path, shill_properties);
227}
228
229void NetworkStateNotifier::ShowConnectErrorNotification(
230    const std::string& error_name,
231    const std::string& service_path,
232    const base::DictionaryValue& shill_properties) {
233  string16 error = GetConnectErrorString(error_name);
234  if (error.empty()) {
235    std::string network_error;
236    shill_properties.GetStringWithoutPathExpansion(
237        flimflam::kErrorProperty, &network_error);
238    error = network_connect::ErrorString(network_error);
239    if (error.empty())
240      error = l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
241  }
242  NET_LOG_ERROR("Connect error notification: " + UTF16ToUTF8(error),
243                service_path);
244
245  std::string network_name =
246      NetworkState::GetNameFromProperties(service_path, shill_properties);
247  std::string network_error_details;
248  shill_properties.GetStringWithoutPathExpansion(
249        shill::kErrorDetailsProperty, &network_error_details);
250
251  string16 error_msg;
252  if (!network_error_details.empty()) {
253    // network_name should't be empty if network_error_details is set.
254    error_msg = l10n_util::GetStringFUTF16(
255        IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_SERVER_MESSAGE,
256        UTF8ToUTF16(network_name), error,
257        UTF8ToUTF16(network_error_details));
258  } else if (network_name.empty()) {
259    error_msg = l10n_util::GetStringFUTF16(
260        IDS_NETWORK_CONNECTION_ERROR_MESSAGE_NO_NAME, error);
261  } else {
262    error_msg = l10n_util::GetStringFUTF16(
263        IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
264        UTF8ToUTF16(network_name), error);
265  }
266
267  std::string network_type;
268  shill_properties.GetStringWithoutPathExpansion(
269      flimflam::kTypeProperty, &network_type);
270
271  ShowErrorNotification(
272      network_connect::kNetworkConnectNotificationId,
273      network_type,
274      l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE),
275      error_msg,
276      base::Bind(&network_connect::ShowNetworkSettings, service_path));
277}
278
279}  // namespace ash
280