Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ash / system / chromeos / network / network_state_notifier.cc
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 "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"
28
29 using chromeos::NetworkConnectionHandler;
30 using chromeos::NetworkHandler;
31 using chromeos::NetworkState;
32 using chromeos::NetworkStateHandler;
33 using chromeos::NetworkTypePattern;
34
35 namespace {
36
37 const char kNetworkOutOfCreditsNotificationId[] =
38     "chrome://settings/internet/out-of-credits";
39
40 const int kMinTimeBetweenOutOfCreditsNotifySeconds = 10 * 60;
41
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;
47 }
48
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);
56   }
57   if (error_name == NetworkConnectionHandler::kErrorCertLoadTimeout) {
58     return l10n_util::GetStringUTF16(
59         IDS_CHROMEOS_NETWORK_ERROR_CERTIFICATES_NOT_LOADED);
60   }
61   if (error_name == ash::network_connect::kErrorActivateFailed) {
62     return l10n_util::GetStringUTF16(
63         IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
64   }
65   return base::string16();
66 }
67
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));
86 }
87
88 }  // namespace
89
90 namespace ash {
91
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());
100 }
101
102 NetworkStateNotifier::~NetworkStateNotifier() {
103   if (!NetworkHandler::IsInitialized())
104     return;
105   NetworkHandler::Get()->network_state_handler()->RemoveObserver(
106       this, FROM_HERE);
107 }
108
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;
117 }
118
119 void NetworkStateNotifier::NetworkPropertiesUpdated(
120     const NetworkState* network) {
121   if (network->type() != shill::kTypeCellular)
122     return;
123   UpdateCellularOutOfCredits(network);
124   UpdateCellularActivating(network);
125 }
126
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;
134   }
135   return false;
136 }
137
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;
144
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;
155
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()));
169   }
170 }
171
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;
179   }
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;
185
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())));
204 }
205
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;
213   }
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));
221 }
222
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;
234   }
235   ShowConnectErrorNotification(error_name, service_path, shill_properties);
236 }
237
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);
245 }
246
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);
265     }
266
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();
279     }
280
281     if (ShillErrorIsIgnored(shill_error)) {
282       NET_LOG_DEBUG("Notify Ignoring error: " + error_name, service_path);
283       return;
284     }
285
286     error = network_connect::ErrorString(shill_error, service_path);
287     if (error.empty())
288       error = l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
289   }
290   NET_LOG_ERROR("Notify connect error: " + base::UTF16ToUTF8(error),
291                 service_path);
292
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);
299
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);
315   }
316
317   std::string network_type;
318   shill_properties.GetStringWithoutPathExpansion(shill::kTypeProperty,
319                                                  &network_type);
320
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));
327 }
328
329 }  // namespace ash