blob: b295cb24edcb1f42f007c0eade47f470e0b21505 [file] [log] [blame]
// Copyright 2016 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/system_tray_client.h"
#include "ash/common/login_status.h"
#include "ash/common/session/session_state_delegate.h"
#include "ash/common/wm_shell.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "base/logging.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/chromeos/accessibility/accessibility_util.h"
#include "chrome/browser/chromeos/login/ui/login_display_host.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/set_time_dialog.h"
#include "chrome/browser/chromeos/system/system_clock.h"
#include "chrome/browser/chromeos/ui/choose_mobile_network_dialog.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/ash_util.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/common/url_constants.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/login/login_state.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/common/service_names.mojom.h"
#include "extensions/browser/api/vpn_provider/vpn_service.h"
#include "extensions/browser/api/vpn_provider/vpn_service_factory.h"
#include "net/base/escape.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/ui/public/cpp/property_type_converters.h"
#include "services/ui/public/interfaces/window_manager.mojom.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
using chromeos::DBusThreadManager;
using chromeos::LoginState;
using views::Widget;
namespace {
const char kDisplaySettingsSubPageName[] = "display";
const char kPaletteSettingsSubPageName[] = "stylus-overlay";
SystemTrayClient* g_instance = nullptr;
void ShowSettingsSubPageForActiveUser(const std::string& sub_page) {
chrome::ShowSettingsSubPageForProfile(ProfileManager::GetActiveUserProfile(),
sub_page);
}
} // namespace
SystemTrayClient::SystemTrayClient() : binding_(this) {
service_manager::Connector* connector =
content::ServiceManagerConnection::GetForProcess()->GetConnector();
// Connect to the SystemTray interface in ash. Under mash the SystemTray
// interface is in the ash process. In classic ash we provide it to ourself.
if (chrome::IsRunningInMash()) {
connector->ConnectToInterface("ash", &system_tray_);
} else {
connector->ConnectToInterface(content::mojom::kBrowserServiceName,
&system_tray_);
}
// Register this object as the client interface implementation.
system_tray_->SetClient(binding_.CreateInterfacePtrAndBind());
// If this observes clock setting changes before ash comes up the IPCs will
// be queued on |system_tray_|.
g_browser_process->platform_part()->GetSystemClock()->AddObserver(this);
DCHECK(!g_instance);
g_instance = this;
}
SystemTrayClient::~SystemTrayClient() {
DCHECK_EQ(this, g_instance);
g_instance = nullptr;
g_browser_process->platform_part()->GetSystemClock()->RemoveObserver(this);
}
// static
SystemTrayClient* SystemTrayClient::Get() {
return g_instance;
}
// static
ash::LoginStatus SystemTrayClient::GetUserLoginStatus() {
if (!LoginState::Get()->IsUserLoggedIn())
return ash::LoginStatus::NOT_LOGGED_IN;
// Session manager client owns screen lock status.
if (DBusThreadManager::Get()->GetSessionManagerClient()->IsScreenLocked())
return ash::LoginStatus::LOCKED;
LoginState::LoggedInUserType user_type =
LoginState::Get()->GetLoggedInUserType();
switch (user_type) {
case LoginState::LOGGED_IN_USER_NONE:
return ash::LoginStatus::NOT_LOGGED_IN;
case LoginState::LOGGED_IN_USER_REGULAR:
return ash::LoginStatus::USER;
case LoginState::LOGGED_IN_USER_OWNER:
return ash::LoginStatus::OWNER;
case LoginState::LOGGED_IN_USER_GUEST:
return ash::LoginStatus::GUEST;
case LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT:
return ash::LoginStatus::PUBLIC;
case LoginState::LOGGED_IN_USER_SUPERVISED:
return ash::LoginStatus::SUPERVISED;
case LoginState::LOGGED_IN_USER_KIOSK_APP:
return ash::LoginStatus::KIOSK_APP;
case LoginState::LOGGED_IN_USER_ARC_KIOSK_APP:
return ash::LoginStatus::ARC_KIOSK_APP;
}
NOTREACHED();
return ash::LoginStatus::NOT_LOGGED_IN;
}
// static
int SystemTrayClient::GetDialogParentContainerId() {
const ash::LoginStatus login_status = GetUserLoginStatus();
if (login_status == ash::LoginStatus::NOT_LOGGED_IN ||
login_status == ash::LoginStatus::LOCKED) {
return ash::kShellWindowId_LockSystemModalContainer;
}
// TODO(mash): Need replacement for SessionStateDelegate. crbug.com/648964
if (chrome::IsRunningInMash())
return ash::kShellWindowId_SystemModalContainer;
ash::WmShell* wm_shell = ash::WmShell::Get();
const bool session_started =
wm_shell->GetSessionStateDelegate()->IsActiveUserSessionStarted();
const bool is_in_secondary_login_screen =
wm_shell->GetSessionStateDelegate()->IsInSecondaryLoginScreen();
if (!session_started || is_in_secondary_login_screen)
return ash::kShellWindowId_LockSystemModalContainer;
return ash::kShellWindowId_SystemModalContainer;
}
// static
Widget* SystemTrayClient::CreateUnownedDialogWidget(
views::WidgetDelegate* widget_delegate) {
DCHECK(widget_delegate);
Widget::InitParams params = views::DialogDelegate::GetDialogWidgetInitParams(
widget_delegate, nullptr, nullptr, gfx::Rect());
// Place the dialog in the appropriate modal dialog container, either above
// or below the lock screen, based on the login state.
int container_id = GetDialogParentContainerId();
if (chrome::IsRunningInMash()) {
using ui::mojom::WindowManager;
params.mus_properties[WindowManager::kInitialContainerId_Property] =
mojo::ConvertTo<std::vector<uint8_t>>(container_id);
} else {
params.parent = ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
container_id);
}
Widget* widget = new Widget; // Owned by native widget.
widget->Init(params);
return widget;
}
////////////////////////////////////////////////////////////////////////////////
// ash::mojom::SystemTrayClient:
void SystemTrayClient::ShowSettings() {
ShowSettingsSubPageForActiveUser(std::string());
}
void SystemTrayClient::ShowDateSettings() {
content::RecordAction(base::UserMetricsAction("ShowDateOptions"));
// Everybody can change the time zone (even though it is a device setting).
chrome::ShowSettingsSubPageForProfile(ProfileManager::GetActiveUserProfile(),
chrome::kDateTimeSubPage);
}
void SystemTrayClient::ShowSetTimeDialog() {
chromeos::SetTimeDialog::ShowDialogInContainer(GetDialogParentContainerId());
}
void SystemTrayClient::ShowDisplaySettings() {
content::RecordAction(base::UserMetricsAction("ShowDisplayOptions"));
ShowSettingsSubPageForActiveUser(kDisplaySettingsSubPageName);
}
void SystemTrayClient::ShowPowerSettings() {
content::RecordAction(base::UserMetricsAction("Tray_ShowPowerOptions"));
ShowSettingsSubPageForActiveUser(chrome::kPowerOptionsSubPage);
}
void SystemTrayClient::ShowChromeSlow() {
chrome::ScopedTabbedBrowserDisplayer displayer(
ProfileManager::GetPrimaryUserProfile());
chrome::ShowSlow(displayer.browser());
}
void SystemTrayClient::ShowIMESettings() {
content::RecordAction(base::UserMetricsAction("OpenLanguageOptionsDialog"));
ShowSettingsSubPageForActiveUser(chrome::kLanguageOptionsSubPage);
}
void SystemTrayClient::ShowHelp() {
chrome::ShowHelpForProfile(ProfileManager::GetActiveUserProfile(),
chrome::HELP_SOURCE_MENU);
}
void SystemTrayClient::ShowAccessibilityHelp() {
chrome::ScopedTabbedBrowserDisplayer displayer(
ProfileManager::GetActiveUserProfile());
chromeos::accessibility::ShowAccessibilityHelp(displayer.browser());
}
void SystemTrayClient::ShowAccessibilitySettings() {
content::RecordAction(base::UserMetricsAction("ShowAccessibilitySettings"));
ShowSettingsSubPageForActiveUser(chrome::kAccessibilitySubPage);
}
void SystemTrayClient::ShowPaletteHelp() {
chrome::ScopedTabbedBrowserDisplayer displayer(
ProfileManager::GetActiveUserProfile());
chrome::ShowSingletonTab(displayer.browser(),
GURL(chrome::kChromePaletteHelpURL));
}
void SystemTrayClient::ShowPaletteSettings() {
content::RecordAction(base::UserMetricsAction("ShowPaletteOptions"));
ShowSettingsSubPageForActiveUser(kPaletteSettingsSubPageName);
}
void SystemTrayClient::ShowPublicAccountInfo() {
chrome::ScopedTabbedBrowserDisplayer displayer(
ProfileManager::GetActiveUserProfile());
chrome::ShowPolicy(displayer.browser());
}
void SystemTrayClient::ShowNetworkConfigure(const std::string& network_id) {
// UI is not available at the lock screen.
// TODO(mash): Need replacement for SessionStateDelegate. crbug.com/648964
if (!chrome::IsRunningInMash() &&
ash::WmShell::Get()->GetSessionStateDelegate()->IsScreenLocked()) {
return;
}
// Dialog will default to the primary display.
chromeos::NetworkConfigView::ShowForNetworkId(network_id,
nullptr /* parent */);
}
void SystemTrayClient::ShowNetworkCreate(const std::string& type) {
int container_id = GetDialogParentContainerId();
if (type == shill::kTypeCellular) {
chromeos::ChooseMobileNetworkDialog::ShowDialogInContainer(container_id);
return;
}
chromeos::NetworkConfigView::ShowForType(type, nullptr /* parent */);
}
void SystemTrayClient::ShowThirdPartyVpnCreate(
const std::string& extension_id) {
const user_manager::User* primary_user =
user_manager::UserManager::Get()->GetPrimaryUser();
if (!primary_user)
return;
Profile* profile =
chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
if (!profile)
return;
// Request that the third-party VPN provider show its "add network" dialog.
chromeos::VpnServiceFactory::GetForBrowserContext(profile)
->SendShowAddDialogToExtension(extension_id);
}
void SystemTrayClient::ShowNetworkSettings(const std::string& network_id) {
if (!chrome::IsRunningInMash()) {
// TODO(mash): Need replacement for SessionStateDelegate. crbug.com/648964
if (!LoginState::Get()->IsUserLoggedIn() ||
ash::WmShell::Get()
->GetSessionStateDelegate()
->IsInSecondaryLoginScreen())
return;
}
std::string page = chrome::kInternetOptionsSubPage;
if (!network_id.empty())
page += "?guid=" + net::EscapeUrlEncodedData(network_id, true);
content::RecordAction(base::UserMetricsAction("OpenInternetOptionsDialog"));
ShowSettingsSubPageForActiveUser(page);
}
void SystemTrayClient::ShowProxySettings() {
LoginState* login_state = LoginState::Get();
// User is not logged in.
CHECK(!login_state->IsUserLoggedIn() ||
login_state->GetLoggedInUserType() == LoginState::LOGGED_IN_USER_NONE);
chromeos::LoginDisplayHost::default_host()->OpenProxySettings();
}
void SystemTrayClient::SignOut() {
chrome::AttemptUserExit();
}
void SystemTrayClient::RequestRestartForUpdate() {
// We expect that UpdateEngine is in "Reboot for update" state now.
chrome::NotifyAndTerminate(true /* fast_path */);
}
////////////////////////////////////////////////////////////////////////////////
// chromeos::system::SystemClockObserver:
void SystemTrayClient::OnSystemClockChanged(
chromeos::system::SystemClock* clock) {
system_tray_->SetUse24HourClock(clock->ShouldUse24HourClock());
}