Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / system / chromeos / network / network_state_notifier.cc
blobefe0bd1b7aff7ef66a6a94257321412d551dd6d8
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.
5 #include "ash/system/chromeos/network/network_state_notifier.h"
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 "chromeos/network/shill_property_util.h"
20 #include "grit/ash_resources.h"
21 #include "grit/ash_strings.h"
22 #include "grit/ui_chromeos_resources.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/message_center/message_center.h"
27 #include "ui/message_center/notification.h"
29 using chromeos::NetworkConnectionHandler;
30 using chromeos::NetworkHandler;
31 using chromeos::NetworkState;
32 using chromeos::NetworkStateHandler;
33 using chromeos::NetworkTypePattern;
35 namespace {
37 const char kNetworkOutOfCreditsNotificationId[] =
38 "chrome://settings/internet/out-of-credits";
40 const int kMinTimeBetweenOutOfCreditsNotifySeconds = 10 * 60;
42 // Ignore in-progress error.
43 bool ShillErrorIsIgnored(const std::string& shill_error) {
44 if (shill_error == shill::kErrorResultInProgress)
45 return true;
46 return false;
49 // Error messages based on |error_name|, not network_state->error().
50 base::string16 GetConnectErrorString(const std::string& error_name) {
51 if (error_name == NetworkConnectionHandler::kErrorNotFound)
52 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED);
53 if (error_name == NetworkConnectionHandler::kErrorConfigureFailed) {
54 return l10n_util::GetStringUTF16(
55 IDS_CHROMEOS_NETWORK_ERROR_CONFIGURE_FAILED);
57 if (error_name == NetworkConnectionHandler::kErrorCertLoadTimeout) {
58 return l10n_util::GetStringUTF16(
59 IDS_CHROMEOS_NETWORK_ERROR_CERTIFICATES_NOT_LOADED);
61 if (error_name == ash::network_connect::kErrorActivateFailed) {
62 return l10n_util::GetStringUTF16(
63 IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
65 return base::string16();
68 void ShowErrorNotification(const std::string& notification_id,
69 const std::string& network_type,
70 const base::string16& title,
71 const base::string16& message,
72 const base::Closure& callback) {
73 int icon_id = (network_type == shill::kTypeCellular) ?
74 IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED :
75 IDR_AURA_UBER_TRAY_NETWORK_FAILED;
76 const gfx::Image& icon =
77 ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
78 message_center::MessageCenter::Get()->AddNotification(
79 message_center::Notification::CreateSystemNotification(
80 notification_id,
81 title,
82 message,
83 icon,
84 ash::system_notifier::kNotifierNetworkError,
85 callback));
88 } // namespace
90 namespace ash {
92 NetworkStateNotifier::NetworkStateNotifier()
93 : did_show_out_of_credits_(false),
94 weak_ptr_factory_(this) {
95 if (!NetworkHandler::IsInitialized())
96 return;
97 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
98 handler->AddObserver(this, FROM_HERE);
99 UpdateDefaultNetwork(handler->DefaultNetwork());
102 NetworkStateNotifier::~NetworkStateNotifier() {
103 if (!NetworkHandler::IsInitialized())
104 return;
105 NetworkHandler::Get()->network_state_handler()->RemoveObserver(
106 this, FROM_HERE);
109 void NetworkStateNotifier::DefaultNetworkChanged(const NetworkState* network) {
110 if (!UpdateDefaultNetwork(network))
111 return;
112 // If the default network changes to another network, allow the out of
113 // credits notification to be shown again. A delay prevents the notification
114 // from being shown too frequently (see below).
115 if (network)
116 did_show_out_of_credits_ = false;
119 void NetworkStateNotifier::NetworkPropertiesUpdated(
120 const NetworkState* network) {
121 if (network->type() != shill::kTypeCellular)
122 return;
123 UpdateCellularOutOfCredits(network);
124 UpdateCellularActivating(network);
127 bool NetworkStateNotifier::UpdateDefaultNetwork(const NetworkState* network) {
128 std::string default_network_path;
129 if (network)
130 default_network_path = network->path();
131 if (default_network_path != last_default_network_) {
132 last_default_network_ = default_network_path;
133 return true;
135 return false;
138 void NetworkStateNotifier::UpdateCellularOutOfCredits(
139 const NetworkState* cellular) {
140 // Only display a notification if we are out of credits and have not already
141 // shown a notification (or have since connected to another network type).
142 if (!cellular->cellular_out_of_credits() || did_show_out_of_credits_)
143 return;
145 // Only display a notification if not connected, connecting, or waiting to
146 // connect to another network.
147 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
148 const NetworkState* default_network = handler->DefaultNetwork();
149 if (default_network && default_network != cellular)
150 return;
151 if (handler->ConnectingNetworkByType(NetworkTypePattern::NonVirtual()) ||
152 NetworkHandler::Get()->network_connection_handler()
153 ->HasPendingConnectRequest())
154 return;
156 did_show_out_of_credits_ = true;
157 base::TimeDelta dtime = base::Time::Now() - out_of_credits_notify_time_;
158 if (dtime.InSeconds() > kMinTimeBetweenOutOfCreditsNotifySeconds) {
159 out_of_credits_notify_time_ = base::Time::Now();
160 base::string16 error_msg = l10n_util::GetStringFUTF16(
161 IDS_NETWORK_OUT_OF_CREDITS_BODY,
162 base::UTF8ToUTF16(cellular->name()));
163 ShowErrorNotification(
164 kNetworkOutOfCreditsNotificationId,
165 cellular->type(),
166 l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE),
167 error_msg,
168 base::Bind(&network_connect::ShowNetworkSettings, cellular->path()));
172 void NetworkStateNotifier::UpdateCellularActivating(
173 const NetworkState* cellular) {
174 // Keep track of any activating cellular network.
175 std::string activation_state = cellular->activation_state();
176 if (activation_state == shill::kActivationStateActivating) {
177 cellular_activating_.insert(cellular->path());
178 return;
180 // Only display a notification if this network was activating and is now
181 // activated.
182 if (!cellular_activating_.count(cellular->path()) ||
183 activation_state != shill::kActivationStateActivated)
184 return;
186 cellular_activating_.erase(cellular->path());
187 int icon_id;
188 if (cellular->network_technology() == shill::kNetworkTechnologyLte)
189 icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_LTE;
190 else
191 icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_3G;
192 const gfx::Image& icon =
193 ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
194 message_center::MessageCenter::Get()->AddNotification(
195 message_center::Notification::CreateSystemNotification(
196 ash::network_connect::kNetworkActivateNotificationId,
197 l10n_util::GetStringUTF16(IDS_NETWORK_CELLULAR_ACTIVATED_TITLE),
198 l10n_util::GetStringFUTF16(IDS_NETWORK_CELLULAR_ACTIVATED,
199 base::UTF8ToUTF16((cellular->name()))),
200 icon,
201 system_notifier::kNotifierNetwork,
202 base::Bind(&ash::network_connect::ShowNetworkSettings,
203 cellular->path())));
206 void NetworkStateNotifier::ShowNetworkConnectError(
207 const std::string& error_name,
208 const std::string& service_path) {
209 if (service_path.empty()) {
210 base::DictionaryValue shill_properties;
211 ShowConnectErrorNotification(error_name, service_path, shill_properties);
212 return;
214 // Get the up-to-date properties for the network and display the error.
215 NetworkHandler::Get()->network_configuration_handler()->GetProperties(
216 service_path,
217 base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesSucceeded,
218 weak_ptr_factory_.GetWeakPtr(), error_name),
219 base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesFailed,
220 weak_ptr_factory_.GetWeakPtr(), error_name, service_path));
223 void NetworkStateNotifier::ConnectErrorPropertiesSucceeded(
224 const std::string& error_name,
225 const std::string& service_path,
226 const base::DictionaryValue& shill_properties) {
227 std::string state;
228 shill_properties.GetStringWithoutPathExpansion(shill::kStateProperty, &state);
229 if (chromeos::NetworkState::StateIsConnected(state) ||
230 chromeos::NetworkState::StateIsConnecting(state)) {
231 // Network is no longer in an error state. This can happen if an unexpected
232 // Idle state transition occurs, see crbug.com/333955.
233 return;
235 ShowConnectErrorNotification(error_name, service_path, shill_properties);
238 void NetworkStateNotifier::ConnectErrorPropertiesFailed(
239 const std::string& error_name,
240 const std::string& service_path,
241 const std::string& shill_connect_error,
242 scoped_ptr<base::DictionaryValue> shill_error_data) {
243 base::DictionaryValue shill_properties;
244 ShowConnectErrorNotification(error_name, service_path, shill_properties);
247 void NetworkStateNotifier::ShowConnectErrorNotification(
248 const std::string& error_name,
249 const std::string& service_path,
250 const base::DictionaryValue& shill_properties) {
251 base::string16 error = GetConnectErrorString(error_name);
252 if (error.empty()) {
253 std::string shill_error;
254 shill_properties.GetStringWithoutPathExpansion(shill::kErrorProperty,
255 &shill_error);
256 if (!chromeos::NetworkState::ErrorIsValid(shill_error)) {
257 shill_properties.GetStringWithoutPathExpansion(
258 shill::kPreviousErrorProperty, &shill_error);
259 NET_LOG_DEBUG("Notify Service.PreviousError: " + shill_error,
260 service_path);
261 if (!chromeos::NetworkState::ErrorIsValid(shill_error))
262 shill_error.clear();
263 } else {
264 NET_LOG_DEBUG("Notify Service.Error: " + shill_error, service_path);
267 const NetworkState* network =
268 NetworkHandler::Get()->network_state_handler()->GetNetworkState(
269 service_path);
270 if (network) {
271 // Always log last_error, but only use it if shill_error is empty.
272 // TODO(stevenjb): This shouldn't ever be necessary, but is kept here as a
273 // failsafe since more information is better than less when debugging and
274 // we have encountered some strange edge cases before.
275 NET_LOG_DEBUG("Notify Network.last_error: " + network->last_error(),
276 service_path);
277 if (shill_error.empty())
278 shill_error = network->last_error();
281 if (ShillErrorIsIgnored(shill_error)) {
282 NET_LOG_DEBUG("Notify Ignoring error: " + error_name, service_path);
283 return;
286 error = network_connect::ErrorString(shill_error, service_path);
287 if (error.empty())
288 error = l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
290 NET_LOG_ERROR("Notify connect error: " + base::UTF16ToUTF8(error),
291 service_path);
293 std::string network_name =
294 chromeos::shill_property_util::GetNameFromProperties(service_path,
295 shill_properties);
296 std::string network_error_details;
297 shill_properties.GetStringWithoutPathExpansion(shill::kErrorDetailsProperty,
298 &network_error_details);
300 base::string16 error_msg;
301 if (!network_error_details.empty()) {
302 // network_name should't be empty if network_error_details is set.
303 error_msg = l10n_util::GetStringFUTF16(
304 IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_SERVER_MESSAGE,
305 base::UTF8ToUTF16(network_name),
306 error,
307 base::UTF8ToUTF16(network_error_details));
308 } else if (network_name.empty()) {
309 error_msg = l10n_util::GetStringFUTF16(
310 IDS_NETWORK_CONNECTION_ERROR_MESSAGE_NO_NAME, error);
311 } else {
312 error_msg = l10n_util::GetStringFUTF16(IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
313 base::UTF8ToUTF16(network_name),
314 error);
317 std::string network_type;
318 shill_properties.GetStringWithoutPathExpansion(shill::kTypeProperty,
319 &network_type);
321 ShowErrorNotification(
322 network_connect::kNetworkConnectNotificationId,
323 network_type,
324 l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE),
325 error_msg,
326 base::Bind(&network_connect::ShowNetworkSettings, service_path));
329 } // namespace ash