blob: 08d97c4840d018315e2f5821d396679b7314ae18 [file] [log] [blame]
// Copyright 2013 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/chrome_shell_delegate.h"
#include "ash/accelerators/magnifier_key_scroller.h"
#include "ash/accelerators/spoken_feedback_toggler.h"
#include "ash/accessibility_delegate.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
#include "chrome/browser/chromeos/background/ash_user_wallpaper_delegate.h"
#include "chrome/browser/chromeos/display/display_configuration_observer.h"
#include "chrome/browser/chromeos/display/display_preferences.h"
#include "chrome/browser/chromeos/policy/display_rotation_default_handler.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/signin_error_notifier_factory_ash.h"
#include "chrome/browser/speech/tts_controller.h"
#include "chrome/browser/sync/sync_error_notifier_factory_ash.h"
#include "chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
#include "chrome/browser/ui/ash/media_delegate_chromeos.h"
#include "chrome/browser/ui/ash/session_state_delegate_chromeos.h"
#include "chrome/browser/ui/ash/system_tray_delegate_chromeos.h"
#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/chromeos_switches.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/user_metrics.h"
#include "ui/aura/window.h"
#include "ui/base/ime/chromeos/input_method_manager.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
void InitAfterFirstSessionStart() {
// Restore focus after the user session is started. It's needed because some
// windows can be opened in background while login UI is still active because
// we currently restore browser windows before login UI is deleted.
ash::Shell* shell = ash::Shell::GetInstance();
ash::MruWindowTracker::WindowList mru_list =
shell->mru_window_tracker()->BuildMruWindowList();
if (!mru_list.empty())
mru_list.front()->Focus();
// Enable magnifier scroll keys as there may be no mouse cursor in kiosk mode.
ash::MagnifierKeyScroller::SetEnabled(chrome::IsRunningInForcedAppMode());
// Enable long press action to toggle spoken feedback with hotrod
// remote which can't handle shortcut.
ash::SpokenFeedbackToggler::SetEnabled(chrome::IsRunningInForcedAppMode());
}
class AccessibilityDelegateImpl : public ash::AccessibilityDelegate {
public:
AccessibilityDelegateImpl() {
ash::Shell::GetInstance()->AddShellObserver(
chromeos::AccessibilityManager::Get());
}
~AccessibilityDelegateImpl() override {
ash::Shell::GetInstance()->RemoveShellObserver(
chromeos::AccessibilityManager::Get());
}
void ToggleHighContrast() override {
DCHECK(chromeos::AccessibilityManager::Get());
chromeos::AccessibilityManager::Get()->EnableHighContrast(
!chromeos::AccessibilityManager::Get()->IsHighContrastEnabled());
}
bool IsSpokenFeedbackEnabled() const override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled();
}
void ToggleSpokenFeedback(
ui::AccessibilityNotificationVisibility notify) override {
DCHECK(chromeos::AccessibilityManager::Get());
chromeos::AccessibilityManager::Get()->ToggleSpokenFeedback(notify);
}
bool IsHighContrastEnabled() const override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->IsHighContrastEnabled();
}
void SetMagnifierEnabled(bool enabled) override {
DCHECK(chromeos::MagnificationManager::Get());
return chromeos::MagnificationManager::Get()->SetMagnifierEnabled(enabled);
}
void SetMagnifierType(ui::MagnifierType type) override {
DCHECK(chromeos::MagnificationManager::Get());
return chromeos::MagnificationManager::Get()->SetMagnifierType(type);
}
bool IsMagnifierEnabled() const override {
DCHECK(chromeos::MagnificationManager::Get());
return chromeos::MagnificationManager::Get()->IsMagnifierEnabled();
}
ui::MagnifierType GetMagnifierType() const override {
DCHECK(chromeos::MagnificationManager::Get());
return chromeos::MagnificationManager::Get()->GetMagnifierType();
}
void SetLargeCursorEnabled(bool enabled) override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->EnableLargeCursor(enabled);
}
bool IsLargeCursorEnabled() const override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->IsLargeCursorEnabled();
}
void SetAutoclickEnabled(bool enabled) override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->EnableAutoclick(enabled);
}
bool IsAutoclickEnabled() const override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->IsAutoclickEnabled();
}
void SetVirtualKeyboardEnabled(bool enabled) override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->
EnableVirtualKeyboard(enabled);
}
bool IsVirtualKeyboardEnabled() const override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->IsVirtualKeyboardEnabled();
}
bool ShouldShowAccessibilityMenu() const override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->
ShouldShowAccessibilityMenu();
}
bool IsBrailleDisplayConnected() const override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->IsBrailleDisplayConnected();
}
void SilenceSpokenFeedback() const override {
TtsController::GetInstance()->Stop();
}
void SaveScreenMagnifierScale(double scale) override {
if (chromeos::MagnificationManager::Get())
chromeos::MagnificationManager::Get()->SaveScreenMagnifierScale(scale);
}
double GetSavedScreenMagnifierScale() override {
if (chromeos::MagnificationManager::Get()) {
return chromeos::MagnificationManager::Get()->
GetSavedScreenMagnifierScale();
}
return std::numeric_limits<double>::min();
}
void TriggerAccessibilityAlert(ui::AccessibilityAlert alert) override {
Profile* profile = ProfileManager::GetActiveUserProfile();
if (profile) {
switch (alert) {
case ui::A11Y_ALERT_WINDOW_NEEDED: {
AutomationManagerAura::GetInstance()->HandleAlert(
profile, l10n_util::GetStringUTF8(IDS_A11Y_ALERT_WINDOW_NEEDED));
break;
}
case ui::A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED: {
AutomationManagerAura::GetInstance()->HandleAlert(
profile, l10n_util::GetStringUTF8(
IDS_A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED));
break;
}
case ui::A11Y_ALERT_NONE:
break;
}
}
}
ui::AccessibilityAlert GetLastAccessibilityAlert() override {
return ui::A11Y_ALERT_NONE;
}
void PlayEarcon(int sound_key) override {
DCHECK(chromeos::AccessibilityManager::Get());
return chromeos::AccessibilityManager::Get()->PlayEarcon(sound_key);
}
base::TimeDelta PlayShutdownSound() const override {
return chromeos::AccessibilityManager::Get()->PlayShutdownSound();
}
private:
DISALLOW_COPY_AND_ASSIGN(AccessibilityDelegateImpl);
};
} // anonymous namespace
bool ChromeShellDelegate::IsFirstRunAfterBoot() const {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kFirstExecAfterBoot);
}
void ChromeShellDelegate::PreInit() {
chromeos::LoadDisplayPreferences(IsFirstRunAfterBoot());
// Object owns itself, and deletes itself when Observer::OnShutdown is called:
new policy::DisplayRotationDefaultHandler();
// Set the observer now so that we can save the initial state
// in Shell::Init.
display_configuration_observer_.reset(
new chromeos::DisplayConfigurationObserver());
arc_session_observer_.reset(new ArcSessionObserver);
chrome_user_metrics_recorder_.reset(new ChromeUserMetricsRecorder);
}
void ChromeShellDelegate::PreShutdown() {
display_configuration_observer_.reset();
// Remove the ARC observer now since it uses the ash::Shell instance in its
// destructor, which is unavailable after PreShutdown() returns.
arc_session_observer_.reset();
chrome_user_metrics_recorder_.reset();
}
ash::SessionStateDelegate* ChromeShellDelegate::CreateSessionStateDelegate() {
return new SessionStateDelegateChromeos;
}
ash::AccessibilityDelegate* ChromeShellDelegate::CreateAccessibilityDelegate() {
return new AccessibilityDelegateImpl;
}
ash::NewWindowDelegate* ChromeShellDelegate::CreateNewWindowDelegate() {
return new ChromeNewWindowDelegateChromeos;
}
ash::MediaDelegate* ChromeShellDelegate::CreateMediaDelegate() {
return new MediaDelegateChromeOS;
}
ash::SystemTrayDelegate* ChromeShellDelegate::CreateSystemTrayDelegate() {
return chromeos::CreateSystemTrayDelegate();
}
ash::UserWallpaperDelegate* ChromeShellDelegate::CreateUserWallpaperDelegate() {
return chromeos::CreateUserWallpaperDelegate();
}
void ChromeShellDelegate::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED: {
Profile* profile = content::Details<Profile>(details).ptr();
if (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
!profile->IsGuestSession() && !profile->IsSupervised()) {
// Start the error notifier services to show auth/sync notifications.
SigninErrorNotifierFactory::GetForProfile(profile);
SyncErrorNotifierFactory::GetForProfile(profile);
}
// Do not use chrome::NOTIFICATION_PROFILE_ADDED because the
// profile is not fully initialized by user_manager. Use
// chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED instead.
if (shelf_delegate_)
shelf_delegate_->OnUserProfileReadyToSwitch(profile);
ash::Shell::GetInstance()->OnLoginUserProfilePrepared();
break;
}
case chrome::NOTIFICATION_SESSION_STARTED:
// InitAfterFirstSessionStart() should only be called once upon system
// start.
if (user_manager::UserManager::Get()->GetLoggedInUsers().size() < 2)
InitAfterFirstSessionStart();
ash::Shell::GetInstance()->ShowShelf();
break;
default:
NOTREACHED() << "Unexpected notification " << type;
}
}
void ChromeShellDelegate::PlatformInit() {
registrar_.Add(this,
chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
content::NotificationService::AllSources());
registrar_.Add(this,
chrome::NOTIFICATION_SESSION_STARTED,
content::NotificationService::AllSources());
}
ChromeShellDelegate::ArcSessionObserver::ArcSessionObserver() {
ash::Shell::GetInstance()->AddShellObserver(this);
}
ChromeShellDelegate::ArcSessionObserver::~ArcSessionObserver() {
ash::Shell::GetInstance()->RemoveShellObserver(this);
}
void ChromeShellDelegate::ArcSessionObserver::OnLoginStateChanged(
ash::user::LoginStatus status) {
switch (status) {
case ash::user::LOGGED_IN_LOCKED:
case ash::user::LOGGED_IN_KIOSK_APP:
return;
case ash::user::LOGGED_IN_NONE:
arc::ArcServiceManager::Get()->arc_bridge_service()->Shutdown();
break;
case ash::user::LOGGED_IN_USER:
case ash::user::LOGGED_IN_OWNER:
case ash::user::LOGGED_IN_GUEST:
case ash::user::LOGGED_IN_PUBLIC:
case ash::user::LOGGED_IN_SUPERVISED:
if (arc::ArcBridgeService::GetEnabled(
base::CommandLine::ForCurrentProcess())) {
arc::ArcServiceManager::Get()->arc_bridge_service()->HandleStartup();
}
break;
}
}