blob: 11637320a4be89d09018299d4e555f170a3ade8c [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 "chrome/browser/ui/ash/network/data_promo_notification.h"
#include <memory>
#include <string>
#include "ash/public/cpp/notification_utils.h"
#include "ash/public/cpp/vector_icons/vector_icons.h"
#include "base/command_line.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/network/network_state_notifier.h"
#include "chrome/browser/ui/ash/system_tray_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/login/login_state.h"
#include "chromeos/network/device_state.h"
#include "chromeos/network/network_connect.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 "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/extension_registry.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
using chromeos::NetworkHandler;
using chromeos::NetworkState;
namespace {
const char kMobileDataNotificationId[] =
"chrome://settings/internet/mobile_data";
const char kNotifierMobileData[] = "ash.mobile-data";
const char kDataSaverNotificationId[] = "chrome://settings/internet/data_saver";
const char kNotifierDataSaver[] = "ash.data-saver";
const char kDataSaverExtensionUrl[] =
"https://chrome.google.com/webstore/detail/"
"pfmgfdlgomnbgkofeojodiodmgpgmkac?utm_source=chromeos-datasaver-prompt";
const int kTimesToShowDataSaverPrompt = 2;
Profile* GetProfileForNotifications() {
return ProfileManager::GetActiveUserProfile();
}
// Returns prefs::kShowMobileDataNotification
bool ShouldShowMobileDataNotification() {
return GetProfileForNotifications()->GetPrefs()->GetBoolean(
prefs::kShowMobileDataNotification);
}
void SetShowMobileDataNotification(bool value) {
GetProfileForNotifications()->GetPrefs()->SetBoolean(
prefs::kShowMobileDataNotification, value);
}
// Returns number of times the Data Saver prompt has been displayed.
int GetDataSaverPromptsShown() {
return GetProfileForNotifications()->GetPrefs()->GetInteger(
prefs::kDataSaverPromptsShown);
}
// Updates number of times the Data Saver prompt has been displayed.
void SetDataSaverPromptsShown(int times_shown) {
GetProfileForNotifications()->GetPrefs()->SetInteger(
prefs::kDataSaverPromptsShown, times_shown);
}
// kDisableDataSaverPrompt takes precedence over any kEnableDataSaverPrompt
// value. If neither flag is set, the Data Saver prompt is enabled by default.
bool DataSaverSwitchEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kDisableDataSaverPrompt);
}
// Is command line switch set for Data Saver demo mode, where we show the prompt
// after any change in network properties?
bool DataSaverSwitchDemoMode() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kDisableDataSaverPrompt))
return false;
const std::string value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
chromeos::switches::kEnableDataSaverPrompt);
return value == chromeos::switches::kDataSaverPromptDemoMode;
}
void DataSaverNotificationClicked() {
chrome::ScopedTabbedBrowserDisplayer displayer(GetProfileForNotifications());
ShowSingletonTab(displayer.browser(), GURL(kDataSaverExtensionUrl));
base::RecordAction(base::UserMetricsAction("DataSaverPrompt_Clicked"));
}
void MobileDataNotificationClicked(const std::string& network_id) {
SystemTrayClient::Get()->ShowNetworkSettings(network_id);
}
void DisplayNotification(const std::string& notification_id,
const std::string& notifier_id,
const base::string16& message,
const base::string16& title,
const base::RepeatingClosure& callback) {
std::unique_ptr<message_center::Notification> notification =
ash::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
message, base::string16() /* display_source */, GURL(),
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT, notifier_id),
message_center::RichNotificationData(),
base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
callback),
ash::kNotificationMobileDataIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
NotificationDisplayService::GetForProfile(GetProfileForNotifications())
->Display(NotificationHandler::Type::TRANSIENT, *notification);
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// DataPromoNotification
DataPromoNotification::DataPromoNotification()
: notifications_shown_(false), weak_ptr_factory_(this) {
NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
}
DataPromoNotification::~DataPromoNotification() {
if (NetworkHandler::IsInitialized()) {
NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
FROM_HERE);
}
}
void DataPromoNotification::NetworkPropertiesUpdated(
const NetworkState* network) {
if (!network ||
(network->type() != shill::kTypeCellular && !DataSaverSwitchDemoMode()))
return;
ShowOptionalMobileDataNotification();
}
void DataPromoNotification::DefaultNetworkChanged(const NetworkState* network) {
// Call NetworkPropertiesUpdated in case the Cellular network became the
// default network.
NetworkPropertiesUpdated(network);
}
void DataPromoNotification::ShowOptionalMobileDataNotification() {
if (notifications_shown_)
return;
// Do not show notifications to unauthenticated users, or when requesting a
// network connection, or if there's no default_network.
if (!chromeos::LoginState::Get()->IsUserAuthenticated())
return;
const NetworkState* default_network =
NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
if (!default_network)
return;
if (NetworkHandler::Get()
->network_connection_handler()
->HasPendingConnectRequest())
return;
if (!DataSaverSwitchDemoMode() &&
default_network->type() != shill::kTypeCellular)
return;
notifications_shown_ = true;
if (ShouldShowDataSaverNotification()) {
DisplayNotification(kDataSaverNotificationId, kNotifierDataSaver,
l10n_util::GetStringUTF16(IDS_3G_DATASAVER_TITLE),
l10n_util::GetStringUTF16(IDS_3G_DATASAVER_MESSAGE),
base::BindRepeating(&DataSaverNotificationClicked));
base::RecordAction(base::UserMetricsAction("DataSaverPrompt_Shown"));
if (DataSaverSwitchDemoMode()) {
SetShowMobileDataNotification(true);
SetDataSaverPromptsShown(0); // demo mode resets times shown counts.
} else {
SetDataSaverPromptsShown(GetDataSaverPromptsShown() + 1);
}
} else if (ShouldShowMobileDataNotification()) {
// Display a one-time notification on first use of Mobile Data connection
DisplayNotification(
kMobileDataNotificationId, kNotifierMobileData,
l10n_util::GetStringUTF16(IDS_MOBILE_DATA_NOTIFICATION_TITLE),
l10n_util::GetStringUTF16(IDS_3G_NOTIFICATION_MESSAGE),
base::BindRepeating(&MobileDataNotificationClicked,
default_network->guid()));
// Update local state to disable mobile usage warning notification.
SetShowMobileDataNotification(false);
}
}
bool DataPromoNotification::ShouldShowDataSaverNotification() {
if (!DataSaverSwitchEnabled())
return false;
int times_shown = GetDataSaverPromptsShown();
if (!DataSaverSwitchDemoMode() && times_shown >= kTimesToShowDataSaverPrompt)
return false;
if (extensions::ExtensionRegistry::Get(ProfileManager::GetActiveUserProfile())
->GetExtensionById(extension_misc::kDataSaverExtensionId,
extensions::ExtensionRegistry::EVERYTHING)) {
// If extension is installed, disable future prompts.
SetDataSaverPromptsShown(kTimesToShowDataSaverPrompt);
return false;
}
return true;
}