blob: 1c971a32a44360d4df4b71d6c223f8e70343b96d [file] [log] [blame]
// 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 == NetworkConnectionHandler::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(
NetworkConnectionHandler::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(
NetworkConnectionHandler::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<string16> 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 == NetworkConnectionHandler::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<string16> 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