blob: 634aca4b76665435aad6cebe130f3974f66b6853 [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/system_notifier.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/network/network_configuration_handler.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 "chromeos/network/shill_property_util.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification.h"
using chromeos::NetworkConnectionHandler;
using chromeos::NetworkHandler;
using chromeos::NetworkState;
using chromeos::NetworkStateHandler;
using chromeos::NetworkTypePattern;
namespace {
const char kNetworkOutOfCreditsNotificationId[] =
"chrome://settings/internet/out-of-credits";
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();
}
void ShowErrorNotification(const std::string& notification_id,
const std::string& network_type,
const base::string16& title,
const base::string16& message,
const base::Closure& callback) {
int icon_id = (network_type == flimflam::kTypeCellular) ?
IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED :
IDR_AURA_UBER_TRAY_NETWORK_FAILED;
const gfx::Image& icon =
ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
message_center::MessageCenter::Get()->AddNotification(
message_center::Notification::CreateSystemNotification(
notification_id,
title,
message,
icon,
ash::system_notifier::NOTIFIER_NETWORK_ERROR,
callback));
}
void ConfigureNetwork(const std::string& service_path) {
ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork(
service_path);
}
} // namespace
namespace ash {
NetworkStateNotifier::NetworkStateNotifier()
: did_show_out_of_credits_(false),
weak_ptr_factory_(this) {
if (!NetworkHandler::IsInitialized())
return;
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
handler->AddObserver(this, FROM_HERE);
UpdateDefaultNetwork(handler->DefaultNetwork());
}
NetworkStateNotifier::~NetworkStateNotifier() {
if (!NetworkHandler::IsInitialized())
return;
NetworkHandler::Get()->network_state_handler()->RemoveObserver(
this, FROM_HERE);
}
void NetworkStateNotifier::DefaultNetworkChanged(const NetworkState* network) {
if (!UpdateDefaultNetwork(network))
return;
// If the default network changes to another network, allow the out of
// credits notification to be shown again. A delay prevents the notification
// from being shown too frequently (see below).
if (network)
did_show_out_of_credits_ = false;
}
void NetworkStateNotifier::NetworkPropertiesUpdated(
const NetworkState* network) {
if (network->type() != flimflam::kTypeCellular)
return;
UpdateCellularOutOfCredits(network);
UpdateCellularActivating(network);
}
bool NetworkStateNotifier::UpdateDefaultNetwork(const NetworkState* network) {
std::string default_network_path;
if (network)
default_network_path = network->path();
if (default_network_path != last_default_network_) {
last_default_network_ = default_network_path;
return true;
}
return false;
}
void NetworkStateNotifier::UpdateCellularOutOfCredits(
const NetworkState* cellular) {
// Only display a notification if we are out of credits and have not already
// shown a notification (or have since connected to another network type).
if (!cellular->cellular_out_of_credits() || did_show_out_of_credits_)
return;
// Only display a notification if not connected, connecting, or waiting to
// connect to another network.
NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
const NetworkState* default_network = handler->DefaultNetwork();
if (default_network && default_network != cellular)
return;
if (handler->ConnectingNetworkByType(NetworkTypePattern::NonVirtual()) ||
NetworkHandler::Get()->network_connection_handler()
->HasPendingConnectRequest())
return;
did_show_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();
string16 error_msg = l10n_util::GetStringFUTF16(
IDS_NETWORK_OUT_OF_CREDITS_BODY,
UTF8ToUTF16(cellular->name()));
ShowErrorNotification(
kNetworkOutOfCreditsNotificationId,
cellular->type(),
l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE),
error_msg,
base::Bind(&ConfigureNetwork, cellular->path()));
}
}
void NetworkStateNotifier::UpdateCellularActivating(
const NetworkState* cellular) {
// Keep track of any activating cellular network.
std::string activation_state = cellular->activation_state();
if (activation_state == flimflam::kActivationStateActivating) {
cellular_activating_.insert(cellular->path());
return;
}
// Only display a notification if this network was activating and is now
// activated.
if (!cellular_activating_.count(cellular->path()) ||
activation_state != flimflam::kActivationStateActivated)
return;
cellular_activating_.erase(cellular->path());
int icon_id;
if (cellular->network_technology() == flimflam::kNetworkTechnologyLte)
icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_LTE;
else
icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_3G;
const gfx::Image& icon =
ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
message_center::MessageCenter::Get()->AddNotification(
message_center::Notification::CreateSystemNotification(
ash::network_connect::kNetworkActivateNotificationId,
l10n_util::GetStringUTF16(IDS_NETWORK_CELLULAR_ACTIVATED_TITLE),
l10n_util::GetStringFUTF16(IDS_NETWORK_CELLULAR_ACTIVATED,
UTF8ToUTF16((cellular->name()))),
icon,
system_notifier::NOTIFIER_NETWORK,
base::Bind(&ash::network_connect::ShowNetworkSettings,
cellular->path())));
}
void NetworkStateNotifier::ShowNetworkConnectError(
const std::string& error_name,
const std::string& service_path) {
if (service_path.empty()) {
base::DictionaryValue shill_properties;
ShowConnectErrorNotification(error_name, service_path, shill_properties);
return;
}
// Get the up-to-date properties for the network and display the error.
NetworkHandler::Get()->network_configuration_handler()->GetProperties(
service_path,
base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesSucceeded,
weak_ptr_factory_.GetWeakPtr(), error_name),
base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesFailed,
weak_ptr_factory_.GetWeakPtr(), error_name, service_path));
}
void NetworkStateNotifier::ConnectErrorPropertiesSucceeded(
const std::string& error_name,
const std::string& service_path,
const base::DictionaryValue& shill_properties) {
ShowConnectErrorNotification(error_name, service_path, shill_properties);
}
void NetworkStateNotifier::ConnectErrorPropertiesFailed(
const std::string& error_name,
const std::string& service_path,
const std::string& shill_error_name,
scoped_ptr<base::DictionaryValue> shill_error_data) {
base::DictionaryValue shill_properties;
ShowConnectErrorNotification(error_name, service_path, shill_properties);
}
void NetworkStateNotifier::ShowConnectErrorNotification(
const std::string& error_name,
const std::string& service_path,
const base::DictionaryValue& shill_properties) {
string16 error = GetConnectErrorString(error_name);
if (error.empty()) {
std::string network_error;
shill_properties.GetStringWithoutPathExpansion(
flimflam::kErrorProperty, &network_error);
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 network_name =
chromeos::shill_property_util::GetNameFromProperties(service_path,
shill_properties);
std::string network_error_details;
shill_properties.GetStringWithoutPathExpansion(
shill::kErrorDetailsProperty, &network_error_details);
string16 error_msg;
if (!network_error_details.empty()) {
// network_name should't be empty if network_error_details is set.
error_msg = l10n_util::GetStringFUTF16(
IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_SERVER_MESSAGE,
UTF8ToUTF16(network_name), error,
UTF8ToUTF16(network_error_details));
} else if (network_name.empty()) {
error_msg = l10n_util::GetStringFUTF16(
IDS_NETWORK_CONNECTION_ERROR_MESSAGE_NO_NAME, error);
} else {
error_msg = l10n_util::GetStringFUTF16(
IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
UTF8ToUTF16(network_name), error);
}
std::string network_type;
shill_properties.GetStringWithoutPathExpansion(
flimflam::kTypeProperty, &network_type);
ShowErrorNotification(
network_connect::kNetworkConnectNotificationId,
network_type,
l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE),
error_msg,
base::Bind(&network_connect::ShowNetworkSettings, service_path));
}
} // namespace ash