blob: dea0d6f44b10c4d5e0257b2132651c5af81c377c [file] [log] [blame]
// Copyright 2014 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/network_portal_notification_controller.h"
#include <stdint.h>
#include <memory>
#include <vector>
#include "ash/public/cpp/notification_utils.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/chromeos/mobile/mobile_activator.h"
#include "chrome/browser/chromeos/net/network_portal_web_dialog.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/notifications/notification_handler.h"
#include "chrome/browser/notifications/system_notification_helper.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_type_pattern.h"
#include "components/captive_portal/core/captive_portal_detector.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/user_manager.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/message_center/public/cpp/notification_types.h"
#include "ui/message_center/public/cpp/notifier_id.h"
#include "ui/views/widget/widget.h"
namespace chromeos {
namespace {
const char kNotifierNetworkPortalDetector[] = "ash.network.portal-detector";
void CloseNotification() {
SystemNotificationHelper::GetInstance()->Close(
NetworkPortalNotificationController::kNotificationId);
}
class NetworkPortalNotificationControllerDelegate
: public message_center::NotificationDelegate {
public:
explicit NetworkPortalNotificationControllerDelegate(
const std::string& guid,
base::WeakPtr<NetworkPortalNotificationController> controller)
: guid_(guid), clicked_(false), controller_(controller) {}
// Overridden from message_center::NotificationDelegate:
void Click(const base::Optional<int>& button_index,
const base::Optional<base::string16>& reply) override;
private:
~NetworkPortalNotificationControllerDelegate() override {}
// GUID of the network this notification is generated for.
std::string guid_;
bool clicked_;
base::WeakPtr<NetworkPortalNotificationController> controller_;
DISALLOW_COPY_AND_ASSIGN(NetworkPortalNotificationControllerDelegate);
};
void NetworkPortalNotificationControllerDelegate::Click(
const base::Optional<int>& button_index,
const base::Optional<base::string16>& reply) {
clicked_ = true;
Profile* profile = ProfileManager::GetActiveUserProfile();
const bool use_incognito_profile =
profile && profile->GetPrefs()->GetBoolean(
prefs::kCaptivePortalAuthenticationIgnoresProxy);
if (use_incognito_profile) {
if (controller_)
controller_->ShowDialog();
} else {
if (!profile)
return;
chrome::ScopedTabbedBrowserDisplayer displayer(profile);
GURL url(captive_portal::CaptivePortalDetector::kDefaultURL);
ShowSingletonTab(displayer.browser(), url);
}
CloseNotification();
}
} // namespace
// static
const char NetworkPortalNotificationController::kNotificationId[] =
"chrome://net/network_portal_detector";
NetworkPortalNotificationController::NetworkPortalNotificationController(
NetworkPortalDetector* network_portal_detector)
: network_portal_detector_(network_portal_detector) {
if (network_portal_detector_) { // May be null in tests.
network_portal_detector_->AddObserver(this);
DCHECK(session_manager::SessionManager::Get());
session_manager::SessionManager::Get()->AddObserver(this);
}
}
NetworkPortalNotificationController::~NetworkPortalNotificationController() {
if (network_portal_detector_) {
if (session_manager::SessionManager::Get())
session_manager::SessionManager::Get()->RemoveObserver(this);
network_portal_detector_->RemoveObserver(this);
}
}
void NetworkPortalNotificationController::OnPortalDetectionCompleted(
const NetworkState* network,
const NetworkPortalDetector::CaptivePortalStatus status) {
if (!network ||
status != NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL) {
last_network_guid_.clear();
// In browser tests we initiate fake network portal detection, but network
// state usually stays connected. This way, after dialog is shown, it is
// immediately closed. The testing check below prevents dialog from closing.
if (dialog_ &&
(!ignore_no_network_for_testing_ ||
status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) {
dialog_->Close();
}
CloseNotification();
return;
}
// Don't do anything if we're currently activating the device.
if (MobileActivator::GetInstance()->RunningActivation())
return;
// Don't do anything if notification for |network| already was
// displayed.
if (network->guid() == last_network_guid_)
return;
last_network_guid_ = network->guid();
std::unique_ptr<message_center::Notification> notification =
CreateDefaultCaptivePortalNotification(network);
SystemNotificationHelper::GetInstance()->Display(*notification);
}
void NetworkPortalNotificationController::OnShutdown() {
CloseDialog();
network_portal_detector_->RemoveObserver(this);
network_portal_detector_ = nullptr;
}
void NetworkPortalNotificationController::OnSessionStateChanged() {
session_manager::SessionState state =
session_manager::SessionManager::Get()->session_state();
if (state == session_manager::SessionState::LOCKED)
CloseDialog();
}
void NetworkPortalNotificationController::ShowDialog() {
if (dialog_)
return;
Profile* signin_profile = ProfileHelper::GetSigninProfile();
dialog_ = new NetworkPortalWebDialog(weak_factory_.GetWeakPtr());
dialog_->SetWidget(views::Widget::GetWidgetForNativeWindow(
chrome::ShowWebDialog(nullptr, signin_profile, dialog_)));
}
void NetworkPortalNotificationController::OnDialogDestroyed(
const NetworkPortalWebDialog* dialog) {
if (dialog == dialog_) {
dialog_ = nullptr;
ProfileHelper::Get()->ClearSigninProfile(base::NullCallback());
}
}
std::unique_ptr<message_center::Notification>
NetworkPortalNotificationController::CreateDefaultCaptivePortalNotification(
const NetworkState* network) {
auto delegate =
base::MakeRefCounted<NetworkPortalNotificationControllerDelegate>(
network->guid(), weak_factory_.GetWeakPtr());
message_center::NotifierId notifier_id(
message_center::NotifierType::SYSTEM_COMPONENT,
kNotifierNetworkPortalDetector);
bool is_wifi = NetworkTypePattern::WiFi().MatchesType(network->type());
std::unique_ptr<message_center::Notification> notification =
ash::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
l10n_util::GetStringUTF16(
is_wifi ? IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIFI
: IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIRED),
l10n_util::GetStringFUTF16(
is_wifi ? IDS_PORTAL_DETECTION_NOTIFICATION_MESSAGE_WIFI
: IDS_PORTAL_DETECTION_NOTIFICATION_MESSAGE_WIRED,
base::UTF8ToUTF16(network->name())),
/*display_source=*/base::string16(), /*origin_url=*/GURL(),
notifier_id, message_center::RichNotificationData(),
std::move(delegate), kNotificationCaptivePortalIcon,
message_center::SystemNotificationWarningLevel::WARNING);
return notification;
}
void NetworkPortalNotificationController::SetIgnoreNoNetworkForTesting() {
ignore_no_network_for_testing_ = true;
}
void NetworkPortalNotificationController::CloseDialog() {
if (dialog_)
dialog_->Close();
}
const NetworkPortalWebDialog*
NetworkPortalNotificationController::GetDialogForTesting() const {
return dialog_;
}
} // namespace chromeos