// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/system/chromeos/network/network_state_notifier.h" #include "ash/shell.h" #include "ash/system/chromeos/network/network_connect.h" #include "ash/system/chromeos/network/network_observer.h" #include "ash/system/tray/system_tray_notifier.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "chromeos/network/network_connection_handler.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler.h" #include "grit/ash_strings.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/base/l10n/l10n_util.h" using chromeos::NetworkConnectionHandler; using chromeos::NetworkHandler; using chromeos::NetworkState; using chromeos::NetworkStateHandler; namespace { const int kMinTimeBetweenOutOfCreditsNotifySeconds = 10 * 60; // Error messages based on |error_name|, not network_state->error(). string16 GetConnectErrorString(const std::string& error_name) { if (error_name == NetworkConnectionHandler::kErrorNotFound) return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED); if (error_name == NetworkConnectionHandler::kErrorConfigureFailed) return l10n_util::GetStringUTF16( IDS_CHROMEOS_NETWORK_ERROR_CONFIGURE_FAILED); if (error_name == ash::network_connect::kErrorActivateFailed) return l10n_util::GetStringUTF16( IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED); return string16(); } } // namespace namespace ash { NetworkStateNotifier::NetworkStateNotifier() : cellular_out_of_credits_(false) { if (!NetworkHandler::IsInitialized()) return; NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); // Initialize |last_active_network_|. const NetworkState* default_network = NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); if (default_network && default_network->IsConnectedState()) last_active_network_ = default_network->path(); } NetworkStateNotifier::~NetworkStateNotifier() { if (!NetworkHandler::IsInitialized()) return; NetworkHandler::Get()->network_state_handler()->RemoveObserver( this, FROM_HERE); } void NetworkStateNotifier::NetworkListChanged() { // Trigger any pending connect failed error if the network list changes // (which indicates all NetworkState entries are up to date). This is in // case a connect attempt fails because a network is no longer visible. if (!connect_failed_network_.empty()) { ShowNetworkConnectError( flimflam::kErrorConnectFailed, connect_failed_network_); } } void NetworkStateNotifier::DefaultNetworkChanged(const NetworkState* network) { if (!network || !network->IsConnectedState()) return; if (network->path() != last_active_network_) { last_active_network_ = network->path(); // Reset state for new connected network cellular_out_of_credits_ = false; } } void NetworkStateNotifier::NetworkPropertiesUpdated( const NetworkState* network) { DCHECK(network); // Trigger a pending connect failed error for |network| when the Error // property has been set. if (network->path() == connect_failed_network_ && !network->error().empty()) { ShowNetworkConnectError( flimflam::kErrorConnectFailed, connect_failed_network_); } // Trigger "Out of credits" notification if the cellular network is the most // recent default network (i.e. we have not switched to another network). if (network->type() == flimflam::kTypeCellular && network->path() == last_active_network_) { cellular_network_ = network->path(); if (network->cellular_out_of_credits() && !cellular_out_of_credits_) { cellular_out_of_credits_ = true; base::TimeDelta dtime = base::Time::Now() - out_of_credits_notify_time_; if (dtime.InSeconds() > kMinTimeBetweenOutOfCreditsNotifySeconds) { out_of_credits_notify_time_ = base::Time::Now(); std::vector links; links.push_back( l10n_util::GetStringFUTF16(IDS_NETWORK_OUT_OF_CREDITS_LINK, UTF8ToUTF16(network->name()))); ash::Shell::GetInstance()->system_tray_notifier()-> NotifySetNetworkMessage( this, NetworkObserver::ERROR_OUT_OF_CREDITS, NetworkObserver::GetNetworkTypeForNetworkState(network), l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE), l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_BODY), links); } } } } void NetworkStateNotifier::NotificationLinkClicked( NetworkObserver::MessageType message_type, size_t link_index) { if (message_type == NetworkObserver::ERROR_OUT_OF_CREDITS) { if (!cellular_network_.empty()) { // This will trigger the activation / portal code. Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork( cellular_network_); } ash::Shell::GetInstance()->system_tray_notifier()-> NotifyClearNetworkMessage(message_type); } } void NetworkStateNotifier::ShowNetworkConnectError( const std::string& error_name, const std::string& service_path) { const NetworkState* network = NetworkHandler::Get()->network_state_handler()-> GetNetworkState(service_path); if (error_name == flimflam::kErrorConnectFailed && service_path != connect_failed_network_) { // Shill may not have set the Error property yet. First request an update // and wait for either the update to complete or the network list to be // updated before displaying the error. connect_failed_network_ = service_path; return; } connect_failed_network_.clear(); string16 error = GetConnectErrorString(error_name); if (error.empty() && network) error = network_connect::ErrorString(network->error()); if (error.empty()) error = l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN); NET_LOG_ERROR("Connect error notification: " + UTF16ToUTF8(error), service_path); std::string name = network ? network->name() : ""; string16 error_msg; if (network && !network->error_details().empty()) { error_msg = l10n_util::GetStringFUTF16( IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_SERVER_MESSAGE, UTF8ToUTF16(name), error, UTF8ToUTF16(network->error_details())); } else { error_msg = l10n_util::GetStringFUTF16( IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_DETAILS, UTF8ToUTF16(name), error); } std::vector no_links; ash::Shell::GetInstance()->system_tray_notifier()->NotifySetNetworkMessage( this, NetworkObserver::ERROR_CONNECT_FAILED, NetworkObserver::GetNetworkTypeForNetworkState(network), l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE), error_msg, no_links); } } // namespace ash