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"
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
;
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
)
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(
84 ash::system_notifier::kNotifierNetworkError
,
92 NetworkStateNotifier::NetworkStateNotifier()
93 : did_show_out_of_credits_(false),
94 weak_ptr_factory_(this) {
95 if (!NetworkHandler::IsInitialized())
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())
105 NetworkHandler::Get()->network_state_handler()->RemoveObserver(
109 void NetworkStateNotifier::DefaultNetworkChanged(const NetworkState
* network
) {
110 if (!UpdateDefaultNetwork(network
))
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).
116 did_show_out_of_credits_
= false;
119 void NetworkStateNotifier::NetworkPropertiesUpdated(
120 const NetworkState
* network
) {
121 if (network
->type() != shill::kTypeCellular
)
123 UpdateCellularOutOfCredits(network
);
124 UpdateCellularActivating(network
);
127 bool NetworkStateNotifier::UpdateDefaultNetwork(const NetworkState
* network
) {
128 std::string default_network_path
;
130 default_network_path
= network
->path();
131 if (default_network_path
!= last_default_network_
) {
132 last_default_network_
= default_network_path
;
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_
)
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
)
151 if (handler
->ConnectingNetworkByType(NetworkTypePattern::NonVirtual()) ||
152 NetworkHandler::Get()->network_connection_handler()
153 ->HasPendingConnectRequest())
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
,
166 l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE
),
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());
180 // Only display a notification if this network was activating and is now
182 if (!cellular_activating_
.count(cellular
->path()) ||
183 activation_state
!= shill::kActivationStateActivated
)
186 cellular_activating_
.erase(cellular
->path());
188 if (cellular
->network_technology() == shill::kNetworkTechnologyLte
)
189 icon_id
= IDR_AURA_UBER_TRAY_NOTIFICATION_LTE
;
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()))),
201 system_notifier::kNotifierNetwork
,
202 base::Bind(&ash::network_connect::ShowNetworkSettings
,
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
);
214 // Get the up-to-date properties for the network and display the error.
215 NetworkHandler::Get()->network_configuration_handler()->GetProperties(
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
) {
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.
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
);
253 std::string shill_error
;
254 shill_properties
.GetStringWithoutPathExpansion(shill::kErrorProperty
,
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
,
261 if (!chromeos::NetworkState::ErrorIsValid(shill_error
))
264 NET_LOG_DEBUG("Notify Service.Error: " + shill_error
, service_path
);
267 const NetworkState
* network
=
268 NetworkHandler::Get()->network_state_handler()->GetNetworkState(
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(),
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
);
286 error
= network_connect::ErrorString(shill_error
, service_path
);
288 error
= l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN
);
290 NET_LOG_ERROR("Notify connect error: " + base::UTF16ToUTF8(error
),
293 std::string network_name
=
294 chromeos::shill_property_util::GetNameFromProperties(service_path
,
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
),
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
);
312 error_msg
= l10n_util::GetStringFUTF16(IDS_NETWORK_CONNECTION_ERROR_MESSAGE
,
313 base::UTF8ToUTF16(network_name
),
317 std::string network_type
;
318 shill_properties
.GetStringWithoutPathExpansion(shill::kTypeProperty
,
321 ShowErrorNotification(
322 network_connect::kNetworkConnectNotificationId
,
324 l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE
),
326 base::Bind(&network_connect::ShowNetworkSettings
, service_path
));