1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/ash/chrome_shell_delegate.h"
6
7#include "ash/accelerators/magnifier_key_scroller.h"
8#include "ash/accelerators/spoken_feedback_toggler.h"
9#include "ash/accessibility_delegate.h"
10#include "ash/wm/mru_window_tracker.h"
11#include "ash/wm/window_util.h"
12#include "base/command_line.h"
13#include "base/prefs/pref_service.h"
14#include "chrome/browser/accessibility/accessibility_events.h"
15#include "chrome/browser/app_mode/app_mode_utils.h"
16#include "chrome/browser/chrome_notification_types.h"
17#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
18#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
19#include "chrome/browser/chromeos/background/ash_user_wallpaper_delegate.h"
20#include "chrome/browser/chromeos/display/display_configuration_observer.h"
21#include "chrome/browser/chromeos/display/display_preferences.h"
22#include "chrome/browser/chromeos/profiles/profile_helper.h"
23#include "chrome/browser/profiles/profile.h"
24#include "chrome/browser/profiles/profile_manager.h"
25#include "chrome/browser/signin/signin_error_notifier_factory_ash.h"
26#include "chrome/browser/speech/tts_controller.h"
27#include "chrome/browser/sync/sync_error_notifier_factory_ash.h"
28#include "chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.h"
29#include "chrome/browser/ui/ash/media_delegate_chromeos.h"
30#include "chrome/browser/ui/ash/session_state_delegate_chromeos.h"
31#include "chrome/browser/ui/ash/system_tray_delegate_chromeos.h"
32#include "chrome/browser/ui/browser.h"
33#include "chrome/browser/ui/browser_finder.h"
34#include "chrome/browser/ui/browser_window.h"
35#include "chrome/common/pref_names.h"
36#include "chrome/grit/generated_resources.h"
37#include "chromeos/chromeos_switches.h"
38#include "chromeos/ime/input_method_manager.h"
39#include "content/public/browser/notification_service.h"
40#include "content/public/browser/user_metrics.h"
41#include "ui/aura/window.h"
42#include "ui/base/l10n/l10n_util.h"
43
44namespace {
45
46void InitAfterSessionStart() {
47  // Restore focus after the user session is started.  It's needed because some
48  // windows can be opened in background while login UI is still active because
49  // we currently restore browser windows before login UI is deleted.
50  ash::Shell* shell = ash::Shell::GetInstance();
51  ash::MruWindowTracker::WindowList mru_list =
52      shell->mru_window_tracker()->BuildMruWindowList();
53  if (!mru_list.empty())
54    mru_list.front()->Focus();
55
56#if defined(USE_X11)
57  // Enable magnifier scroll keys as there may be no mouse cursor in kiosk mode.
58  ash::MagnifierKeyScroller::SetEnabled(chrome::IsRunningInForcedAppMode());
59
60  // Enable long press action to toggle spoken feedback with hotrod
61  // remote which can't handle shortcut.
62  ash::SpokenFeedbackToggler::SetEnabled(chrome::IsRunningInForcedAppMode());
63#endif
64}
65
66class AccessibilityDelegateImpl : public ash::AccessibilityDelegate {
67 public:
68  AccessibilityDelegateImpl() {}
69  virtual ~AccessibilityDelegateImpl() {}
70
71  virtual void ToggleHighContrast() OVERRIDE {
72    DCHECK(chromeos::AccessibilityManager::Get());
73    chromeos::AccessibilityManager::Get()->EnableHighContrast(
74        !chromeos::AccessibilityManager::Get()->IsHighContrastEnabled());
75  }
76
77  virtual bool IsSpokenFeedbackEnabled() const OVERRIDE {
78    DCHECK(chromeos::AccessibilityManager::Get());
79    return chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled();
80  }
81
82  virtual void ToggleSpokenFeedback(
83      ash::AccessibilityNotificationVisibility notify) OVERRIDE {
84    DCHECK(chromeos::AccessibilityManager::Get());
85    chromeos::AccessibilityManager::Get()->ToggleSpokenFeedback(notify);
86  }
87
88  virtual bool IsHighContrastEnabled() const OVERRIDE {
89    DCHECK(chromeos::AccessibilityManager::Get());
90    return chromeos::AccessibilityManager::Get()->IsHighContrastEnabled();
91  }
92
93  virtual void SetMagnifierEnabled(bool enabled) OVERRIDE {
94    DCHECK(chromeos::MagnificationManager::Get());
95    return chromeos::MagnificationManager::Get()->SetMagnifierEnabled(enabled);
96  }
97
98  virtual void SetMagnifierType(ash::MagnifierType type) OVERRIDE {
99    DCHECK(chromeos::MagnificationManager::Get());
100    return chromeos::MagnificationManager::Get()->SetMagnifierType(type);
101  }
102
103  virtual bool IsMagnifierEnabled() const OVERRIDE {
104    DCHECK(chromeos::MagnificationManager::Get());
105    return chromeos::MagnificationManager::Get()->IsMagnifierEnabled();
106  }
107
108  virtual ash::MagnifierType GetMagnifierType() const OVERRIDE {
109    DCHECK(chromeos::MagnificationManager::Get());
110    return chromeos::MagnificationManager::Get()->GetMagnifierType();
111  }
112
113  virtual void SetLargeCursorEnabled(bool enabled) OVERRIDE {
114    DCHECK(chromeos::AccessibilityManager::Get());
115    return chromeos::AccessibilityManager::Get()->EnableLargeCursor(enabled);
116  }
117
118  virtual bool IsLargeCursorEnabled() const OVERRIDE {
119    DCHECK(chromeos::AccessibilityManager::Get());
120    return chromeos::AccessibilityManager::Get()->IsLargeCursorEnabled();
121  }
122
123  virtual void SetAutoclickEnabled(bool enabled) OVERRIDE {
124    DCHECK(chromeos::AccessibilityManager::Get());
125    return chromeos::AccessibilityManager::Get()->EnableAutoclick(enabled);
126  }
127
128  virtual bool IsAutoclickEnabled() const OVERRIDE {
129    DCHECK(chromeos::AccessibilityManager::Get());
130    return chromeos::AccessibilityManager::Get()->IsAutoclickEnabled();
131  }
132
133  virtual void SetVirtualKeyboardEnabled(bool enabled) OVERRIDE {
134    DCHECK(chromeos::AccessibilityManager::Get());
135    return chromeos::AccessibilityManager::Get()->
136        EnableVirtualKeyboard(enabled);
137  }
138
139  virtual bool IsVirtualKeyboardEnabled() const OVERRIDE {
140    DCHECK(chromeos::AccessibilityManager::Get());
141    return chromeos::AccessibilityManager::Get()->IsVirtualKeyboardEnabled();
142  }
143
144  virtual bool ShouldShowAccessibilityMenu() const OVERRIDE {
145    DCHECK(chromeos::AccessibilityManager::Get());
146    return chromeos::AccessibilityManager::Get()->
147        ShouldShowAccessibilityMenu();
148  }
149
150  virtual bool IsBrailleDisplayConnected() const OVERRIDE {
151    DCHECK(chromeos::AccessibilityManager::Get());
152    return chromeos::AccessibilityManager::Get()->IsBrailleDisplayConnected();
153  }
154
155  virtual void SilenceSpokenFeedback() const OVERRIDE {
156    TtsController::GetInstance()->Stop();
157  }
158
159  virtual void SaveScreenMagnifierScale(double scale) OVERRIDE {
160    if (chromeos::MagnificationManager::Get())
161      chromeos::MagnificationManager::Get()->SaveScreenMagnifierScale(scale);
162  }
163
164  virtual double GetSavedScreenMagnifierScale() OVERRIDE {
165    if (chromeos::MagnificationManager::Get()) {
166      return chromeos::MagnificationManager::Get()->
167          GetSavedScreenMagnifierScale();
168    }
169    return std::numeric_limits<double>::min();
170  }
171
172  virtual void TriggerAccessibilityAlert(
173      ash::AccessibilityAlert alert) OVERRIDE {
174    Profile* profile = ProfileManager::GetActiveUserProfile();
175    if (profile) {
176      switch (alert) {
177        case ash::A11Y_ALERT_WINDOW_NEEDED: {
178          AccessibilityAlertInfo event(
179              profile, l10n_util::GetStringUTF8(IDS_A11Y_ALERT_WINDOW_NEEDED));
180          SendControlAccessibilityNotification(
181              ui::AX_EVENT_ALERT, &event);
182          break;
183        }
184        case ash::A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED: {
185          AccessibilityAlertInfo event(
186              profile, l10n_util::GetStringUTF8(
187                  IDS_A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED));
188          SendControlAccessibilityNotification(
189              ui::AX_EVENT_ALERT, &event);
190          break;
191        }
192        case ash::A11Y_ALERT_NONE:
193          break;
194      }
195    }
196  }
197
198  virtual ash::AccessibilityAlert GetLastAccessibilityAlert() OVERRIDE {
199    return ash::A11Y_ALERT_NONE;
200  }
201
202  virtual void PlayEarcon(int sound_key) OVERRIDE {
203    DCHECK(chromeos::AccessibilityManager::Get());
204    return chromeos::AccessibilityManager::Get()->PlayEarcon(sound_key);
205  }
206
207  virtual base::TimeDelta PlayShutdownSound() const OVERRIDE {
208    return chromeos::AccessibilityManager::Get()->PlayShutdownSound();
209  }
210
211 private:
212  DISALLOW_COPY_AND_ASSIGN(AccessibilityDelegateImpl);
213};
214
215}  // anonymous namespace
216
217bool ChromeShellDelegate::IsFirstRunAfterBoot() const {
218  return CommandLine::ForCurrentProcess()->HasSwitch(
219      chromeos::switches::kFirstExecAfterBoot);
220}
221
222void ChromeShellDelegate::PreInit() {
223  chromeos::LoadDisplayPreferences(IsFirstRunAfterBoot());
224  // Set the observer now so that we can save the initial state
225  // in Shell::Init.
226  display_configuration_observer_.reset(
227      new chromeos::DisplayConfigurationObserver());
228}
229
230void ChromeShellDelegate::PreShutdown() {
231  display_configuration_observer_.reset();
232}
233
234ash::SessionStateDelegate* ChromeShellDelegate::CreateSessionStateDelegate() {
235  return new SessionStateDelegateChromeos;
236}
237
238ash::AccessibilityDelegate* ChromeShellDelegate::CreateAccessibilityDelegate() {
239  return new AccessibilityDelegateImpl;
240}
241
242ash::NewWindowDelegate* ChromeShellDelegate::CreateNewWindowDelegate() {
243  return new ChromeNewWindowDelegateChromeos;
244}
245
246ash::MediaDelegate* ChromeShellDelegate::CreateMediaDelegate() {
247  return new MediaDelegateChromeOS;
248}
249
250ash::SystemTrayDelegate* ChromeShellDelegate::CreateSystemTrayDelegate() {
251  return chromeos::CreateSystemTrayDelegate();
252}
253
254ash::UserWallpaperDelegate* ChromeShellDelegate::CreateUserWallpaperDelegate() {
255  return chromeos::CreateUserWallpaperDelegate();
256}
257
258void ChromeShellDelegate::Observe(int type,
259                                  const content::NotificationSource& source,
260                                  const content::NotificationDetails& details) {
261  switch (type) {
262    case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED: {
263      Profile* profile = content::Details<Profile>(details).ptr();
264      if (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
265          !profile->IsGuestSession() && !profile->IsSupervised()) {
266        // Start the error notifier services to show auth/sync notifications.
267        SigninErrorNotifierFactory::GetForProfile(profile);
268        SyncErrorNotifierFactory::GetForProfile(profile);
269      }
270      ash::Shell::GetInstance()->OnLoginUserProfilePrepared();
271      break;
272    }
273    case chrome::NOTIFICATION_SESSION_STARTED:
274      InitAfterSessionStart();
275      ash::Shell::GetInstance()->ShowShelf();
276      break;
277    default:
278      NOTREACHED() << "Unexpected notification " << type;
279  }
280}
281
282void ChromeShellDelegate::PlatformInit() {
283  registrar_.Add(this,
284                 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
285                 content::NotificationService::AllSources());
286  registrar_.Add(this,
287                 chrome::NOTIFICATION_SESSION_STARTED,
288                 content::NotificationService::AllSources());
289}
290