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