system_tray_delegate_chromeos.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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/system_tray_delegate_chromeos.h"
6
7#include <algorithm>
8#include <set>
9#include <string>
10#include <vector>
11
12#include "ash/ash_switches.h"
13#include "ash/desktop_background/desktop_background_controller.h"
14#include "ash/ime/input_method_menu_item.h"
15#include "ash/ime/input_method_menu_manager.h"
16#include "ash/metrics/user_metrics_recorder.h"
17#include "ash/session/session_state_delegate.h"
18#include "ash/session/session_state_observer.h"
19#include "ash/shell.h"
20#include "ash/shell_delegate.h"
21#include "ash/shell_window_ids.h"
22#include "ash/system/bluetooth/bluetooth_observer.h"
23#include "ash/system/chromeos/session/logout_button_observer.h"
24#include "ash/system/date/clock_observer.h"
25#include "ash/system/ime/ime_observer.h"
26#include "ash/system/tray/system_tray.h"
27#include "ash/system/tray/system_tray_delegate.h"
28#include "ash/system/tray/system_tray_notifier.h"
29#include "ash/system/tray_accessibility.h"
30#include "ash/system/user/login_status.h"
31#include "ash/system/user/update_observer.h"
32#include "ash/system/user/user_observer.h"
33#include "ash/volume_control_delegate.h"
34#include "ash/wm/lock_state_controller.h"
35#include "base/bind_helpers.h"
36#include "base/callback.h"
37#include "base/logging.h"
38#include "base/memory/weak_ptr.h"
39#include "base/prefs/pref_service.h"
40#include "base/strings/stringprintf.h"
41#include "base/strings/utf_string_conversions.h"
42#include "base/sys_info.h"
43#include "base/time/time.h"
44#include "chrome/browser/browser_process.h"
45#include "chrome/browser/chrome_notification_types.h"
46#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
47#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
48#include "chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.h"
49#include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h"
50#include "chrome/browser/chromeos/enrollment_dialog_view.h"
51#include "chrome/browser/chromeos/events/system_key_event_listener.h"
52#include "chrome/browser/chromeos/input_method/input_method_util.h"
53#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
54#include "chrome/browser/chromeos/login/help_app_launcher.h"
55#include "chrome/browser/chromeos/login/login_wizard.h"
56#include "chrome/browser/chromeos/login/ui/login_display_host.h"
57#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
58#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
59#include "chrome/browser/chromeos/login/user_flow.h"
60#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
61#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
62#include "chrome/browser/chromeos/options/network_config_view.h"
63#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
64#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
65#include "chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.h"
66#include "chrome/browser/chromeos/profiles/profile_helper.h"
67#include "chrome/browser/chromeos/set_time_dialog.h"
68#include "chrome/browser/chromeos/settings/cros_settings.h"
69#include "chrome/browser/chromeos/sim_dialog_delegate.h"
70#include "chrome/browser/chromeos/ui/choose_mobile_network_dialog.h"
71#include "chrome/browser/lifetime/application_lifetime.h"
72#include "chrome/browser/profiles/profile_manager.h"
73#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
74#include "chrome/browser/ui/ash/user_accounts_delegate_chromeos.h"
75#include "chrome/browser/ui/ash/volume_controller_chromeos.h"
76#include "chrome/browser/ui/browser.h"
77#include "chrome/browser/ui/browser_finder.h"
78#include "chrome/browser/ui/browser_list.h"
79#include "chrome/browser/ui/chrome_pages.h"
80#include "chrome/browser/ui/host_desktop.h"
81#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
82#include "chrome/browser/ui/singleton_tabs.h"
83#include "chrome/browser/ui/tabs/tab_strip_model.h"
84#include "chrome/browser/ui/webui/chromeos/charger_replacement_handler.h"
85#include "chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h"
86#include "chrome/browser/upgrade_detector.h"
87#include "chrome/common/chrome_switches.h"
88#include "chrome/common/pref_names.h"
89#include "chrome/common/url_constants.h"
90#include "chromeos/dbus/dbus_thread_manager.h"
91#include "chromeos/dbus/session_manager_client.h"
92#include "chromeos/ime/extension_ime_util.h"
93#include "chromeos/ime/ime_keyboard.h"
94#include "chromeos/ime/input_method_manager.h"
95#include "chromeos/login/login_state.h"
96#include "chromeos/network/portal_detector/network_portal_detector.h"
97#include "components/google/core/browser/google_util.h"
98#include "components/policy/core/common/cloud/cloud_policy_store.h"
99#include "components/user_manager/user.h"
100#include "components/user_manager/user_manager.h"
101#include "components/user_manager/user_type.h"
102#include "content/public/browser/notification_observer.h"
103#include "content/public/browser/notification_service.h"
104#include "content/public/browser/user_metrics.h"
105#include "content/public/browser/web_contents.h"
106#include "device/bluetooth/bluetooth_adapter.h"
107#include "device/bluetooth/bluetooth_adapter_factory.h"
108#include "device/bluetooth/bluetooth_device.h"
109#include "grit/ash_strings.h"
110#include "grit/generated_resources.h"
111#include "grit/locale_settings.h"
112#include "net/base/escape.h"
113#include "third_party/cros_system_api/dbus/service_constants.h"
114#include "ui/base/l10n/l10n_util.h"
115#include "ui/base/l10n/time_format.h"
116
117namespace chromeos {
118
119namespace {
120
121// The minimum session length limit that can be set.
122const int kSessionLengthLimitMinMs = 30 * 1000;  // 30 seconds.
123
124// The maximum session length limit that can be set.
125const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000;  // 24 hours.
126
127const char kDisplaySettingsSubPageName[] = "display";
128const char kDisplayOverscanSettingsSubPageName[] = "displayOverscan";
129
130void ExtractIMEInfo(const input_method::InputMethodDescriptor& ime,
131                    const input_method::InputMethodUtil& util,
132                    ash::IMEInfo* info) {
133  info->id = ime.id();
134  info->name = util.GetInputMethodLongName(ime);
135  info->medium_name = util.GetInputMethodMediumName(ime);
136  info->short_name = util.GetInputMethodShortName(ime);
137  info->third_party = extension_ime_util::IsExtensionIME(ime.id());
138}
139
140gfx::NativeWindow GetNativeWindowByStatus(ash::user::LoginStatus login_status,
141                                          bool session_started) {
142  bool isUserAddingRunning = ash::Shell::GetInstance()
143                                 ->session_state_delegate()
144                                 ->IsInSecondaryLoginScreen();
145
146  int container_id =
147      (!session_started || login_status == ash::user::LOGGED_IN_NONE ||
148       login_status == ash::user::LOGGED_IN_LOCKED || isUserAddingRunning)
149          ? ash::kShellWindowId_LockSystemModalContainer
150          : ash::kShellWindowId_SystemModalContainer;
151  return ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
152                                  container_id);
153}
154
155void BluetoothPowerFailure() {
156  // TODO(sad): Show an error bubble?
157}
158
159void BluetoothSetDiscoveringError() {
160  LOG(ERROR) << "BluetoothSetDiscovering failed.";
161}
162
163void BluetoothDeviceConnectError(
164    device::BluetoothDevice::ConnectErrorCode error_code) {
165  // TODO(sad): Do something?
166}
167
168void ShowSettingsSubPageForActiveUser(const std::string& sub_page) {
169  chrome::ShowSettingsSubPageForProfile(
170      ProfileManager::GetActiveUserProfile(), sub_page);
171}
172
173void ShowNetworkSettingsPage(const std::string& service_path) {
174  std::string page = chrome::kInternetOptionsSubPage;
175  page += "?servicePath=" + net::EscapeUrlEncodedData(service_path, true);
176  content::RecordAction(base::UserMetricsAction("OpenInternetOptionsDialog"));
177  ShowSettingsSubPageForActiveUser(page);
178}
179
180void OnAcceptMultiprofilesIntro(bool no_show_again) {
181  PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
182  prefs->SetBoolean(prefs::kMultiProfileNeverShowIntro, no_show_again);
183  UserAddingScreen::Get()->Start();
184}
185
186}  // namespace
187
188SystemTrayDelegateChromeOS::SystemTrayDelegateChromeOS()
189    : weak_ptr_factory_(this),
190      user_profile_(NULL),
191      clock_type_(base::GetHourClockType()),
192      search_key_mapped_to_(input_method::kSearchKey),
193      screen_locked_(false),
194      have_session_start_time_(false),
195      have_session_length_limit_(false),
196      should_run_bluetooth_discovery_(false),
197      volume_control_delegate_(new VolumeController()),
198      device_settings_observer_(CrosSettings::Get()->AddSettingsObserver(
199          kSystemUse24HourClock,
200          base::Bind(&SystemTrayDelegateChromeOS::UpdateClockType,
201                     base::Unretained(this)))) {
202  // Register notifications on construction so that events such as
203  // PROFILE_CREATED do not get missed if they happen before Initialize().
204  registrar_.reset(new content::NotificationRegistrar);
205  registrar_->Add(this,
206                  chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
207                  content::NotificationService::AllSources());
208  registrar_->Add(this,
209                  chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
210                  content::NotificationService::AllSources());
211  if (GetUserLoginStatus() == ash::user::LOGGED_IN_NONE) {
212    registrar_->Add(this,
213                    chrome::NOTIFICATION_SESSION_STARTED,
214                    content::NotificationService::AllSources());
215  }
216  registrar_->Add(this,
217                  chrome::NOTIFICATION_PROFILE_CREATED,
218                  content::NotificationService::AllSources());
219  registrar_->Add(this,
220                  chrome::NOTIFICATION_PROFILE_DESTROYED,
221                  content::NotificationService::AllSources());
222
223  AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
224  CHECK(accessibility_manager);
225  accessibility_subscription_ = accessibility_manager->RegisterCallback(
226      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityStatusChanged,
227                 base::Unretained(this)));
228}
229
230void SystemTrayDelegateChromeOS::Initialize() {
231  DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
232
233  input_method::InputMethodManager::Get()->AddObserver(this);
234  ash::ime::InputMethodMenuManager::GetInstance()->AddObserver(this);
235  UpdateClockType();
236
237  device::BluetoothAdapterFactory::GetAdapter(
238      base::Bind(&SystemTrayDelegateChromeOS::InitializeOnAdapterReady,
239                 weak_ptr_factory_.GetWeakPtr()));
240
241  ash::Shell::GetInstance()->session_state_delegate()->AddSessionStateObserver(
242      this);
243
244  if (LoginState::IsInitialized())
245    LoginState::Get()->AddObserver(this);
246
247  if (CrasAudioHandler::IsInitialized())
248    CrasAudioHandler::Get()->AddAudioObserver(this);
249
250  BrowserList::AddObserver(this);
251}
252
253void SystemTrayDelegateChromeOS::Shutdown() {
254  device_settings_observer_.reset();
255}
256
257void SystemTrayDelegateChromeOS::InitializeOnAdapterReady(
258    scoped_refptr<device::BluetoothAdapter> adapter) {
259  bluetooth_adapter_ = adapter;
260  CHECK(bluetooth_adapter_.get());
261  bluetooth_adapter_->AddObserver(this);
262
263  local_state_registrar_.reset(new PrefChangeRegistrar);
264  local_state_registrar_->Init(g_browser_process->local_state());
265
266  UpdateSessionStartTime();
267  UpdateSessionLengthLimit();
268
269  local_state_registrar_->Add(
270      prefs::kSessionStartTime,
271      base::Bind(&SystemTrayDelegateChromeOS::UpdateSessionStartTime,
272                 base::Unretained(this)));
273  local_state_registrar_->Add(
274      prefs::kSessionLengthLimit,
275      base::Bind(&SystemTrayDelegateChromeOS::UpdateSessionLengthLimit,
276                 base::Unretained(this)));
277
278  policy::BrowserPolicyConnectorChromeOS* policy_connector =
279      g_browser_process->platform_part()->browser_policy_connector_chromeos();
280  policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
281      policy_connector->GetDeviceCloudPolicyManager();
282  if (policy_manager)
283    policy_manager->core()->store()->AddObserver(this);
284  UpdateEnterpriseDomain();
285}
286
287SystemTrayDelegateChromeOS::~SystemTrayDelegateChromeOS() {
288  // Unregister PrefChangeRegistrars.
289  local_state_registrar_.reset();
290  user_pref_registrar_.reset();
291
292  // Unregister content notifications before destroying any components.
293  registrar_.reset();
294
295  // Unregister a11y status subscription.
296  accessibility_subscription_.reset();
297
298  DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
299  input_method::InputMethodManager::Get()->RemoveObserver(this);
300  ash::ime::InputMethodMenuManager::GetInstance()->RemoveObserver(this);
301  bluetooth_adapter_->RemoveObserver(this);
302  ash::Shell::GetInstance()
303      ->session_state_delegate()
304      ->RemoveSessionStateObserver(this);
305  LoginState::Get()->RemoveObserver(this);
306
307  if (CrasAudioHandler::IsInitialized())
308    CrasAudioHandler::Get()->RemoveAudioObserver(this);
309
310  BrowserList::RemoveObserver(this);
311  StopObservingAppWindowRegistry();
312
313  policy::BrowserPolicyConnectorChromeOS* connector =
314      g_browser_process->platform_part()->browser_policy_connector_chromeos();
315  policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
316      connector->GetDeviceCloudPolicyManager();
317  if (policy_manager)
318    policy_manager->core()->store()->RemoveObserver(this);
319}
320
321// Overridden from ash::SystemTrayDelegate:
322bool SystemTrayDelegateChromeOS::GetTrayVisibilityOnStartup() {
323  // In case of OOBE / sign in screen tray will be shown later.
324  return LoginState::Get()->IsUserLoggedIn();
325}
326
327ash::user::LoginStatus SystemTrayDelegateChromeOS::GetUserLoginStatus() const {
328  // All non-logged in ChromeOS specific LOGGED_IN states map to the same
329  // Ash specific LOGGED_IN state.
330  if (!LoginState::Get()->IsUserLoggedIn())
331    return ash::user::LOGGED_IN_NONE;
332
333  if (screen_locked_)
334    return ash::user::LOGGED_IN_LOCKED;
335
336  LoginState::LoggedInUserType user_type =
337      LoginState::Get()->GetLoggedInUserType();
338  switch (user_type) {
339    case LoginState::LOGGED_IN_USER_NONE:
340      return ash::user::LOGGED_IN_NONE;
341    case LoginState::LOGGED_IN_USER_REGULAR:
342      return ash::user::LOGGED_IN_USER;
343    case LoginState::LOGGED_IN_USER_OWNER:
344      return ash::user::LOGGED_IN_OWNER;
345    case LoginState::LOGGED_IN_USER_GUEST:
346      return ash::user::LOGGED_IN_GUEST;
347    case LoginState::LOGGED_IN_USER_RETAIL_MODE:
348      return ash::user::LOGGED_IN_RETAIL_MODE;
349    case LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT:
350      return ash::user::LOGGED_IN_PUBLIC;
351    case LoginState::LOGGED_IN_USER_SUPERVISED:
352      return ash::user::LOGGED_IN_SUPERVISED;
353    case LoginState::LOGGED_IN_USER_KIOSK_APP:
354      return ash::user::LOGGED_IN_KIOSK_APP;
355  }
356  NOTREACHED();
357  return ash::user::LOGGED_IN_NONE;
358}
359
360void SystemTrayDelegateChromeOS::ChangeProfilePicture() {
361  content::RecordAction(
362      base::UserMetricsAction("OpenChangeProfilePictureDialog"));
363  ShowSettingsSubPageForActiveUser(chrome::kChangeProfilePictureSubPage);
364}
365
366const std::string SystemTrayDelegateChromeOS::GetEnterpriseDomain() const {
367  return enterprise_domain_;
368}
369
370const base::string16 SystemTrayDelegateChromeOS::GetEnterpriseMessage() const {
371  if (GetEnterpriseDomain().empty())
372    return base::string16();
373  return l10n_util::GetStringFUTF16(IDS_DEVICE_OWNED_BY_NOTICE,
374                                    base::UTF8ToUTF16(GetEnterpriseDomain()));
375}
376
377const std::string SystemTrayDelegateChromeOS::GetSupervisedUserManager() const {
378  if (GetUserLoginStatus() != ash::user::LOGGED_IN_SUPERVISED)
379    return std::string();
380  return ChromeUserManager::Get()
381      ->GetSupervisedUserManager()
382      ->GetManagerDisplayEmail(
383          user_manager::UserManager::Get()->GetActiveUser()->email());
384}
385
386const base::string16
387SystemTrayDelegateChromeOS::GetSupervisedUserManagerName() const {
388  if (GetUserLoginStatus() != ash::user::LOGGED_IN_SUPERVISED)
389    return base::string16();
390  return ChromeUserManager::Get()
391      ->GetSupervisedUserManager()
392      ->GetManagerDisplayName(
393          user_manager::UserManager::Get()->GetActiveUser()->email());
394}
395
396const base::string16 SystemTrayDelegateChromeOS::GetSupervisedUserMessage()
397    const {
398  if (GetUserLoginStatus() != ash::user::LOGGED_IN_SUPERVISED)
399    return base::string16();
400  return l10n_util::GetStringFUTF16(
401      IDS_USER_IS_SUPERVISED_BY_NOTICE,
402      base::UTF8ToUTF16(GetSupervisedUserManager()));
403}
404
405bool SystemTrayDelegateChromeOS::SystemShouldUpgrade() const {
406  return UpgradeDetector::GetInstance()->notify_upgrade();
407}
408
409base::HourClockType SystemTrayDelegateChromeOS::GetHourClockType() const {
410  return clock_type_;
411}
412
413void SystemTrayDelegateChromeOS::ShowSettings() {
414  ShowSettingsSubPageForActiveUser("");
415}
416
417bool SystemTrayDelegateChromeOS::ShouldShowSettings() {
418  return ChromeUserManager::Get()->GetCurrentUserFlow()->ShouldShowSettings() &&
419         !ash::Shell::GetInstance()
420              ->session_state_delegate()
421              ->IsInSecondaryLoginScreen();
422}
423
424void SystemTrayDelegateChromeOS::ShowDateSettings() {
425  content::RecordAction(base::UserMetricsAction("ShowDateOptions"));
426  std::string sub_page =
427      std::string(chrome::kSearchSubPage) + "#" +
428      l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
429  // Everybody can change the time zone (even though it is a device setting).
430  ShowSettingsSubPageForActiveUser(sub_page);
431}
432
433void SystemTrayDelegateChromeOS::ShowSetTimeDialog() {
434  SetTimeDialog::ShowDialog(GetNativeWindow());
435}
436
437void SystemTrayDelegateChromeOS::ShowNetworkSettings(
438    const std::string& service_path) {
439  bool userAddingRunning = ash::Shell::GetInstance()
440                               ->session_state_delegate()
441                               ->IsInSecondaryLoginScreen();
442
443  if (!LoginState::Get()->IsUserLoggedIn() || userAddingRunning)
444    return;
445  ShowNetworkSettingsPage(service_path);
446}
447
448void SystemTrayDelegateChromeOS::ShowBluetoothSettings() {
449  // TODO(sad): Make this work.
450}
451
452void SystemTrayDelegateChromeOS::ShowDisplaySettings() {
453  content::RecordAction(base::UserMetricsAction("ShowDisplayOptions"));
454  ShowSettingsSubPageForActiveUser(kDisplaySettingsSubPageName);
455}
456
457void SystemTrayDelegateChromeOS::ShowChromeSlow() {
458  chrome::ScopedTabbedBrowserDisplayer displayer(
459      ProfileManager::GetPrimaryUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
460  chrome::ShowSlow(displayer.browser());
461}
462
463bool SystemTrayDelegateChromeOS::ShouldShowDisplayNotification() {
464  // Packaged app is not counted as 'last active', so if a browser opening the
465  // display settings is in background of a packaged app, it will return true.
466  // TODO(mukai): fix this.
467  Browser* active_browser =
468      chrome::FindLastActiveWithHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH);
469  if (!active_browser)
470    return true;
471
472  content::WebContents* active_contents =
473      active_browser->tab_strip_model()->GetActiveWebContents();
474  if (!active_contents)
475    return true;
476
477  GURL visible_url = active_contents->GetLastCommittedURL();
478  GURL display_settings_url =
479      chrome::GetSettingsUrl(kDisplaySettingsSubPageName);
480  GURL display_overscan_url =
481      chrome::GetSettingsUrl(kDisplayOverscanSettingsSubPageName);
482  return (visible_url != display_settings_url &&
483          visible_url != display_overscan_url);
484}
485
486void SystemTrayDelegateChromeOS::ShowIMESettings() {
487  content::RecordAction(base::UserMetricsAction("OpenLanguageOptionsDialog"));
488  ShowSettingsSubPageForActiveUser(chrome::kLanguageOptionsSubPage);
489}
490
491void SystemTrayDelegateChromeOS::ShowHelp() {
492  chrome::ShowHelpForProfile(ProfileManager::GetActiveUserProfile(),
493                             chrome::HOST_DESKTOP_TYPE_ASH,
494                             chrome::HELP_SOURCE_MENU);
495}
496
497void SystemTrayDelegateChromeOS::ShowAccessibilityHelp() {
498  chrome::ScopedTabbedBrowserDisplayer displayer(
499      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
500  accessibility::ShowAccessibilityHelp(displayer.browser());
501}
502
503void SystemTrayDelegateChromeOS::ShowAccessibilitySettings() {
504  content::RecordAction(base::UserMetricsAction("ShowAccessibilitySettings"));
505  std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
506                         l10n_util::GetStringUTF8(
507                             IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY);
508  ShowSettingsSubPageForActiveUser(sub_page);
509}
510
511void SystemTrayDelegateChromeOS::ShowPublicAccountInfo() {
512  chrome::ScopedTabbedBrowserDisplayer displayer(
513      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
514  chrome::ShowPolicy(displayer.browser());
515}
516
517void SystemTrayDelegateChromeOS::ShowSupervisedUserInfo() {
518  // TODO(antrim): find out what should we show in this case.
519  // http://crbug.com/229762
520}
521
522void SystemTrayDelegateChromeOS::ShowEnterpriseInfo() {
523  ash::user::LoginStatus status = GetUserLoginStatus();
524  bool userAddingRunning = ash::Shell::GetInstance()
525                               ->session_state_delegate()
526                               ->IsInSecondaryLoginScreen();
527
528  if (status == ash::user::LOGGED_IN_NONE ||
529      status == ash::user::LOGGED_IN_LOCKED || userAddingRunning) {
530    scoped_refptr<chromeos::HelpAppLauncher> help_app(
531        new chromeos::HelpAppLauncher(GetNativeWindow()));
532    help_app->ShowHelpTopic(chromeos::HelpAppLauncher::HELP_ENTERPRISE);
533  } else {
534    chrome::ScopedTabbedBrowserDisplayer displayer(
535        ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
536    chrome::ShowSingletonTab(displayer.browser(),
537                             GURL(chrome::kLearnMoreEnterpriseURL));
538  }
539}
540
541void SystemTrayDelegateChromeOS::ShowUserLogin() {
542  ash::Shell* shell = ash::Shell::GetInstance();
543  if (!shell->delegate()->IsMultiProfilesEnabled())
544    return;
545
546  // Only regular users could add other users to current session.
547  if (user_manager::UserManager::Get()->GetActiveUser()->GetType() !=
548      user_manager::USER_TYPE_REGULAR) {
549    return;
550  }
551
552  if (static_cast<int>(
553          user_manager::UserManager::Get()->GetLoggedInUsers().size()) >=
554      shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers())
555    return;
556
557  // Launch sign in screen to add another user to current session.
558  if (user_manager::UserManager::Get()
559          ->GetUsersAdmittedForMultiProfile()
560          .size()) {
561    // Don't show dialog if any logged in user in multi-profiles session
562    // dismissed it.
563    bool show_intro = true;
564    const user_manager::UserList logged_in_users =
565        user_manager::UserManager::Get()->GetLoggedInUsers();
566    for (user_manager::UserList::const_iterator it = logged_in_users.begin();
567         it != logged_in_users.end();
568         ++it) {
569      show_intro &= !multi_user_util::GetProfileFromUserID(
570                         multi_user_util::GetUserIDFromEmail((*it)->email()))
571                         ->GetPrefs()
572                         ->GetBoolean(prefs::kMultiProfileNeverShowIntro);
573      if (!show_intro)
574        break;
575    }
576    if (show_intro) {
577      base::Callback<void(bool)> on_accept =
578          base::Bind(&OnAcceptMultiprofilesIntro);
579      ShowMultiprofilesIntroDialog(on_accept);
580    } else {
581      UserAddingScreen::Get()->Start();
582    }
583  }
584}
585
586bool SystemTrayDelegateChromeOS::ShowSpringChargerReplacementDialog() {
587  if (!ChargerReplacementDialog::ShouldShowDialog())
588    return false;
589
590  ChargerReplacementDialog* dialog =
591      new ChargerReplacementDialog(GetNativeWindow());
592  dialog->Show();
593  return true;
594}
595
596bool SystemTrayDelegateChromeOS::IsSpringChargerReplacementDialogVisible() {
597  return ChargerReplacementDialog::IsDialogVisible();
598}
599
600bool SystemTrayDelegateChromeOS::HasUserConfirmedSafeSpringCharger() {
601  return ChargerReplacementHandler::GetChargerStatusPref() ==
602         ChargerReplacementHandler::CONFIRM_SAFE_CHARGER;
603}
604
605void SystemTrayDelegateChromeOS::ShutDown() {
606  ash::Shell::GetInstance()->lock_state_controller()->RequestShutdown();
607}
608
609void SystemTrayDelegateChromeOS::SignOut() {
610  chrome::AttemptUserExit();
611}
612
613void SystemTrayDelegateChromeOS::RequestLockScreen() {
614  // TODO(antrim) : additional logging for crbug/173178
615  LOG(WARNING) << "Requesting screen lock from AshSystemTrayDelegate";
616  DBusThreadManager::Get()->GetSessionManagerClient()->RequestLockScreen();
617}
618
619void SystemTrayDelegateChromeOS::RequestRestartForUpdate() {
620  // We expect that UpdateEngine is in "Reboot for update" state now.
621  chrome::NotifyAndTerminate(true /* fast path */);
622}
623
624void SystemTrayDelegateChromeOS::GetAvailableBluetoothDevices(
625    ash::BluetoothDeviceList* list) {
626  device::BluetoothAdapter::DeviceList devices =
627      bluetooth_adapter_->GetDevices();
628  for (size_t i = 0; i < devices.size(); ++i) {
629    device::BluetoothDevice* device = devices[i];
630    ash::BluetoothDeviceInfo info;
631    info.address = device->GetAddress();
632    info.display_name = device->GetName();
633    info.connected = device->IsConnected();
634    info.connecting = device->IsConnecting();
635    info.paired = device->IsPaired();
636    list->push_back(info);
637  }
638}
639
640void SystemTrayDelegateChromeOS::BluetoothStartDiscovering() {
641  if (GetBluetoothDiscovering()) {
642    LOG(WARNING) << "Already have active Bluetooth device discovery session.";
643    return;
644  }
645  VLOG(1) << "Requesting new Bluetooth device discovery session.";
646  should_run_bluetooth_discovery_ = true;
647  bluetooth_adapter_->StartDiscoverySession(
648      base::Bind(&SystemTrayDelegateChromeOS::OnStartBluetoothDiscoverySession,
649                 weak_ptr_factory_.GetWeakPtr()),
650      base::Bind(&BluetoothSetDiscoveringError));
651}
652
653void SystemTrayDelegateChromeOS::BluetoothStopDiscovering() {
654  should_run_bluetooth_discovery_ = false;
655  if (!GetBluetoothDiscovering()) {
656    LOG(WARNING) << "No active Bluetooth device discovery session.";
657    return;
658  }
659  VLOG(1) << "Stopping Bluetooth device discovery session.";
660  bluetooth_discovery_session_->Stop(
661      base::Bind(&base::DoNothing), base::Bind(&BluetoothSetDiscoveringError));
662}
663
664void SystemTrayDelegateChromeOS::ConnectToBluetoothDevice(
665    const std::string& address) {
666  device::BluetoothDevice* device = bluetooth_adapter_->GetDevice(address);
667  if (!device || device->IsConnecting() ||
668      (device->IsConnected() && device->IsPaired())) {
669    return;
670  }
671  if (device->IsPaired() && !device->IsConnectable())
672    return;
673  if (device->IsPaired() || !device->IsPairable()) {
674    ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
675        ash::UMA_STATUS_AREA_BLUETOOTH_CONNECT_KNOWN_DEVICE);
676    device->Connect(NULL,
677                    base::Bind(&base::DoNothing),
678                    base::Bind(&BluetoothDeviceConnectError));
679  } else {  // Show paring dialog for the unpaired device.
680    ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
681        ash::UMA_STATUS_AREA_BLUETOOTH_CONNECT_UNKNOWN_DEVICE);
682    BluetoothPairingDialog* dialog =
683        new BluetoothPairingDialog(GetNativeWindow(), device);
684    // The dialog deletes itself on close.
685    dialog->Show();
686  }
687}
688
689bool SystemTrayDelegateChromeOS::IsBluetoothDiscovering() {
690  return bluetooth_adapter_->IsDiscovering();
691}
692
693void SystemTrayDelegateChromeOS::GetCurrentIME(ash::IMEInfo* info) {
694  input_method::InputMethodManager* manager =
695      input_method::InputMethodManager::Get();
696  input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
697  input_method::InputMethodDescriptor ime = manager->GetCurrentInputMethod();
698  ExtractIMEInfo(ime, *util, info);
699  info->selected = true;
700}
701
702void SystemTrayDelegateChromeOS::GetAvailableIMEList(ash::IMEInfoList* list) {
703  input_method::InputMethodManager* manager =
704      input_method::InputMethodManager::Get();
705  input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
706  scoped_ptr<input_method::InputMethodDescriptors> ime_descriptors(
707      manager->GetActiveInputMethods());
708  std::string current = manager->GetCurrentInputMethod().id();
709  for (size_t i = 0; i < ime_descriptors->size(); i++) {
710    input_method::InputMethodDescriptor& ime = ime_descriptors->at(i);
711    ash::IMEInfo info;
712    ExtractIMEInfo(ime, *util, &info);
713    info.selected = ime.id() == current;
714    list->push_back(info);
715  }
716}
717
718void SystemTrayDelegateChromeOS::GetCurrentIMEProperties(
719    ash::IMEPropertyInfoList* list) {
720  ash::ime::InputMethodMenuItemList menu_list =
721      ash::ime::InputMethodMenuManager::GetInstance()->
722      GetCurrentInputMethodMenuItemList();
723  for (size_t i = 0; i < menu_list.size(); ++i) {
724    ash::IMEPropertyInfo property;
725    property.key = menu_list[i].key;
726    property.name = base::UTF8ToUTF16(menu_list[i].label);
727    property.selected = menu_list[i].is_selection_item_checked;
728    list->push_back(property);
729  }
730}
731
732void SystemTrayDelegateChromeOS::SwitchIME(const std::string& ime_id) {
733  input_method::InputMethodManager::Get()->ChangeInputMethod(ime_id);
734}
735
736void SystemTrayDelegateChromeOS::ActivateIMEProperty(const std::string& key) {
737  input_method::InputMethodManager::Get()->ActivateInputMethodMenuItem(key);
738}
739
740void SystemTrayDelegateChromeOS::ShowNetworkConfigure(
741    const std::string& network_id,
742    gfx::NativeWindow parent_window) {
743  NetworkConfigView::Show(network_id, parent_window);
744}
745
746bool SystemTrayDelegateChromeOS::EnrollNetwork(
747    const std::string& network_id,
748    gfx::NativeWindow parent_window) {
749  return enrollment::CreateDialog(network_id, parent_window);
750}
751
752void SystemTrayDelegateChromeOS::ManageBluetoothDevices() {
753  content::RecordAction(base::UserMetricsAction("ShowBluetoothSettingsPage"));
754  std::string sub_page =
755      std::string(chrome::kSearchSubPage) + "#" +
756      l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH);
757  ShowSettingsSubPageForActiveUser(sub_page);
758}
759
760void SystemTrayDelegateChromeOS::ToggleBluetooth() {
761  bluetooth_adapter_->SetPowered(!bluetooth_adapter_->IsPowered(),
762                                 base::Bind(&base::DoNothing),
763                                 base::Bind(&BluetoothPowerFailure));
764}
765
766void SystemTrayDelegateChromeOS::ShowMobileSimDialog() {
767  SimDialogDelegate::ShowDialog(GetNativeWindow(),
768                                SimDialogDelegate::SIM_DIALOG_UNLOCK);
769}
770
771void SystemTrayDelegateChromeOS::ShowMobileSetupDialog(
772    const std::string& service_path) {
773  MobileSetupDialog::Show(service_path);
774}
775
776void SystemTrayDelegateChromeOS::ShowOtherNetworkDialog(
777    const std::string& type) {
778  if (type == shill::kTypeCellular) {
779    ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow());
780    return;
781  }
782  NetworkConfigView::ShowForType(type, GetNativeWindow());
783}
784
785bool SystemTrayDelegateChromeOS::GetBluetoothAvailable() {
786  return bluetooth_adapter_->IsPresent();
787}
788
789bool SystemTrayDelegateChromeOS::GetBluetoothEnabled() {
790  return bluetooth_adapter_->IsPowered();
791}
792
793bool SystemTrayDelegateChromeOS::GetBluetoothDiscovering() {
794  return (bluetooth_discovery_session_.get() &&
795      bluetooth_discovery_session_->IsActive());
796}
797
798void SystemTrayDelegateChromeOS::ChangeProxySettings() {
799  CHECK(GetUserLoginStatus() == ash::user::LOGGED_IN_NONE);
800  LoginDisplayHostImpl::default_host()->OpenProxySettings();
801}
802
803ash::VolumeControlDelegate*
804SystemTrayDelegateChromeOS::GetVolumeControlDelegate() const {
805  return volume_control_delegate_.get();
806}
807
808void SystemTrayDelegateChromeOS::SetVolumeControlDelegate(
809    scoped_ptr<ash::VolumeControlDelegate> delegate) {
810  volume_control_delegate_.swap(delegate);
811}
812
813bool SystemTrayDelegateChromeOS::GetSessionStartTime(
814    base::TimeTicks* session_start_time) {
815  *session_start_time = session_start_time_;
816  return have_session_start_time_;
817}
818
819bool SystemTrayDelegateChromeOS::GetSessionLengthLimit(
820    base::TimeDelta* session_length_limit) {
821  *session_length_limit = session_length_limit_;
822  return have_session_length_limit_;
823}
824
825int SystemTrayDelegateChromeOS::GetSystemTrayMenuWidth() {
826  return l10n_util::GetLocalizedContentsWidthInPixels(
827      IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
828}
829
830void SystemTrayDelegateChromeOS::ActiveUserWasChanged() {
831  GetSystemTrayNotifier()->NotifyUserUpdate();
832}
833
834bool SystemTrayDelegateChromeOS::IsSearchKeyMappedToCapsLock() {
835  return search_key_mapped_to_ == input_method::kCapsLockKey;
836}
837
838ash::tray::UserAccountsDelegate*
839SystemTrayDelegateChromeOS::GetUserAccountsDelegate(
840    const std::string& user_id) {
841  if (!accounts_delegates_.contains(user_id)) {
842    const user_manager::User* user =
843        user_manager::UserManager::Get()->FindUser(user_id);
844    Profile* user_profile = ProfileHelper::Get()->GetProfileByUserUnsafe(user);
845    CHECK(user_profile);
846    accounts_delegates_.set(
847        user_id,
848        scoped_ptr<ash::tray::UserAccountsDelegate>(
849            new UserAccountsDelegateChromeOS(user_profile)));
850  }
851  return accounts_delegates_.get(user_id);
852}
853
854ash::SystemTray* SystemTrayDelegateChromeOS::GetPrimarySystemTray() {
855  return ash::Shell::GetInstance()->GetPrimarySystemTray();
856}
857
858ash::SystemTrayNotifier* SystemTrayDelegateChromeOS::GetSystemTrayNotifier() {
859  return ash::Shell::GetInstance()->system_tray_notifier();
860}
861
862void SystemTrayDelegateChromeOS::SetProfile(Profile* profile) {
863  // Stop observing the AppWindowRegistry of the current |user_profile_|.
864  StopObservingAppWindowRegistry();
865
866  user_profile_ = profile;
867
868  // Start observing the AppWindowRegistry of the newly set |user_profile_|.
869  apps::AppWindowRegistry::Get(user_profile_)->AddObserver(this);
870
871  PrefService* prefs = profile->GetPrefs();
872  user_pref_registrar_.reset(new PrefChangeRegistrar);
873  user_pref_registrar_->Init(prefs);
874  user_pref_registrar_->Add(
875      prefs::kUse24HourClock,
876      base::Bind(&SystemTrayDelegateChromeOS::UpdateClockType,
877                 base::Unretained(this)));
878  user_pref_registrar_->Add(
879      prefs::kLanguageRemapSearchKeyTo,
880      base::Bind(&SystemTrayDelegateChromeOS::OnLanguageRemapSearchKeyToChanged,
881                 base::Unretained(this)));
882  user_pref_registrar_->Add(
883      prefs::kShowLogoutButtonInTray,
884      base::Bind(&SystemTrayDelegateChromeOS::UpdateShowLogoutButtonInTray,
885                 base::Unretained(this)));
886  user_pref_registrar_->Add(
887      prefs::kLogoutDialogDurationMs,
888      base::Bind(&SystemTrayDelegateChromeOS::UpdateLogoutDialogDuration,
889                 base::Unretained(this)));
890  user_pref_registrar_->Add(
891      prefs::kAccessibilityLargeCursorEnabled,
892      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
893                 base::Unretained(this),
894                 ash::A11Y_NOTIFICATION_NONE));
895  user_pref_registrar_->Add(
896      prefs::kAccessibilityAutoclickEnabled,
897      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
898                 base::Unretained(this),
899                 ash::A11Y_NOTIFICATION_NONE));
900  user_pref_registrar_->Add(
901      prefs::kShouldAlwaysShowAccessibilityMenu,
902      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
903                 base::Unretained(this),
904                 ash::A11Y_NOTIFICATION_NONE));
905  user_pref_registrar_->Add(
906      prefs::kPerformanceTracingEnabled,
907      base::Bind(&SystemTrayDelegateChromeOS::UpdatePerformanceTracing,
908                 base::Unretained(this)));
909
910  UpdateClockType();
911  UpdateShowLogoutButtonInTray();
912  UpdateLogoutDialogDuration();
913  UpdatePerformanceTracing();
914  search_key_mapped_to_ =
915      profile->GetPrefs()->GetInteger(prefs::kLanguageRemapSearchKeyTo);
916}
917
918bool SystemTrayDelegateChromeOS::UnsetProfile(Profile* profile) {
919  if (profile != user_profile_)
920    return false;
921  user_pref_registrar_.reset();
922  user_profile_ = NULL;
923  return true;
924}
925
926bool SystemTrayDelegateChromeOS::GetShouldUse24HourClockForTesting() const {
927  return ShouldUse24HourClock();
928}
929
930bool SystemTrayDelegateChromeOS::ShouldUse24HourClock() const {
931  // On login screen and in guest mode owner default is used for
932  // kUse24HourClock preference.
933  const ash::user::LoginStatus status = GetUserLoginStatus();
934  const CrosSettings* const cros_settings = CrosSettings::Get();
935  bool system_use_24_hour_clock = true;
936  const bool system_value_found = cros_settings->GetBoolean(
937      kSystemUse24HourClock, &system_use_24_hour_clock);
938
939  if ((status == ash::user::LOGGED_IN_NONE) || !user_pref_registrar_)
940    return (system_value_found
941                ? system_use_24_hour_clock
942                : (base::GetHourClockType() == base::k24HourClock));
943
944  const PrefService::Preference* user_pref =
945      user_pref_registrar_->prefs()->FindPreference(prefs::kUse24HourClock);
946  if (status == ash::user::LOGGED_IN_GUEST && user_pref->IsDefaultValue())
947    return (system_value_found
948                ? system_use_24_hour_clock
949                : (base::GetHourClockType() == base::k24HourClock));
950
951  bool use_24_hour_clock = true;
952  user_pref->GetValue()->GetAsBoolean(&use_24_hour_clock);
953  return use_24_hour_clock;
954}
955
956void SystemTrayDelegateChromeOS::UpdateClockType() {
957  const bool use_24_hour_clock = ShouldUse24HourClock();
958  clock_type_ = use_24_hour_clock ? base::k24HourClock : base::k12HourClock;
959  GetSystemTrayNotifier()->NotifyDateFormatChanged();
960  // This also works for enterprise-managed devices because they never have
961  // local owner.
962  if (user_manager::UserManager::Get()->IsCurrentUserOwner())
963    CrosSettings::Get()->SetBoolean(kSystemUse24HourClock, use_24_hour_clock);
964}
965
966void SystemTrayDelegateChromeOS::UpdateShowLogoutButtonInTray() {
967  GetSystemTrayNotifier()->NotifyShowLoginButtonChanged(
968      user_pref_registrar_->prefs()->GetBoolean(
969          prefs::kShowLogoutButtonInTray));
970}
971
972void SystemTrayDelegateChromeOS::UpdateLogoutDialogDuration() {
973  const int duration_ms =
974      user_pref_registrar_->prefs()->GetInteger(prefs::kLogoutDialogDurationMs);
975  GetSystemTrayNotifier()->NotifyLogoutDialogDurationChanged(
976      base::TimeDelta::FromMilliseconds(duration_ms));
977}
978
979void SystemTrayDelegateChromeOS::UpdateSessionStartTime() {
980  const PrefService* local_state = local_state_registrar_->prefs();
981  if (local_state->HasPrefPath(prefs::kSessionStartTime)) {
982    have_session_start_time_ = true;
983    session_start_time_ = base::TimeTicks::FromInternalValue(
984        local_state->GetInt64(prefs::kSessionStartTime));
985  } else {
986    have_session_start_time_ = false;
987    session_start_time_ = base::TimeTicks();
988  }
989  GetSystemTrayNotifier()->NotifySessionStartTimeChanged();
990}
991
992void SystemTrayDelegateChromeOS::UpdateSessionLengthLimit() {
993  const PrefService* local_state = local_state_registrar_->prefs();
994  if (local_state->HasPrefPath(prefs::kSessionLengthLimit)) {
995    have_session_length_limit_ = true;
996    session_length_limit_ = base::TimeDelta::FromMilliseconds(
997        std::min(std::max(local_state->GetInteger(prefs::kSessionLengthLimit),
998                          kSessionLengthLimitMinMs),
999                 kSessionLengthLimitMaxMs));
1000  } else {
1001    have_session_length_limit_ = false;
1002    session_length_limit_ = base::TimeDelta();
1003  }
1004  GetSystemTrayNotifier()->NotifySessionLengthLimitChanged();
1005}
1006
1007void SystemTrayDelegateChromeOS::StopObservingAppWindowRegistry() {
1008  if (!user_profile_)
1009    return;
1010
1011  apps::AppWindowRegistry* registry =
1012      apps::AppWindowRegistry::Factory::GetForBrowserContext(user_profile_,
1013                                                             false);
1014  if (registry)
1015    registry->RemoveObserver(this);
1016}
1017
1018void SystemTrayDelegateChromeOS::NotifyIfLastWindowClosed() {
1019  if (!user_profile_)
1020    return;
1021
1022  BrowserList* browser_list =
1023      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
1024  for (BrowserList::const_iterator it = browser_list->begin();
1025       it != browser_list->end();
1026       ++it) {
1027    if ((*it)->profile()->IsSameProfile(user_profile_)) {
1028      // The current user has at least one open browser window.
1029      return;
1030    }
1031  }
1032
1033  if (!apps::AppWindowRegistry::Get(user_profile_)->app_windows().empty()) {
1034    // The current user has at least one open app window.
1035    return;
1036  }
1037
1038  GetSystemTrayNotifier()->NotifyLastWindowClosed();
1039}
1040
1041// LoginState::Observer overrides.
1042void SystemTrayDelegateChromeOS::LoggedInStateChanged() {
1043  // It apparently sometimes takes a while after login before the current user
1044  // is recognized as the owner. Make sure that the system-wide clock setting
1045  // is updated when the recognition eventually happens
1046  // (http://crbug.com/278601).
1047  //
1048  // Note that it isn't safe to blindly call UpdateClockType() from this
1049  // method, as LoggedInStateChanged() is also called before the logged-in
1050  // user's profile has actually been loaded (http://crbug.com/317745). The
1051  // system tray's time format is updated at login via SetProfile().
1052  if (user_manager::UserManager::Get()->IsCurrentUserOwner()) {
1053    CrosSettings::Get()->SetBoolean(kSystemUse24HourClock,
1054                                    ShouldUse24HourClock());
1055  }
1056}
1057
1058// Overridden from SessionManagerClient::Observer.
1059void SystemTrayDelegateChromeOS::ScreenIsLocked() {
1060  screen_locked_ = true;
1061  ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(GetUserLoginStatus());
1062}
1063
1064void SystemTrayDelegateChromeOS::ScreenIsUnlocked() {
1065  screen_locked_ = false;
1066  ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(GetUserLoginStatus());
1067}
1068
1069gfx::NativeWindow SystemTrayDelegateChromeOS::GetNativeWindow() const {
1070  bool session_started = ash::Shell::GetInstance()
1071                             ->session_state_delegate()
1072                             ->IsActiveUserSessionStarted();
1073  return GetNativeWindowByStatus(GetUserLoginStatus(), session_started);
1074}
1075
1076// content::NotificationObserver implementation.
1077void SystemTrayDelegateChromeOS::Observe(
1078    int type,
1079    const content::NotificationSource& source,
1080    const content::NotificationDetails& details) {
1081  switch (type) {
1082    case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: {
1083      UpgradeDetector* detector =
1084          content::Source<UpgradeDetector>(source).ptr();
1085      ash::UpdateObserver::UpdateSeverity severity =
1086          ash::UpdateObserver::UPDATE_NORMAL;
1087      switch (detector->upgrade_notification_stage()) {
1088        case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
1089          severity = ash::UpdateObserver::UPDATE_SEVERE_RED;
1090          break;
1091
1092        case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
1093          severity = ash::UpdateObserver::UPDATE_HIGH_ORANGE;
1094          break;
1095
1096        case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
1097          severity = ash::UpdateObserver::UPDATE_LOW_GREEN;
1098          break;
1099
1100        case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
1101        default:
1102          severity = ash::UpdateObserver::UPDATE_NORMAL;
1103          break;
1104      }
1105      GetSystemTrayNotifier()->NotifyUpdateRecommended(severity);
1106      break;
1107    }
1108    case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
1109      // This notification is also sent on login screen when user avatar
1110      // is loaded from file.
1111      if (GetUserLoginStatus() != ash::user::LOGGED_IN_NONE) {
1112        GetSystemTrayNotifier()->NotifyUserUpdate();
1113      }
1114      break;
1115    }
1116    case chrome::NOTIFICATION_PROFILE_CREATED: {
1117      SetProfile(content::Source<Profile>(source).ptr());
1118      registrar_->Remove(this,
1119                         chrome::NOTIFICATION_PROFILE_CREATED,
1120                         content::NotificationService::AllSources());
1121      break;
1122    }
1123    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
1124      if (UnsetProfile(content::Source<Profile>(source).ptr())) {
1125        registrar_->Remove(this,
1126                           chrome::NOTIFICATION_PROFILE_DESTROYED,
1127                           content::NotificationService::AllSources());
1128      }
1129      break;
1130    }
1131    case chrome::NOTIFICATION_SESSION_STARTED: {
1132      ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(
1133          GetUserLoginStatus());
1134      SetProfile(ProfileManager::GetActiveUserProfile());
1135      break;
1136    }
1137    default:
1138      NOTREACHED();
1139  }
1140}
1141
1142void SystemTrayDelegateChromeOS::OnLanguageRemapSearchKeyToChanged() {
1143  search_key_mapped_to_ = user_pref_registrar_->prefs()->GetInteger(
1144      prefs::kLanguageRemapSearchKeyTo);
1145}
1146
1147void SystemTrayDelegateChromeOS::OnAccessibilityModeChanged(
1148    ash::AccessibilityNotificationVisibility notify) {
1149  GetSystemTrayNotifier()->NotifyAccessibilityModeChanged(notify);
1150}
1151
1152void SystemTrayDelegateChromeOS::UpdatePerformanceTracing() {
1153  if (!user_pref_registrar_)
1154    return;
1155  bool value = user_pref_registrar_->prefs()->GetBoolean(
1156      prefs::kPerformanceTracingEnabled);
1157  GetSystemTrayNotifier()->NotifyTracingModeChanged(value);
1158}
1159
1160// Overridden from InputMethodManager::Observer.
1161void SystemTrayDelegateChromeOS::InputMethodChanged(
1162    input_method::InputMethodManager* manager,
1163    bool show_message) {
1164  GetSystemTrayNotifier()->NotifyRefreshIME();
1165}
1166
1167// Overridden from InputMethodMenuManager::Observer.
1168void SystemTrayDelegateChromeOS::InputMethodMenuItemChanged(
1169    ash::ime::InputMethodMenuManager* manager) {
1170  GetSystemTrayNotifier()->NotifyRefreshIME();
1171}
1172
1173// Overridden from CrasAudioHandler::AudioObserver.
1174void SystemTrayDelegateChromeOS::OnOutputVolumeChanged() {
1175  GetSystemTrayNotifier()->NotifyAudioOutputVolumeChanged();
1176}
1177
1178void SystemTrayDelegateChromeOS::OnOutputMuteChanged() {
1179  GetSystemTrayNotifier()->NotifyAudioOutputMuteChanged();
1180}
1181
1182void SystemTrayDelegateChromeOS::OnInputGainChanged() {
1183}
1184
1185void SystemTrayDelegateChromeOS::OnInputMuteChanged() {
1186}
1187
1188void SystemTrayDelegateChromeOS::OnAudioNodesChanged() {
1189  GetSystemTrayNotifier()->NotifyAudioNodesChanged();
1190}
1191
1192void SystemTrayDelegateChromeOS::OnActiveOutputNodeChanged() {
1193  GetSystemTrayNotifier()->NotifyAudioActiveOutputNodeChanged();
1194}
1195
1196void SystemTrayDelegateChromeOS::OnActiveInputNodeChanged() {
1197  GetSystemTrayNotifier()->NotifyAudioActiveInputNodeChanged();
1198}
1199
1200// Overridden from BluetoothAdapter::Observer.
1201void SystemTrayDelegateChromeOS::AdapterPresentChanged(
1202    device::BluetoothAdapter* adapter,
1203    bool present) {
1204  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1205}
1206
1207void SystemTrayDelegateChromeOS::AdapterPoweredChanged(
1208    device::BluetoothAdapter* adapter,
1209    bool powered) {
1210  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1211}
1212
1213void SystemTrayDelegateChromeOS::AdapterDiscoveringChanged(
1214    device::BluetoothAdapter* adapter,
1215    bool discovering) {
1216  GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
1217}
1218
1219void SystemTrayDelegateChromeOS::DeviceAdded(device::BluetoothAdapter* adapter,
1220                                             device::BluetoothDevice* device) {
1221  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1222}
1223
1224void SystemTrayDelegateChromeOS::DeviceChanged(
1225    device::BluetoothAdapter* adapter,
1226    device::BluetoothDevice* device) {
1227  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1228}
1229
1230void SystemTrayDelegateChromeOS::DeviceRemoved(
1231    device::BluetoothAdapter* adapter,
1232    device::BluetoothDevice* device) {
1233  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1234}
1235
1236void SystemTrayDelegateChromeOS::OnStartBluetoothDiscoverySession(
1237    scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
1238  // If the discovery session was returned after a request to stop discovery
1239  // (e.g. the user dismissed the Bluetooth detailed view before the call
1240  // returned), don't claim the discovery session and let it clean up.
1241  if (!should_run_bluetooth_discovery_)
1242    return;
1243  VLOG(1) << "Claiming new Bluetooth device discovery session.";
1244  bluetooth_discovery_session_ = discovery_session.Pass();
1245  GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
1246}
1247
1248void SystemTrayDelegateChromeOS::UpdateEnterpriseDomain() {
1249  policy::BrowserPolicyConnectorChromeOS* connector =
1250      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1251  std::string enterprise_domain = connector->GetEnterpriseDomain();
1252  if (enterprise_domain_ != enterprise_domain) {
1253    enterprise_domain_ = enterprise_domain;
1254    GetSystemTrayNotifier()->NotifyEnterpriseDomainChanged();
1255  }
1256}
1257
1258// Overridden from CloudPolicyStore::Observer
1259void SystemTrayDelegateChromeOS::OnStoreLoaded(
1260    policy::CloudPolicyStore* store) {
1261  UpdateEnterpriseDomain();
1262}
1263
1264void SystemTrayDelegateChromeOS::OnStoreError(policy::CloudPolicyStore* store) {
1265  UpdateEnterpriseDomain();
1266}
1267
1268// Overridden from ash::SessionStateObserver
1269void SystemTrayDelegateChromeOS::UserAddedToSession(
1270    const std::string& user_id) {
1271  GetSystemTrayNotifier()->NotifyUserAddedToSession();
1272}
1273
1274// Overridden from chrome::BrowserListObserver.
1275void SystemTrayDelegateChromeOS::OnBrowserRemoved(Browser* browser) {
1276  NotifyIfLastWindowClosed();
1277}
1278
1279// Overridden from apps::AppWindowRegistry::Observer.
1280void SystemTrayDelegateChromeOS::OnAppWindowRemoved(
1281    apps::AppWindow* app_window) {
1282  NotifyIfLastWindowClosed();
1283}
1284
1285void SystemTrayDelegateChromeOS::OnAccessibilityStatusChanged(
1286    const AccessibilityStatusEventDetails& details) {
1287  if (details.notification_type == ACCESSIBILITY_MANAGER_SHUTDOWN)
1288    accessibility_subscription_.reset();
1289  else
1290    OnAccessibilityModeChanged(details.notify);
1291}
1292
1293ash::SystemTrayDelegate* CreateSystemTrayDelegate() {
1294  return new SystemTrayDelegateChromeOS();
1295}
1296
1297}  // namespace chromeos
1298