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/chromeos/network/network_observer.h" 10 #include "ash/system/tray/system_tray_notifier.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_connection_handler.h" 15 #include "chromeos/network/network_event_log.h" 16 #include "chromeos/network/network_state.h" 17 #include "chromeos/network/network_state_handler.h" 18 #include "grit/ash_strings.h" 19 #include "third_party/cros_system_api/dbus/service_constants.h" 20 #include "ui/base/l10n/l10n_util.h" 21 22 using chromeos::NetworkConnectionHandler; 23 using chromeos::NetworkHandler; 24 using chromeos::NetworkState; 25 using chromeos::NetworkStateHandler; 26 27 namespace { 28 29 const int kMinTimeBetweenOutOfCreditsNotifySeconds = 10 * 60; 30 31 // Error messages based on |error_name|, not network_state->error(). 32 string16 GetConnectErrorString(const std::string& error_name) { 33 if (error_name == NetworkConnectionHandler::kErrorNotFound) 34 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED); 35 if (error_name == NetworkConnectionHandler::kErrorConfigureFailed) 36 return l10n_util::GetStringUTF16( 37 IDS_CHROMEOS_NETWORK_ERROR_CONFIGURE_FAILED); 38 if (error_name == ash::network_connect::kErrorActivateFailed) 39 return l10n_util::GetStringUTF16( 40 IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED); 41 return string16(); 42 } 43 44 } // namespace 45 46 namespace ash { 47 48 NetworkStateNotifier::NetworkStateNotifier() 49 : cellular_out_of_credits_(false) { 50 if (!NetworkHandler::IsInitialized()) 51 return; 52 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); 53 54 // Initialize |last_active_network_|. 55 const NetworkState* default_network = 56 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); 57 if (default_network && default_network->IsConnectedState()) 58 last_active_network_ = default_network->path(); 59 } 60 61 NetworkStateNotifier::~NetworkStateNotifier() { 62 if (!NetworkHandler::IsInitialized()) 63 return; 64 NetworkHandler::Get()->network_state_handler()->RemoveObserver( 65 this, FROM_HERE); 66 } 67 68 void NetworkStateNotifier::NetworkListChanged() { 69 // Trigger any pending connect failed error if the network list changes 70 // (which indicates all NetworkState entries are up to date). This is in 71 // case a connect attempt fails because a network is no longer visible. 72 if (!connect_failed_network_.empty()) { 73 ShowNetworkConnectError( 74 flimflam::kErrorConnectFailed, connect_failed_network_); 75 } 76 } 77 78 void NetworkStateNotifier::DefaultNetworkChanged(const NetworkState* network) { 79 if (!network || !network->IsConnectedState()) 80 return; 81 if (network->path() != last_active_network_) { 82 last_active_network_ = network->path(); 83 // Reset state for new connected network 84 cellular_out_of_credits_ = false; 85 } 86 } 87 88 void NetworkStateNotifier::NetworkPropertiesUpdated( 89 const NetworkState* network) { 90 DCHECK(network); 91 // Trigger a pending connect failed error for |network| when the Error 92 // property has been set. 93 if (network->path() == connect_failed_network_ && !network->error().empty()) { 94 ShowNetworkConnectError( 95 flimflam::kErrorConnectFailed, connect_failed_network_); 96 } 97 // Trigger "Out of credits" notification if the cellular network is the most 98 // recent default network (i.e. we have not switched to another network). 99 if (network->type() == flimflam::kTypeCellular && 100 network->path() == last_active_network_) { 101 cellular_network_ = network->path(); 102 if (network->cellular_out_of_credits() && 103 !cellular_out_of_credits_) { 104 cellular_out_of_credits_ = true; 105 base::TimeDelta dtime = base::Time::Now() - out_of_credits_notify_time_; 106 if (dtime.InSeconds() > kMinTimeBetweenOutOfCreditsNotifySeconds) { 107 out_of_credits_notify_time_ = base::Time::Now(); 108 std::vector<string16> links; 109 links.push_back( 110 l10n_util::GetStringFUTF16(IDS_NETWORK_OUT_OF_CREDITS_LINK, 111 UTF8ToUTF16(network->name()))); 112 ash::Shell::GetInstance()->system_tray_notifier()-> 113 NotifySetNetworkMessage( 114 this, 115 NetworkObserver::ERROR_OUT_OF_CREDITS, 116 NetworkObserver::GetNetworkTypeForNetworkState(network), 117 l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE), 118 l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_BODY), 119 links); 120 } 121 } 122 } 123 } 124 125 void NetworkStateNotifier::NotificationLinkClicked( 126 NetworkObserver::MessageType message_type, 127 size_t link_index) { 128 if (message_type == NetworkObserver::ERROR_OUT_OF_CREDITS) { 129 if (!cellular_network_.empty()) { 130 // This will trigger the activation / portal code. 131 Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork( 132 cellular_network_); 133 } 134 ash::Shell::GetInstance()->system_tray_notifier()-> 135 NotifyClearNetworkMessage(message_type); 136 } 137 } 138 139 void NetworkStateNotifier::ShowNetworkConnectError( 140 const std::string& error_name, 141 const std::string& service_path) { 142 const NetworkState* network = NetworkHandler::Get()->network_state_handler()-> 143 GetNetworkState(service_path); 144 if (error_name == flimflam::kErrorConnectFailed && 145 service_path != connect_failed_network_) { 146 // Shill may not have set the Error property yet. First request an update 147 // and wait for either the update to complete or the network list to be 148 // updated before displaying the error. 149 connect_failed_network_ = service_path; 150 return; 151 } 152 connect_failed_network_.clear(); 153 154 string16 error = GetConnectErrorString(error_name); 155 if (error.empty() && network) 156 error = network_connect::ErrorString(network->error()); 157 if (error.empty()) 158 error = l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN); 159 NET_LOG_ERROR("Connect error notification: " + UTF16ToUTF8(error), 160 service_path); 161 162 std::string name = network ? network->name() : ""; 163 string16 error_msg; 164 if (network && !network->error_details().empty()) { 165 error_msg = l10n_util::GetStringFUTF16( 166 IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_SERVER_MESSAGE, 167 UTF8ToUTF16(name), error, UTF8ToUTF16(network->error_details())); 168 } else { 169 error_msg = l10n_util::GetStringFUTF16( 170 IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_DETAILS, 171 UTF8ToUTF16(name), error); 172 } 173 174 std::vector<string16> no_links; 175 ash::Shell::GetInstance()->system_tray_notifier()->NotifySetNetworkMessage( 176 this, 177 NetworkObserver::ERROR_CONNECT_FAILED, 178 NetworkObserver::GetNetworkTypeForNetworkState(network), 179 l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE), 180 error_msg, 181 no_links); 182 } 183 184 } // namespace ash 185