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