root/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ExtractIMEInfo
  2. GetNativeWindowByStatus
  3. ConvertToDriveOperationStatus
  4. ConvertToFinishedDriveOperationStatus
  5. ConvertToDriveStatusList
  6. BluetoothPowerFailure
  7. BluetoothSetDiscoveringError
  8. BluetoothDeviceConnectError
  9. ShowSettingsSubPageForActiveUser
  10. ShowNetworkSettingsPage
  11. OnAcceptMultiprofilesIntro
  12. device_settings_observer_
  13. Initialize
  14. Shutdown
  15. InitializeOnAdapterReady
  16. GetTrayVisibilityOnStartup
  17. GetUserLoginStatus
  18. IsOobeCompleted
  19. ChangeProfilePicture
  20. GetEnterpriseDomain
  21. GetEnterpriseMessage
  22. GetLocallyManagedUserManager
  23. GetLocallyManagedUserManagerName
  24. GetLocallyManagedUserMessage
  25. SystemShouldUpgrade
  26. GetHourClockType
  27. ShowSettings
  28. ShouldShowSettings
  29. ShowDateSettings
  30. ShowNetworkSettings
  31. ShowBluetoothSettings
  32. ShowDisplaySettings
  33. ShowChromeSlow
  34. ShouldShowDisplayNotification
  35. ShowDriveSettings
  36. ShowIMESettings
  37. ShowHelp
  38. ShowAccessibilityHelp
  39. ShowAccessibilitySettings
  40. ShowPublicAccountInfo
  41. ShowLocallyManagedUserInfo
  42. ShowEnterpriseInfo
  43. ShowUserLogin
  44. ShowSpringChargerReplacementDialog
  45. IsSpringChargerReplacementDialogVisible
  46. HasUserConfirmedSafeSpringCharger
  47. ShutDown
  48. SignOut
  49. RequestLockScreen
  50. RequestRestartForUpdate
  51. GetAvailableBluetoothDevices
  52. BluetoothStartDiscovering
  53. BluetoothStopDiscovering
  54. ConnectToBluetoothDevice
  55. IsBluetoothDiscovering
  56. GetCurrentIME
  57. GetAvailableIMEList
  58. GetCurrentIMEProperties
  59. SwitchIME
  60. ActivateIMEProperty
  61. CancelDriveOperation
  62. GetDriveOperationStatusList
  63. ShowNetworkConfigure
  64. EnrollNetwork
  65. ManageBluetoothDevices
  66. ToggleBluetooth
  67. ShowMobileSimDialog
  68. ShowMobileSetupDialog
  69. ShowOtherNetworkDialog
  70. GetBluetoothAvailable
  71. GetBluetoothEnabled
  72. GetBluetoothDiscovering
  73. ChangeProxySettings
  74. GetVolumeControlDelegate
  75. SetVolumeControlDelegate
  76. GetSessionStartTime
  77. GetSessionLengthLimit
  78. GetSystemTrayMenuWidth
  79. ActiveUserWasChanged
  80. IsNetworkBehindCaptivePortal
  81. IsSearchKeyMappedToCapsLock
  82. GetPrimarySystemTray
  83. GetSystemTrayNotifier
  84. SetProfile
  85. UnsetProfile
  86. ObserveDriveUpdates
  87. UnobserveDriveUpdates
  88. GetShouldUse24HourClockForTesting
  89. ShouldUse24HourClock
  90. UpdateClockType
  91. UpdateShowLogoutButtonInTray
  92. UpdateLogoutDialogDuration
  93. UpdateSessionStartTime
  94. UpdateSessionLengthLimit
  95. StopObservingAppWindowRegistry
  96. NotifyIfLastWindowClosed
  97. LoggedInStateChanged
  98. ScreenIsLocked
  99. ScreenIsUnlocked
  100. GetNativeWindow
  101. Observe
  102. OnLanguageRemapSearchKeyToChanged
  103. OnAccessibilityModeChanged
  104. UpdatePerformanceTracing
  105. InputMethodChanged
  106. InputMethodMenuItemChanged
  107. OnOutputVolumeChanged
  108. OnOutputMuteChanged
  109. OnInputGainChanged
  110. OnInputMuteChanged
  111. OnAudioNodesChanged
  112. OnActiveOutputNodeChanged
  113. OnActiveInputNodeChanged
  114. OnJobAdded
  115. OnJobDone
  116. OnJobUpdated
  117. FindDriveIntegrationService
  118. AdapterPresentChanged
  119. AdapterPoweredChanged
  120. AdapterDiscoveringChanged
  121. DeviceAdded
  122. DeviceChanged
  123. DeviceRemoved
  124. OnStartBluetoothDiscoverySession
  125. UpdateEnterpriseDomain
  126. OnStoreLoaded
  127. OnStoreError
  128. UserAddedToSession
  129. OnBrowserRemoved
  130. OnAppWindowAdded
  131. OnAppWindowIconChanged
  132. OnAppWindowRemoved
  133. OnAccessibilityStatusChanged
  134. CreateSystemTrayDelegate

// 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/system_tray_delegate_chromeos.h"

#include <algorithm>
#include <set>
#include <string>
#include <vector>

#include "ash/ash_switches.h"
#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/ime/input_method_menu_item.h"
#include "ash/ime/input_method_menu_manager.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/session_state_delegate.h"
#include "ash/session_state_observer.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
#include "ash/system/bluetooth/bluetooth_observer.h"
#include "ash/system/chromeos/session/logout_button_observer.h"
#include "ash/system/date/clock_observer.h"
#include "ash/system/drive/drive_observer.h"
#include "ash/system/ime/ime_observer.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/tray_accessibility.h"
#include "ash/system/user/login_status.h"
#include "ash/system/user/update_observer.h"
#include "ash/system/user/user_observer.h"
#include "ash/volume_control_delegate.h"
#include "ash/wm/lock_state_controller.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.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/bluetooth/bluetooth_pairing_dialog.h"
#include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h"
#include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
#include "chrome/browser/chromeos/drive/drive_integration_service.h"
#include "chrome/browser/chromeos/drive/job_list.h"
#include "chrome/browser/chromeos/enrollment_dialog_view.h"
#include "chrome/browser/chromeos/events/system_key_event_listener.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
#include "chrome/browser/chromeos/login/help_app_launcher.h"
#include "chrome/browser/chromeos/login/login_display_host.h"
#include "chrome/browser/chromeos/login/login_display_host_impl.h"
#include "chrome/browser/chromeos/login/login_wizard.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/supervised_user_manager.h"
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_adding_screen.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/net/network_portal_detector.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
#include "chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/sim_dialog_delegate.h"
#include "chrome/browser/drive/drive_service_interface.h"
#include "chrome/browser/feedback/tracing_manager.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/browser/ui/ash/volume_controller_chromeos.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/webui/chromeos/charger_replacement_handler.h"
#include "chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/ime/extension_ime_util.h"
#include "chromeos/ime/input_method_manager.h"
#include "chromeos/ime/xkeyboard.h"
#include "chromeos/login/login_state.h"
#include "components/policy/core/common/cloud/cloud_policy_store.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "grit/ash_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "net/base/escape.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/time_format.h"

using drive::DriveIntegrationService;
using drive::DriveIntegrationServiceFactory;

namespace chromeos {

namespace {

// The minimum session length limit that can be set.
const int kSessionLengthLimitMinMs = 30 * 1000;  // 30 seconds.

// The maximum session length limit that can be set.
const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000;  // 24 hours.

const char kDisplaySettingsSubPageName[] = "display";
const char kDisplayOverscanSettingsSubPageName[] = "displayOverscan";

// The URL for the Google Drive settings page.
const char kDriveSettingsPageURL[] = "https://drive.google.com";

void ExtractIMEInfo(const input_method::InputMethodDescriptor& ime,
                    const input_method::InputMethodUtil& util,
                    ash::IMEInfo* info) {
  info->id = ime.id();
  info->name = util.GetInputMethodLongName(ime);
  info->medium_name = util.GetInputMethodMediumName(ime);
  info->short_name = util.GetInputMethodShortName(ime);
  info->third_party = extension_ime_util::IsExtensionIME(ime.id());
}

gfx::NativeWindow GetNativeWindowByStatus(ash::user::LoginStatus login_status,
                                          bool session_started) {
  int container_id =
      (!session_started || login_status == ash::user::LOGGED_IN_NONE ||
       login_status == ash::user::LOGGED_IN_LOCKED)
          ? ash::kShellWindowId_LockSystemModalContainer
          : ash::kShellWindowId_SystemModalContainer;
  return ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
                                  container_id);
}

// Converts drive::JobInfo to ash::DriveOperationStatus.
// If the job is not of type that ash tray is interested, returns false.
bool ConvertToDriveOperationStatus(const drive::JobInfo& info,
                                   ash::DriveOperationStatus* status) {
  if (info.job_type == drive::TYPE_DOWNLOAD_FILE) {
    status->type = ash::DriveOperationStatus::OPERATION_DOWNLOAD;
  } else if (info.job_type == drive::TYPE_UPLOAD_NEW_FILE ||
             info.job_type == drive::TYPE_UPLOAD_EXISTING_FILE) {
    status->type = ash::DriveOperationStatus::OPERATION_UPLOAD;
  } else {
    return false;
  }

  if (info.state == drive::STATE_NONE)
    status->state = ash::DriveOperationStatus::OPERATION_NOT_STARTED;
  else
    status->state = ash::DriveOperationStatus::OPERATION_IN_PROGRESS;

  status->id = info.job_id;
  status->file_path = info.file_path;
  status->progress = info.num_total_bytes == 0 ? 0.0 :
      static_cast<double>(info.num_completed_bytes) /
          static_cast<double>(info.num_total_bytes);
  return true;
}

// Converts drive::JobInfo that has finished in |error| state
// to ash::DriveOperationStatus.
// If the job is not of type that ash tray is interested, returns false.
bool ConvertToFinishedDriveOperationStatus(const drive::JobInfo& info,
                                           drive::FileError error,
                                           ash::DriveOperationStatus* status) {
  if (!ConvertToDriveOperationStatus(info, status))
    return false;
  status->state = (error == drive::FILE_ERROR_OK)
                      ? ash::DriveOperationStatus::OPERATION_COMPLETED
                      : ash::DriveOperationStatus::OPERATION_FAILED;
  return true;
}

// Converts a list of drive::JobInfo to a list of ash::DriveOperationStatusList.
ash::DriveOperationStatusList ConvertToDriveStatusList(
    const std::vector<drive::JobInfo>& list) {
  ash::DriveOperationStatusList results;
  for (size_t i = 0; i < list.size(); ++i) {
    ash::DriveOperationStatus status;
    if (ConvertToDriveOperationStatus(list[i], &status))
      results.push_back(status);
  }
  return results;
}

void BluetoothPowerFailure() {
  // TODO(sad): Show an error bubble?
}

void BluetoothSetDiscoveringError() {
  LOG(ERROR) << "BluetoothSetDiscovering failed.";
}

void BluetoothDeviceConnectError(
    device::BluetoothDevice::ConnectErrorCode error_code) {
  // TODO(sad): Do something?
}

void ShowSettingsSubPageForActiveUser(const std::string& sub_page) {
  chrome::ShowSettingsSubPageForProfile(
      ProfileManager::GetActiveUserProfile(), sub_page);
}

void ShowNetworkSettingsPage(const std::string& service_path) {
  std::string page = chrome::kInternetOptionsSubPage;
  page += "?servicePath=" + net::EscapeUrlEncodedData(service_path, true);
  content::RecordAction(base::UserMetricsAction("OpenInternetOptionsDialog"));
  ShowSettingsSubPageForActiveUser(page);
}

void OnAcceptMultiprofilesIntro(bool no_show_again) {
  PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
  prefs->SetBoolean(prefs::kMultiProfileNeverShowIntro, no_show_again);
  UserAddingScreen::Get()->Start();
}

}  // namespace

SystemTrayDelegateChromeOS::SystemTrayDelegateChromeOS()
    : weak_ptr_factory_(this),
      user_profile_(NULL),
      clock_type_(base::GetHourClockType()),
      search_key_mapped_to_(input_method::kSearchKey),
      screen_locked_(false),
      have_session_start_time_(false),
      have_session_length_limit_(false),
      should_run_bluetooth_discovery_(false),
      volume_control_delegate_(new VolumeController()),
      device_settings_observer_(CrosSettings::Get()->AddSettingsObserver(
          kSystemUse24HourClock,
          base::Bind(&SystemTrayDelegateChromeOS::UpdateClockType,
                     base::Unretained(this)))) {
  // Register notifications on construction so that events such as
  // PROFILE_CREATED do not get missed if they happen before Initialize().
  registrar_.reset(new content::NotificationRegistrar);
  registrar_->Add(this,
                  chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
                  content::NotificationService::AllSources());
  registrar_->Add(this,
                  chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
                  content::NotificationService::AllSources());
  if (GetUserLoginStatus() == ash::user::LOGGED_IN_NONE) {
    registrar_->Add(this,
                    chrome::NOTIFICATION_SESSION_STARTED,
                    content::NotificationService::AllSources());
  }
  registrar_->Add(this,
                  chrome::NOTIFICATION_PROFILE_CREATED,
                  content::NotificationService::AllSources());
  registrar_->Add(this,
                  chrome::NOTIFICATION_PROFILE_DESTROYED,
                  content::NotificationService::AllSources());

  AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
  CHECK(accessibility_manager);
  accessibility_subscription_ = accessibility_manager->RegisterCallback(
      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityStatusChanged,
                 base::Unretained(this)));
}

void SystemTrayDelegateChromeOS::Initialize() {
  DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);

  input_method::InputMethodManager::Get()->AddObserver(this);
  ash::ime::InputMethodMenuManager::GetInstance()->AddObserver(this);
  UpdateClockType();

  device::BluetoothAdapterFactory::GetAdapter(
      base::Bind(&SystemTrayDelegateChromeOS::InitializeOnAdapterReady,
                 weak_ptr_factory_.GetWeakPtr()));

  ash::Shell::GetInstance()->session_state_delegate()->AddSessionStateObserver(
      this);

  if (LoginState::IsInitialized())
    LoginState::Get()->AddObserver(this);

  if (CrasAudioHandler::IsInitialized())
    CrasAudioHandler::Get()->AddAudioObserver(this);

  BrowserList::AddObserver(this);
}

void SystemTrayDelegateChromeOS::Shutdown() {
  device_settings_observer_.reset();
}

void SystemTrayDelegateChromeOS::InitializeOnAdapterReady(
    scoped_refptr<device::BluetoothAdapter> adapter) {
  bluetooth_adapter_ = adapter;
  CHECK(bluetooth_adapter_.get());
  bluetooth_adapter_->AddObserver(this);

  local_state_registrar_.reset(new PrefChangeRegistrar);
  local_state_registrar_->Init(g_browser_process->local_state());

  UpdateSessionStartTime();
  UpdateSessionLengthLimit();

  local_state_registrar_->Add(
      prefs::kSessionStartTime,
      base::Bind(&SystemTrayDelegateChromeOS::UpdateSessionStartTime,
                 base::Unretained(this)));
  local_state_registrar_->Add(
      prefs::kSessionLengthLimit,
      base::Bind(&SystemTrayDelegateChromeOS::UpdateSessionLengthLimit,
                 base::Unretained(this)));

  policy::BrowserPolicyConnectorChromeOS* policy_connector =
      g_browser_process->platform_part()->browser_policy_connector_chromeos();
  policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
      policy_connector->GetDeviceCloudPolicyManager();
  if (policy_manager)
    policy_manager->core()->store()->AddObserver(this);
  UpdateEnterpriseDomain();
}

SystemTrayDelegateChromeOS::~SystemTrayDelegateChromeOS() {
  // Unregister PrefChangeRegistrars.
  local_state_registrar_.reset();
  user_pref_registrar_.reset();

  // Unregister content notifications before destroying any components.
  registrar_.reset();

  // Unregister a11y status subscription.
  accessibility_subscription_.reset();

  DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
  input_method::InputMethodManager::Get()->RemoveObserver(this);
  ash::ime::InputMethodMenuManager::GetInstance()->RemoveObserver(this);
  bluetooth_adapter_->RemoveObserver(this);
  ash::Shell::GetInstance()
      ->session_state_delegate()
      ->RemoveSessionStateObserver(this);
  LoginState::Get()->RemoveObserver(this);

  if (CrasAudioHandler::IsInitialized())
    CrasAudioHandler::Get()->RemoveAudioObserver(this);

  BrowserList::RemoveObserver(this);
  StopObservingAppWindowRegistry();

  // Stop observing Drive operations.
  UnobserveDriveUpdates();

  policy::BrowserPolicyConnectorChromeOS* connector =
      g_browser_process->platform_part()->browser_policy_connector_chromeos();
  policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
      connector->GetDeviceCloudPolicyManager();
  if (policy_manager)
    policy_manager->core()->store()->RemoveObserver(this);
}

// Overridden from ash::SystemTrayDelegate:
bool SystemTrayDelegateChromeOS::GetTrayVisibilityOnStartup() {
  // In case of OOBE / sign in screen tray will be shown later.
  return LoginState::Get()->IsUserLoggedIn();
}

ash::user::LoginStatus SystemTrayDelegateChromeOS::GetUserLoginStatus() const {
  // All non-logged in ChromeOS specific LOGGED_IN states map to the same
  // Ash specific LOGGED_IN state.
  if (!LoginState::Get()->IsUserLoggedIn())
    return ash::user::LOGGED_IN_NONE;

  if (screen_locked_)
    return ash::user::LOGGED_IN_LOCKED;

  LoginState::LoggedInUserType user_type =
      LoginState::Get()->GetLoggedInUserType();
  switch (user_type) {
    case LoginState::LOGGED_IN_USER_NONE:
      return ash::user::LOGGED_IN_NONE;
    case LoginState::LOGGED_IN_USER_REGULAR:
      return ash::user::LOGGED_IN_USER;
    case LoginState::LOGGED_IN_USER_OWNER:
      return ash::user::LOGGED_IN_OWNER;
    case LoginState::LOGGED_IN_USER_GUEST:
      return ash::user::LOGGED_IN_GUEST;
    case LoginState::LOGGED_IN_USER_RETAIL_MODE:
      return ash::user::LOGGED_IN_RETAIL_MODE;
    case LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT:
      return ash::user::LOGGED_IN_PUBLIC;
    case LoginState::LOGGED_IN_USER_LOCALLY_MANAGED:
      return ash::user::LOGGED_IN_LOCALLY_MANAGED;
    case LoginState::LOGGED_IN_USER_KIOSK_APP:
      return ash::user::LOGGED_IN_KIOSK_APP;
  }
  NOTREACHED();
  return ash::user::LOGGED_IN_NONE;
}

bool SystemTrayDelegateChromeOS::IsOobeCompleted() const {
  if (!base::SysInfo::IsRunningOnChromeOS() &&
      LoginState::Get()->IsUserLoggedIn())
    return true;
  return StartupUtils::IsOobeCompleted();
}

void SystemTrayDelegateChromeOS::ChangeProfilePicture() {
  content::RecordAction(
      base::UserMetricsAction("OpenChangeProfilePictureDialog"));
  ShowSettingsSubPageForActiveUser(chrome::kChangeProfilePictureSubPage);
}

const std::string SystemTrayDelegateChromeOS::GetEnterpriseDomain() const {
  return enterprise_domain_;
}

const base::string16 SystemTrayDelegateChromeOS::GetEnterpriseMessage() const {
  if (GetEnterpriseDomain().empty())
    return base::string16();
  return l10n_util::GetStringFUTF16(IDS_DEVICE_OWNED_BY_NOTICE,
                                    base::UTF8ToUTF16(GetEnterpriseDomain()));
}

const std::string SystemTrayDelegateChromeOS::GetLocallyManagedUserManager()
    const {
  if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
    return std::string();
  return UserManager::Get()->GetSupervisedUserManager()->GetManagerDisplayEmail(
      chromeos::UserManager::Get()->GetActiveUser()->email());
}

const base::string16
SystemTrayDelegateChromeOS::GetLocallyManagedUserManagerName() const {
  if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
    return base::string16();
  return UserManager::Get()->GetSupervisedUserManager()->GetManagerDisplayName(
      chromeos::UserManager::Get()->GetActiveUser()->email());
}

const base::string16 SystemTrayDelegateChromeOS::GetLocallyManagedUserMessage()
    const {
  if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
    return base::string16();
  return l10n_util::GetStringFUTF16(
      IDS_USER_IS_LOCALLY_MANAGED_BY_NOTICE,
      base::UTF8ToUTF16(GetLocallyManagedUserManager()));
}

bool SystemTrayDelegateChromeOS::SystemShouldUpgrade() const {
  return UpgradeDetector::GetInstance()->notify_upgrade();
}

base::HourClockType SystemTrayDelegateChromeOS::GetHourClockType() const {
  return clock_type_;
}

void SystemTrayDelegateChromeOS::ShowSettings() {
  ShowSettingsSubPageForActiveUser("");
}

bool SystemTrayDelegateChromeOS::ShouldShowSettings() {
  return UserManager::Get()->GetCurrentUserFlow()->ShouldShowSettings();
}

void SystemTrayDelegateChromeOS::ShowDateSettings() {
  content::RecordAction(base::UserMetricsAction("ShowDateOptions"));
  std::string sub_page =
      std::string(chrome::kSearchSubPage) + "#" +
      l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
  // Everybody can change the time zone (even though it is a device setting).
  ShowSettingsSubPageForActiveUser(sub_page);
}

void SystemTrayDelegateChromeOS::ShowNetworkSettings(
    const std::string& service_path) {
  if (!LoginState::Get()->IsUserLoggedIn())
    return;
  ShowNetworkSettingsPage(service_path);
}

void SystemTrayDelegateChromeOS::ShowBluetoothSettings() {
  // TODO(sad): Make this work.
}

void SystemTrayDelegateChromeOS::ShowDisplaySettings() {
  content::RecordAction(base::UserMetricsAction("ShowDisplayOptions"));
  ShowSettingsSubPageForActiveUser(kDisplaySettingsSubPageName);
}

void SystemTrayDelegateChromeOS::ShowChromeSlow() {
  chrome::ScopedTabbedBrowserDisplayer displayer(
      ProfileManager::GetPrimaryUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
  chrome::ShowSlow(displayer.browser());
}

bool SystemTrayDelegateChromeOS::ShouldShowDisplayNotification() {
  // Packaged app is not counted as 'last active', so if a browser opening the
  // display settings is in background of a packaged app, it will return true.
  // TODO(mukai): fix this.
  Browser* active_browser =
      chrome::FindLastActiveWithHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH);
  if (!active_browser)
    return true;

  content::WebContents* active_contents =
      active_browser->tab_strip_model()->GetActiveWebContents();
  if (!active_contents)
    return true;

  GURL visible_url = active_contents->GetLastCommittedURL();
  GURL display_settings_url =
      chrome::GetSettingsUrl(kDisplaySettingsSubPageName);
  GURL display_overscan_url =
      chrome::GetSettingsUrl(kDisplayOverscanSettingsSubPageName);
  return (visible_url != display_settings_url &&
          visible_url != display_overscan_url);
}

void SystemTrayDelegateChromeOS::ShowDriveSettings() {
  // TODO(tengs): Open the drive-specific settings page once we put it in.
  // For now just show Google Drive main page.
  chrome::ScopedTabbedBrowserDisplayer displayer(
      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
  chrome::ShowSingletonTabOverwritingNTP(
      displayer.browser(),
      chrome::GetSingletonTabNavigateParams(displayer.browser(),
                                            GURL(kDriveSettingsPageURL)));
}

void SystemTrayDelegateChromeOS::ShowIMESettings() {
  content::RecordAction(base::UserMetricsAction("OpenLanguageOptionsDialog"));
  ShowSettingsSubPageForActiveUser(chrome::kLanguageOptionsSubPage);
}

void SystemTrayDelegateChromeOS::ShowHelp() {
  chrome::ShowHelpForProfile(ProfileManager::GetActiveUserProfile(),
                             chrome::HOST_DESKTOP_TYPE_ASH,
                             chrome::HELP_SOURCE_MENU);
}

void SystemTrayDelegateChromeOS::ShowAccessibilityHelp() {
  chrome::ScopedTabbedBrowserDisplayer displayer(
      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
  accessibility::ShowAccessibilityHelp(displayer.browser());
}

void SystemTrayDelegateChromeOS::ShowAccessibilitySettings() {
  content::RecordAction(base::UserMetricsAction("ShowAccessibilitySettings"));
  std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
                         l10n_util::GetStringUTF8(
                             IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY);
  ShowSettingsSubPageForActiveUser(sub_page);
}

void SystemTrayDelegateChromeOS::ShowPublicAccountInfo() {
  chrome::ScopedTabbedBrowserDisplayer displayer(
      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
  chrome::ShowPolicy(displayer.browser());
}

void SystemTrayDelegateChromeOS::ShowLocallyManagedUserInfo() {
  // TODO(antrim): find out what should we show in this case.
  // http://crbug.com/229762
}

void SystemTrayDelegateChromeOS::ShowEnterpriseInfo() {
  ash::user::LoginStatus status = GetUserLoginStatus();
  if (status == ash::user::LOGGED_IN_NONE ||
      status == ash::user::LOGGED_IN_LOCKED) {
    scoped_refptr<chromeos::HelpAppLauncher> help_app(
        new chromeos::HelpAppLauncher(GetNativeWindow()));
    help_app->ShowHelpTopic(chromeos::HelpAppLauncher::HELP_ENTERPRISE);
  } else {
    GURL url(google_util::StringAppendGoogleLocaleParam(
        chrome::kLearnMoreEnterpriseURL));
    chrome::ScopedTabbedBrowserDisplayer displayer(
        ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
    chrome::ShowSingletonTab(displayer.browser(), url);
  }
}

void SystemTrayDelegateChromeOS::ShowUserLogin() {
  ash::Shell* shell = ash::Shell::GetInstance();
  if (!shell->delegate()->IsMultiProfilesEnabled())
    return;

  // Only regular users could add other users to current session.
  if (UserManager::Get()->GetActiveUser()->GetType() !=
      User::USER_TYPE_REGULAR) {
    return;
  }

  if (static_cast<int>(UserManager::Get()->GetLoggedInUsers().size()) >=
      shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers())
    return;

  // Launch sign in screen to add another user to current session.
  if (UserManager::Get()->GetUsersAdmittedForMultiProfile().size()) {
    // Don't show dialog if any logged in user in multi-profiles session
    // dismissed it.
    bool show_intro = true;
    const UserList logged_in_users = UserManager::Get()->GetLoggedInUsers();
    for (UserList::const_iterator it = logged_in_users.begin();
         it != logged_in_users.end();
         ++it) {
      show_intro &= !multi_user_util::GetProfileFromUserID(
                         multi_user_util::GetUserIDFromEmail((*it)->email()))
                         ->GetPrefs()
                         ->GetBoolean(prefs::kMultiProfileNeverShowIntro);
      if (!show_intro)
        break;
    }
    if (show_intro) {
      base::Callback<void(bool)> on_accept =
          base::Bind(&OnAcceptMultiprofilesIntro);
      ShowMultiprofilesIntroDialog(on_accept);
    } else {
      UserAddingScreen::Get()->Start();
    }
  }
}

bool SystemTrayDelegateChromeOS::ShowSpringChargerReplacementDialog() {
  if (!ChargerReplacementDialog::ShouldShowDialog())
    return false;

  ChargerReplacementDialog* dialog =
      new ChargerReplacementDialog(GetNativeWindow());
  dialog->Show();
  return true;
}

bool SystemTrayDelegateChromeOS::IsSpringChargerReplacementDialogVisible() {
  return ChargerReplacementDialog::IsDialogVisible();
}

bool SystemTrayDelegateChromeOS::HasUserConfirmedSafeSpringCharger() {
  return ChargerReplacementHandler::GetChargerStatusPref() ==
         ChargerReplacementHandler::CONFIRM_SAFE_CHARGER;
}

void SystemTrayDelegateChromeOS::ShutDown() {
  ash::Shell::GetInstance()->lock_state_controller()->RequestShutdown();
}

void SystemTrayDelegateChromeOS::SignOut() {
  chrome::AttemptUserExit();
}

void SystemTrayDelegateChromeOS::RequestLockScreen() {
  // TODO(antrim) : additional logging for crbug/173178
  LOG(WARNING) << "Requesting screen lock from AshSystemTrayDelegate";
  DBusThreadManager::Get()->GetSessionManagerClient()->RequestLockScreen();
}

void SystemTrayDelegateChromeOS::RequestRestartForUpdate() {
  // We expect that UpdateEngine is in "Reboot for update" state now.
  chrome::NotifyAndTerminate(true /* fast path */);
}

void SystemTrayDelegateChromeOS::GetAvailableBluetoothDevices(
    ash::BluetoothDeviceList* list) {
  device::BluetoothAdapter::DeviceList devices =
      bluetooth_adapter_->GetDevices();
  for (size_t i = 0; i < devices.size(); ++i) {
    device::BluetoothDevice* device = devices[i];
    ash::BluetoothDeviceInfo info;
    info.address = device->GetAddress();
    info.display_name = device->GetName();
    info.connected = device->IsConnected();
    info.connecting = device->IsConnecting();
    info.paired = device->IsPaired();
    list->push_back(info);
  }
}

void SystemTrayDelegateChromeOS::BluetoothStartDiscovering() {
  if (GetBluetoothDiscovering()) {
    LOG(WARNING) << "Already have active Bluetooth device discovery session.";
    return;
  }
  VLOG(1) << "Requesting new Bluetooth device discovery session.";
  should_run_bluetooth_discovery_ = true;
  bluetooth_adapter_->StartDiscoverySession(
      base::Bind(&SystemTrayDelegateChromeOS::OnStartBluetoothDiscoverySession,
                 weak_ptr_factory_.GetWeakPtr()),
      base::Bind(&BluetoothSetDiscoveringError));
}

void SystemTrayDelegateChromeOS::BluetoothStopDiscovering() {
  should_run_bluetooth_discovery_ = false;
  if (!GetBluetoothDiscovering()) {
    LOG(WARNING) << "No active Bluetooth device discovery session.";
    return;
  }
  VLOG(1) << "Stopping Bluetooth device discovery session.";
  bluetooth_discovery_session_->Stop(
      base::Bind(&base::DoNothing), base::Bind(&BluetoothSetDiscoveringError));
}

void SystemTrayDelegateChromeOS::ConnectToBluetoothDevice(
    const std::string& address) {
  device::BluetoothDevice* device = bluetooth_adapter_->GetDevice(address);
  if (!device || device->IsConnecting() ||
      (device->IsConnected() && device->IsPaired())) {
    return;
  }
  if (device->IsPaired() && !device->IsConnectable())
    return;
  if (device->IsPaired() || !device->IsPairable()) {
    ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
        ash::UMA_STATUS_AREA_BLUETOOTH_CONNECT_KNOWN_DEVICE);
    device->Connect(NULL,
                    base::Bind(&base::DoNothing),
                    base::Bind(&BluetoothDeviceConnectError));
  } else {  // Show paring dialog for the unpaired device.
    ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
        ash::UMA_STATUS_AREA_BLUETOOTH_CONNECT_UNKNOWN_DEVICE);
    BluetoothPairingDialog* dialog =
        new BluetoothPairingDialog(GetNativeWindow(), device);
    // The dialog deletes itself on close.
    dialog->Show();
  }
}

bool SystemTrayDelegateChromeOS::IsBluetoothDiscovering() {
  return bluetooth_adapter_->IsDiscovering();
}

void SystemTrayDelegateChromeOS::GetCurrentIME(ash::IMEInfo* info) {
  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::Get();
  input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
  input_method::InputMethodDescriptor ime = manager->GetCurrentInputMethod();
  ExtractIMEInfo(ime, *util, info);
  info->selected = true;
}

void SystemTrayDelegateChromeOS::GetAvailableIMEList(ash::IMEInfoList* list) {
  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::Get();
  input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
  scoped_ptr<input_method::InputMethodDescriptors> ime_descriptors(
      manager->GetActiveInputMethods());
  std::string current = manager->GetCurrentInputMethod().id();
  for (size_t i = 0; i < ime_descriptors->size(); i++) {
    input_method::InputMethodDescriptor& ime = ime_descriptors->at(i);
    ash::IMEInfo info;
    ExtractIMEInfo(ime, *util, &info);
    info.selected = ime.id() == current;
    list->push_back(info);
  }
}

void SystemTrayDelegateChromeOS::GetCurrentIMEProperties(
    ash::IMEPropertyInfoList* list) {
  ash::ime::InputMethodMenuItemList menu_list =
      ash::ime::InputMethodMenuManager::GetInstance()->
      GetCurrentInputMethodMenuItemList();
  for (size_t i = 0; i < menu_list.size(); ++i) {
    ash::IMEPropertyInfo property;
    property.key = menu_list[i].key;
    property.name = base::UTF8ToUTF16(menu_list[i].label);
    property.selected = menu_list[i].is_selection_item_checked;
    list->push_back(property);
  }
}

void SystemTrayDelegateChromeOS::SwitchIME(const std::string& ime_id) {
  input_method::InputMethodManager::Get()->ChangeInputMethod(ime_id);
}

void SystemTrayDelegateChromeOS::ActivateIMEProperty(const std::string& key) {
  input_method::InputMethodManager::Get()->ActivateInputMethodMenuItem(key);
}

void SystemTrayDelegateChromeOS::CancelDriveOperation(int32 operation_id) {
  DriveIntegrationService* integration_service = FindDriveIntegrationService();
  if (!integration_service)
    return;

  integration_service->job_list()->CancelJob(operation_id);
}

void SystemTrayDelegateChromeOS::GetDriveOperationStatusList(
    ash::DriveOperationStatusList* list) {
  DriveIntegrationService* integration_service = FindDriveIntegrationService();
  if (!integration_service)
    return;

  *list = ConvertToDriveStatusList(
      integration_service->job_list()->GetJobInfoList());
}

void SystemTrayDelegateChromeOS::ShowNetworkConfigure(
    const std::string& network_id,
    gfx::NativeWindow parent_window) {
  NetworkConfigView::Show(network_id, parent_window);
}

bool SystemTrayDelegateChromeOS::EnrollNetwork(
    const std::string& network_id,
    gfx::NativeWindow parent_window) {
  return enrollment::CreateDialog(network_id, parent_window);
}

void SystemTrayDelegateChromeOS::ManageBluetoothDevices() {
  content::RecordAction(base::UserMetricsAction("ShowBluetoothSettingsPage"));
  std::string sub_page =
      std::string(chrome::kSearchSubPage) + "#" +
      l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH);
  ShowSettingsSubPageForActiveUser(sub_page);
}

void SystemTrayDelegateChromeOS::ToggleBluetooth() {
  bluetooth_adapter_->SetPowered(!bluetooth_adapter_->IsPowered(),
                                 base::Bind(&base::DoNothing),
                                 base::Bind(&BluetoothPowerFailure));
}

void SystemTrayDelegateChromeOS::ShowMobileSimDialog() {
  SimDialogDelegate::ShowDialog(GetNativeWindow(),
                                SimDialogDelegate::SIM_DIALOG_UNLOCK);
}

void SystemTrayDelegateChromeOS::ShowMobileSetupDialog(
    const std::string& service_path) {
  MobileSetupDialog::Show(service_path);
}

void SystemTrayDelegateChromeOS::ShowOtherNetworkDialog(
    const std::string& type) {
  if (type == shill::kTypeCellular) {
    ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow());
    return;
  }
  NetworkConfigView::ShowForType(type, GetNativeWindow());
}

bool SystemTrayDelegateChromeOS::GetBluetoothAvailable() {
  return bluetooth_adapter_->IsPresent();
}

bool SystemTrayDelegateChromeOS::GetBluetoothEnabled() {
  return bluetooth_adapter_->IsPowered();
}

bool SystemTrayDelegateChromeOS::GetBluetoothDiscovering() {
  return (bluetooth_discovery_session_.get() &&
      bluetooth_discovery_session_->IsActive());
}

void SystemTrayDelegateChromeOS::ChangeProxySettings() {
  CHECK(GetUserLoginStatus() == ash::user::LOGGED_IN_NONE);
  LoginDisplayHostImpl::default_host()->OpenProxySettings();
}

ash::VolumeControlDelegate*
SystemTrayDelegateChromeOS::GetVolumeControlDelegate() const {
  return volume_control_delegate_.get();
}

void SystemTrayDelegateChromeOS::SetVolumeControlDelegate(
    scoped_ptr<ash::VolumeControlDelegate> delegate) {
  volume_control_delegate_.swap(delegate);
}

bool SystemTrayDelegateChromeOS::GetSessionStartTime(
    base::TimeTicks* session_start_time) {
  *session_start_time = session_start_time_;
  return have_session_start_time_;
}

bool SystemTrayDelegateChromeOS::GetSessionLengthLimit(
    base::TimeDelta* session_length_limit) {
  *session_length_limit = session_length_limit_;
  return have_session_length_limit_;
}

int SystemTrayDelegateChromeOS::GetSystemTrayMenuWidth() {
  return l10n_util::GetLocalizedContentsWidthInPixels(
      IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
}

void SystemTrayDelegateChromeOS::ActiveUserWasChanged() {
  GetSystemTrayNotifier()->NotifyUserUpdate();
}

bool SystemTrayDelegateChromeOS::IsNetworkBehindCaptivePortal(
    const std::string& service_path) const {
  NetworkPortalDetector::CaptivePortalState state =
      NetworkPortalDetector::Get()->GetCaptivePortalState(service_path);
  return state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
}

bool SystemTrayDelegateChromeOS::IsSearchKeyMappedToCapsLock() {
  return search_key_mapped_to_ == input_method::kCapsLockKey;
}

ash::SystemTray* SystemTrayDelegateChromeOS::GetPrimarySystemTray() {
  return ash::Shell::GetInstance()->GetPrimarySystemTray();
}

ash::SystemTrayNotifier* SystemTrayDelegateChromeOS::GetSystemTrayNotifier() {
  return ash::Shell::GetInstance()->system_tray_notifier();
}

void SystemTrayDelegateChromeOS::SetProfile(Profile* profile) {
  // Stop observing the Drive integration status and the AppWindowRegistry of
  // the current |user_profile_|.
  UnobserveDriveUpdates();
  StopObservingAppWindowRegistry();

  user_profile_ = profile;

  // Start observing the Drive integration status and the AppWindowRegistry of
  // the newly set |user_profile_|.
  ObserveDriveUpdates();
  apps::AppWindowRegistry::Get(user_profile_)->AddObserver(this);

  PrefService* prefs = profile->GetPrefs();
  user_pref_registrar_.reset(new PrefChangeRegistrar);
  user_pref_registrar_->Init(prefs);
  user_pref_registrar_->Add(
      prefs::kUse24HourClock,
      base::Bind(&SystemTrayDelegateChromeOS::UpdateClockType,
                 base::Unretained(this)));
  user_pref_registrar_->Add(
      prefs::kLanguageRemapSearchKeyTo,
      base::Bind(&SystemTrayDelegateChromeOS::OnLanguageRemapSearchKeyToChanged,
                 base::Unretained(this)));
  user_pref_registrar_->Add(
      prefs::kShowLogoutButtonInTray,
      base::Bind(&SystemTrayDelegateChromeOS::UpdateShowLogoutButtonInTray,
                 base::Unretained(this)));
  user_pref_registrar_->Add(
      prefs::kLogoutDialogDurationMs,
      base::Bind(&SystemTrayDelegateChromeOS::UpdateLogoutDialogDuration,
                 base::Unretained(this)));
  user_pref_registrar_->Add(
      prefs::kLargeCursorEnabled,
      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
                 base::Unretained(this),
                 ash::A11Y_NOTIFICATION_NONE));
  user_pref_registrar_->Add(
      prefs::kAutoclickEnabled,
      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
                 base::Unretained(this),
                 ash::A11Y_NOTIFICATION_NONE));
  user_pref_registrar_->Add(
      prefs::kShouldAlwaysShowAccessibilityMenu,
      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
                 base::Unretained(this),
                 ash::A11Y_NOTIFICATION_NONE));
  user_pref_registrar_->Add(
      prefs::kPerformanceTracingEnabled,
      base::Bind(&SystemTrayDelegateChromeOS::UpdatePerformanceTracing,
                 base::Unretained(this)));

  UpdateClockType();
  UpdateShowLogoutButtonInTray();
  UpdateLogoutDialogDuration();
  UpdatePerformanceTracing();
  search_key_mapped_to_ =
      profile->GetPrefs()->GetInteger(prefs::kLanguageRemapSearchKeyTo);
}

bool SystemTrayDelegateChromeOS::UnsetProfile(Profile* profile) {
  if (profile != user_profile_)
    return false;
  user_pref_registrar_.reset();
  user_profile_ = NULL;
  return true;
}

void SystemTrayDelegateChromeOS::ObserveDriveUpdates() {
  DriveIntegrationService* integration_service = FindDriveIntegrationService();
  if (integration_service)
    integration_service->job_list()->AddObserver(this);
}

void SystemTrayDelegateChromeOS::UnobserveDriveUpdates() {
  DriveIntegrationService* integration_service = FindDriveIntegrationService();
  if (integration_service)
    integration_service->job_list()->RemoveObserver(this);
}

bool SystemTrayDelegateChromeOS::GetShouldUse24HourClockForTesting() const {
  return ShouldUse24HourClock();
}

bool SystemTrayDelegateChromeOS::ShouldUse24HourClock() const {
  // On login screen and in guest mode owner default is used for
  // kUse24HourClock preference.
  const ash::user::LoginStatus status = GetUserLoginStatus();
  const CrosSettings* const cros_settings = CrosSettings::Get();
  bool system_use_24_hour_clock = true;
  const bool system_value_found = cros_settings->GetBoolean(
      kSystemUse24HourClock, &system_use_24_hour_clock);

  if ((status == ash::user::LOGGED_IN_NONE) || !user_pref_registrar_)
    return (system_value_found
                ? system_use_24_hour_clock
                : (base::GetHourClockType() == base::k24HourClock));

  const PrefService::Preference* user_pref =
      user_pref_registrar_->prefs()->FindPreference(prefs::kUse24HourClock);
  if (status == ash::user::LOGGED_IN_GUEST && user_pref->IsDefaultValue())
    return (system_value_found
                ? system_use_24_hour_clock
                : (base::GetHourClockType() == base::k24HourClock));

  bool use_24_hour_clock = true;
  user_pref->GetValue()->GetAsBoolean(&use_24_hour_clock);
  return use_24_hour_clock;
}

void SystemTrayDelegateChromeOS::UpdateClockType() {
  const bool use_24_hour_clock = ShouldUse24HourClock();
  clock_type_ = use_24_hour_clock ? base::k24HourClock : base::k12HourClock;
  GetSystemTrayNotifier()->NotifyDateFormatChanged();
  // This also works for enterprise-managed devices because they never have
  // local owner.
  if (chromeos::UserManager::Get()->IsCurrentUserOwner())
    CrosSettings::Get()->SetBoolean(kSystemUse24HourClock, use_24_hour_clock);
}

void SystemTrayDelegateChromeOS::UpdateShowLogoutButtonInTray() {
  GetSystemTrayNotifier()->NotifyShowLoginButtonChanged(
      user_pref_registrar_->prefs()->GetBoolean(
          prefs::kShowLogoutButtonInTray));
}

void SystemTrayDelegateChromeOS::UpdateLogoutDialogDuration() {
  const int duration_ms =
      user_pref_registrar_->prefs()->GetInteger(prefs::kLogoutDialogDurationMs);
  GetSystemTrayNotifier()->NotifyLogoutDialogDurationChanged(
      base::TimeDelta::FromMilliseconds(duration_ms));
}

void SystemTrayDelegateChromeOS::UpdateSessionStartTime() {
  const PrefService* local_state = local_state_registrar_->prefs();
  if (local_state->HasPrefPath(prefs::kSessionStartTime)) {
    have_session_start_time_ = true;
    session_start_time_ = base::TimeTicks::FromInternalValue(
        local_state->GetInt64(prefs::kSessionStartTime));
  } else {
    have_session_start_time_ = false;
    session_start_time_ = base::TimeTicks();
  }
  GetSystemTrayNotifier()->NotifySessionStartTimeChanged();
}

void SystemTrayDelegateChromeOS::UpdateSessionLengthLimit() {
  const PrefService* local_state = local_state_registrar_->prefs();
  if (local_state->HasPrefPath(prefs::kSessionLengthLimit)) {
    have_session_length_limit_ = true;
    session_length_limit_ = base::TimeDelta::FromMilliseconds(
        std::min(std::max(local_state->GetInteger(prefs::kSessionLengthLimit),
                          kSessionLengthLimitMinMs),
                 kSessionLengthLimitMaxMs));
  } else {
    have_session_length_limit_ = false;
    session_length_limit_ = base::TimeDelta();
  }
  GetSystemTrayNotifier()->NotifySessionLengthLimitChanged();
}

void SystemTrayDelegateChromeOS::StopObservingAppWindowRegistry() {
  if (!user_profile_)
    return;

  apps::AppWindowRegistry* registry =
      apps::AppWindowRegistry::Factory::GetForBrowserContext(user_profile_,
                                                             false);
  if (registry)
    registry->RemoveObserver(this);
}

void SystemTrayDelegateChromeOS::NotifyIfLastWindowClosed() {
  if (!user_profile_)
    return;

  BrowserList* browser_list =
      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
  for (BrowserList::const_iterator it = browser_list->begin();
       it != browser_list->end();
       ++it) {
    if ((*it)->profile()->IsSameProfile(user_profile_)) {
      // The current user has at least one open browser window.
      return;
    }
  }

  if (!apps::AppWindowRegistry::Get(user_profile_)->app_windows().empty()) {
    // The current user has at least one open app window.
    return;
  }

  GetSystemTrayNotifier()->NotifyLastWindowClosed();
}

// LoginState::Observer overrides.
void SystemTrayDelegateChromeOS::LoggedInStateChanged() {
  // It apparently sometimes takes a while after login before the current user
  // is recognized as the owner. Make sure that the system-wide clock setting
  // is updated when the recognition eventually happens
  // (http://crbug.com/278601).
  //
  // Note that it isn't safe to blindly call UpdateClockType() from this
  // method, as LoggedInStateChanged() is also called before the logged-in
  // user's profile has actually been loaded (http://crbug.com/317745). The
  // system tray's time format is updated at login via SetProfile().
  if (chromeos::UserManager::Get()->IsCurrentUserOwner()) {
    CrosSettings::Get()->SetBoolean(kSystemUse24HourClock,
                                    ShouldUse24HourClock());
  }
}

// Overridden from SessionManagerClient::Observer.
void SystemTrayDelegateChromeOS::ScreenIsLocked() {
  screen_locked_ = true;
  ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(GetUserLoginStatus());
}

void SystemTrayDelegateChromeOS::ScreenIsUnlocked() {
  screen_locked_ = false;
  ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(GetUserLoginStatus());
}

gfx::NativeWindow SystemTrayDelegateChromeOS::GetNativeWindow() const {
  bool session_started = ash::Shell::GetInstance()
                             ->session_state_delegate()
                             ->IsActiveUserSessionStarted();
  return GetNativeWindowByStatus(GetUserLoginStatus(), session_started);
}

// content::NotificationObserver implementation.
void SystemTrayDelegateChromeOS::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: {
      UpgradeDetector* detector =
          content::Source<UpgradeDetector>(source).ptr();
      ash::UpdateObserver::UpdateSeverity severity =
          ash::UpdateObserver::UPDATE_NORMAL;
      switch (detector->upgrade_notification_stage()) {
        case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
          severity = ash::UpdateObserver::UPDATE_SEVERE_RED;
          break;

        case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
          severity = ash::UpdateObserver::UPDATE_HIGH_ORANGE;
          break;

        case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
          severity = ash::UpdateObserver::UPDATE_LOW_GREEN;
          break;

        case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
        default:
          severity = ash::UpdateObserver::UPDATE_NORMAL;
          break;
      }
      GetSystemTrayNotifier()->NotifyUpdateRecommended(severity);
      break;
    }
    case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
      // This notification is also sent on login screen when user avatar
      // is loaded from file.
      if (GetUserLoginStatus() != ash::user::LOGGED_IN_NONE) {
        GetSystemTrayNotifier()->NotifyUserUpdate();
      }
      break;
    }
    case chrome::NOTIFICATION_PROFILE_CREATED: {
      SetProfile(content::Source<Profile>(source).ptr());
      registrar_->Remove(this,
                         chrome::NOTIFICATION_PROFILE_CREATED,
                         content::NotificationService::AllSources());
      break;
    }
    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
      if (UnsetProfile(content::Source<Profile>(source).ptr())) {
        registrar_->Remove(this,
                           chrome::NOTIFICATION_PROFILE_DESTROYED,
                           content::NotificationService::AllSources());
      }
      break;
    }
    case chrome::NOTIFICATION_SESSION_STARTED: {
      ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(
          GetUserLoginStatus());
      SetProfile(ProfileManager::GetActiveUserProfile());
      break;
    }
    default:
      NOTREACHED();
  }
}

void SystemTrayDelegateChromeOS::OnLanguageRemapSearchKeyToChanged() {
  search_key_mapped_to_ = user_pref_registrar_->prefs()->GetInteger(
      prefs::kLanguageRemapSearchKeyTo);
}

void SystemTrayDelegateChromeOS::OnAccessibilityModeChanged(
    ash::AccessibilityNotificationVisibility notify) {
  GetSystemTrayNotifier()->NotifyAccessibilityModeChanged(notify);
}

void SystemTrayDelegateChromeOS::UpdatePerformanceTracing() {
  if (!user_pref_registrar_)
    return;
  bool value = user_pref_registrar_->prefs()->GetBoolean(
      prefs::kPerformanceTracingEnabled);
  GetSystemTrayNotifier()->NotifyTracingModeChanged(value);
}

// Overridden from InputMethodManager::Observer.
void SystemTrayDelegateChromeOS::InputMethodChanged(
    input_method::InputMethodManager* manager,
    bool show_message) {
  GetSystemTrayNotifier()->NotifyRefreshIME();
}

// Overridden from InputMethodMenuManager::Observer.
void SystemTrayDelegateChromeOS::InputMethodMenuItemChanged(
    ash::ime::InputMethodMenuManager* manager) {
  GetSystemTrayNotifier()->NotifyRefreshIME();
}

// Overridden from CrasAudioHandler::AudioObserver.
void SystemTrayDelegateChromeOS::OnOutputVolumeChanged() {
  GetSystemTrayNotifier()->NotifyAudioOutputVolumeChanged();
}

void SystemTrayDelegateChromeOS::OnOutputMuteChanged() {
  GetSystemTrayNotifier()->NotifyAudioOutputMuteChanged();
}

void SystemTrayDelegateChromeOS::OnInputGainChanged() {
}

void SystemTrayDelegateChromeOS::OnInputMuteChanged() {
}

void SystemTrayDelegateChromeOS::OnAudioNodesChanged() {
  GetSystemTrayNotifier()->NotifyAudioNodesChanged();
}

void SystemTrayDelegateChromeOS::OnActiveOutputNodeChanged() {
  GetSystemTrayNotifier()->NotifyAudioActiveOutputNodeChanged();
}

void SystemTrayDelegateChromeOS::OnActiveInputNodeChanged() {
  GetSystemTrayNotifier()->NotifyAudioActiveInputNodeChanged();
}

// drive::JobListObserver overrides.
void SystemTrayDelegateChromeOS::OnJobAdded(const drive::JobInfo& job_info) {
  OnJobUpdated(job_info);
}

void SystemTrayDelegateChromeOS::OnJobDone(const drive::JobInfo& job_info,
                                           drive::FileError error) {
  ash::DriveOperationStatus status;
  if (ConvertToFinishedDriveOperationStatus(job_info, error, &status))
    GetSystemTrayNotifier()->NotifyDriveJobUpdated(status);
}

void SystemTrayDelegateChromeOS::OnJobUpdated(const drive::JobInfo& job_info) {
  ash::DriveOperationStatus status;
  if (ConvertToDriveOperationStatus(job_info, &status))
    GetSystemTrayNotifier()->NotifyDriveJobUpdated(status);
}

DriveIntegrationService*
SystemTrayDelegateChromeOS::FindDriveIntegrationService() {
  return user_profile_
             ? DriveIntegrationServiceFactory::FindForProfile(user_profile_)
             : NULL;
}

// Overridden from BluetoothAdapter::Observer.
void SystemTrayDelegateChromeOS::AdapterPresentChanged(
    device::BluetoothAdapter* adapter,
    bool present) {
  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}

void SystemTrayDelegateChromeOS::AdapterPoweredChanged(
    device::BluetoothAdapter* adapter,
    bool powered) {
  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}

void SystemTrayDelegateChromeOS::AdapterDiscoveringChanged(
    device::BluetoothAdapter* adapter,
    bool discovering) {
  GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
}

void SystemTrayDelegateChromeOS::DeviceAdded(device::BluetoothAdapter* adapter,
                                             device::BluetoothDevice* device) {
  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}

void SystemTrayDelegateChromeOS::DeviceChanged(
    device::BluetoothAdapter* adapter,
    device::BluetoothDevice* device) {
  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}

void SystemTrayDelegateChromeOS::DeviceRemoved(
    device::BluetoothAdapter* adapter,
    device::BluetoothDevice* device) {
  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}

void SystemTrayDelegateChromeOS::OnStartBluetoothDiscoverySession(
    scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
  // If the discovery session was returned after a request to stop discovery
  // (e.g. the user dismissed the Bluetooth detailed view before the call
  // returned), don't claim the discovery session and let it clean up.
  if (!should_run_bluetooth_discovery_)
    return;
  VLOG(1) << "Claiming new Bluetooth device discovery session.";
  bluetooth_discovery_session_ = discovery_session.Pass();
  GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
}

void SystemTrayDelegateChromeOS::UpdateEnterpriseDomain() {
  policy::BrowserPolicyConnectorChromeOS* connector =
      g_browser_process->platform_part()->browser_policy_connector_chromeos();
  std::string enterprise_domain = connector->GetEnterpriseDomain();
  if (enterprise_domain_ != enterprise_domain) {
    enterprise_domain_ = enterprise_domain;
    GetSystemTrayNotifier()->NotifyEnterpriseDomainChanged();
  }
}

// Overridden from CloudPolicyStore::Observer
void SystemTrayDelegateChromeOS::OnStoreLoaded(
    policy::CloudPolicyStore* store) {
  UpdateEnterpriseDomain();
}

void SystemTrayDelegateChromeOS::OnStoreError(policy::CloudPolicyStore* store) {
  UpdateEnterpriseDomain();
}

// Overridden from ash::SessionStateObserver
void SystemTrayDelegateChromeOS::UserAddedToSession(
    const std::string& user_id) {
  GetSystemTrayNotifier()->NotifyUserAddedToSession();
}

// Overridden from chrome::BrowserListObserver.
void SystemTrayDelegateChromeOS::OnBrowserRemoved(Browser* browser) {
  NotifyIfLastWindowClosed();
}

// Overridden from apps::AppWindowRegistry::Observer.
void SystemTrayDelegateChromeOS::OnAppWindowAdded(apps::AppWindow* app_window) {
}

void SystemTrayDelegateChromeOS::OnAppWindowIconChanged(
    apps::AppWindow* app_window) {}

void SystemTrayDelegateChromeOS::OnAppWindowRemoved(
    apps::AppWindow* app_window) {
  NotifyIfLastWindowClosed();
}

void SystemTrayDelegateChromeOS::OnAccessibilityStatusChanged(
    const AccessibilityStatusEventDetails& details) {
  if (details.notification_type == ACCESSIBILITY_MANAGER_SHUTDOWN)
    accessibility_subscription_.reset();
  else
    OnAccessibilityModeChanged(details.notify);
}

ash::SystemTrayDelegate* CreateSystemTrayDelegate() {
  return new SystemTrayDelegateChromeOS();
}

}  // namespace chromeos

/* [<][>][^][v][top][bottom][index][help] */