system_tray_delegate_chromeos.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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/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_display_host.h"
59#include "chrome/browser/chromeos/login/login_display_host_impl.h"
60#include "chrome/browser/chromeos/login/login_wizard.h"
61#include "chrome/browser/chromeos/login/supervised_user_manager.h"
62#include "chrome/browser/chromeos/login/user.h"
63#include "chrome/browser/chromeos/login/user_adding_screen.h"
64#include "chrome/browser/chromeos/login/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/settings/cros_settings.h"
71#include "chrome/browser/chromeos/sim_dialog_delegate.h"
72#include "chrome/browser/chromeos/ui/choose_mobile_network_dialog.h"
73#include "chrome/browser/drive/drive_service_interface.h"
74#include "chrome/browser/feedback/tracing_manager.h"
75#include "chrome/browser/google/google_util.h"
76#include "chrome/browser/lifetime/application_lifetime.h"
77#include "chrome/browser/profiles/profile_manager.h"
78#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
79#include "chrome/browser/ui/ash/stub_user_accounts_delegate.h"
80#include "chrome/browser/ui/ash/volume_controller_chromeos.h"
81#include "chrome/browser/ui/browser.h"
82#include "chrome/browser/ui/browser_finder.h"
83#include "chrome/browser/ui/browser_list.h"
84#include "chrome/browser/ui/chrome_pages.h"
85#include "chrome/browser/ui/host_desktop.h"
86#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
87#include "chrome/browser/ui/singleton_tabs.h"
88#include "chrome/browser/ui/tabs/tab_strip_model.h"
89#include "chrome/browser/ui/webui/chromeos/charger_replacement_handler.h"
90#include "chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h"
91#include "chrome/browser/upgrade_detector.h"
92#include "chrome/common/chrome_switches.h"
93#include "chrome/common/pref_names.h"
94#include "chrome/common/url_constants.h"
95#include "chromeos/dbus/dbus_thread_manager.h"
96#include "chromeos/dbus/session_manager_client.h"
97#include "chromeos/ime/extension_ime_util.h"
98#include "chromeos/ime/ime_keyboard.h"
99#include "chromeos/ime/input_method_manager.h"
100#include "chromeos/login/login_state.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
117using drive::DriveIntegrationService;
118using drive::DriveIntegrationServiceFactory;
119
120namespace chromeos {
121
122namespace {
123
124// The minimum session length limit that can be set.
125const int kSessionLengthLimitMinMs = 30 * 1000;  // 30 seconds.
126
127// The maximum session length limit that can be set.
128const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000;  // 24 hours.
129
130const char kDisplaySettingsSubPageName[] = "display";
131const char kDisplayOverscanSettingsSubPageName[] = "displayOverscan";
132
133// The URL for the Google Drive settings page.
134const char kDriveSettingsPageURL[] = "https://drive.google.com";
135
136void 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
146gfx::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.
159bool 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.
186bool 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.
198ash::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
209void BluetoothPowerFailure() {
210  // TODO(sad): Show an error bubble?
211}
212
213void BluetoothSetDiscoveringError() {
214  LOG(ERROR) << "BluetoothSetDiscovering failed.";
215}
216
217void BluetoothDeviceConnectError(
218    device::BluetoothDevice::ConnectErrorCode error_code) {
219  // TODO(sad): Do something?
220}
221
222void ShowSettingsSubPageForActiveUser(const std::string& sub_page) {
223  chrome::ShowSettingsSubPageForProfile(
224      ProfileManager::GetActiveUserProfile(), sub_page);
225}
226
227void 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
234void 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
242SystemTrayDelegateChromeOS::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
284void 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
307void SystemTrayDelegateChromeOS::Shutdown() {
308  device_settings_observer_.reset();
309}
310
311void 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
341SystemTrayDelegateChromeOS::~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:
379bool SystemTrayDelegateChromeOS::GetTrayVisibilityOnStartup() {
380  // In case of OOBE / sign in screen tray will be shown later.
381  return LoginState::Get()->IsUserLoggedIn();
382}
383
384ash::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
417void SystemTrayDelegateChromeOS::ChangeProfilePicture() {
418  content::RecordAction(
419      base::UserMetricsAction("OpenChangeProfilePictureDialog"));
420  ShowSettingsSubPageForActiveUser(chrome::kChangeProfilePictureSubPage);
421}
422
423const std::string SystemTrayDelegateChromeOS::GetEnterpriseDomain() const {
424  return enterprise_domain_;
425}
426
427const 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
434const 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
442const base::string16
443SystemTrayDelegateChromeOS::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
450const 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
459bool SystemTrayDelegateChromeOS::SystemShouldUpgrade() const {
460  return UpgradeDetector::GetInstance()->notify_upgrade();
461}
462
463base::HourClockType SystemTrayDelegateChromeOS::GetHourClockType() const {
464  return clock_type_;
465}
466
467void SystemTrayDelegateChromeOS::ShowSettings() {
468  ShowSettingsSubPageForActiveUser("");
469}
470
471bool SystemTrayDelegateChromeOS::ShouldShowSettings() {
472  return UserManager::Get()->GetCurrentUserFlow()->ShouldShowSettings();
473}
474
475void 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
484void SystemTrayDelegateChromeOS::ShowNetworkSettings(
485    const std::string& service_path) {
486  if (!LoginState::Get()->IsUserLoggedIn())
487    return;
488  ShowNetworkSettingsPage(service_path);
489}
490
491void SystemTrayDelegateChromeOS::ShowBluetoothSettings() {
492  // TODO(sad): Make this work.
493}
494
495void SystemTrayDelegateChromeOS::ShowDisplaySettings() {
496  content::RecordAction(base::UserMetricsAction("ShowDisplayOptions"));
497  ShowSettingsSubPageForActiveUser(kDisplaySettingsSubPageName);
498}
499
500void SystemTrayDelegateChromeOS::ShowChromeSlow() {
501  chrome::ScopedTabbedBrowserDisplayer displayer(
502      ProfileManager::GetPrimaryUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
503  chrome::ShowSlow(displayer.browser());
504}
505
506bool SystemTrayDelegateChromeOS::ShouldShowDisplayNotification() {
507  // Packaged app is not counted as 'last active', so if a browser opening the
508  // display settings is in background of a packaged app, it will return true.
509  // TODO(mukai): fix this.
510  Browser* active_browser =
511      chrome::FindLastActiveWithHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH);
512  if (!active_browser)
513    return true;
514
515  content::WebContents* active_contents =
516      active_browser->tab_strip_model()->GetActiveWebContents();
517  if (!active_contents)
518    return true;
519
520  GURL visible_url = active_contents->GetLastCommittedURL();
521  GURL display_settings_url =
522      chrome::GetSettingsUrl(kDisplaySettingsSubPageName);
523  GURL display_overscan_url =
524      chrome::GetSettingsUrl(kDisplayOverscanSettingsSubPageName);
525  return (visible_url != display_settings_url &&
526          visible_url != display_overscan_url);
527}
528
529void SystemTrayDelegateChromeOS::ShowDriveSettings() {
530  // TODO(tengs): Open the drive-specific settings page once we put it in.
531  // For now just show Google Drive main page.
532  chrome::ScopedTabbedBrowserDisplayer displayer(
533      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
534  chrome::ShowSingletonTabOverwritingNTP(
535      displayer.browser(),
536      chrome::GetSingletonTabNavigateParams(displayer.browser(),
537                                            GURL(kDriveSettingsPageURL)));
538}
539
540void SystemTrayDelegateChromeOS::ShowIMESettings() {
541  content::RecordAction(base::UserMetricsAction("OpenLanguageOptionsDialog"));
542  ShowSettingsSubPageForActiveUser(chrome::kLanguageOptionsSubPage);
543}
544
545void SystemTrayDelegateChromeOS::ShowHelp() {
546  chrome::ShowHelpForProfile(ProfileManager::GetActiveUserProfile(),
547                             chrome::HOST_DESKTOP_TYPE_ASH,
548                             chrome::HELP_SOURCE_MENU);
549}
550
551void SystemTrayDelegateChromeOS::ShowAccessibilityHelp() {
552  chrome::ScopedTabbedBrowserDisplayer displayer(
553      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
554  accessibility::ShowAccessibilityHelp(displayer.browser());
555}
556
557void SystemTrayDelegateChromeOS::ShowAccessibilitySettings() {
558  content::RecordAction(base::UserMetricsAction("ShowAccessibilitySettings"));
559  std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
560                         l10n_util::GetStringUTF8(
561                             IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY);
562  ShowSettingsSubPageForActiveUser(sub_page);
563}
564
565void SystemTrayDelegateChromeOS::ShowPublicAccountInfo() {
566  chrome::ScopedTabbedBrowserDisplayer displayer(
567      ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
568  chrome::ShowPolicy(displayer.browser());
569}
570
571void SystemTrayDelegateChromeOS::ShowLocallyManagedUserInfo() {
572  // TODO(antrim): find out what should we show in this case.
573  // http://crbug.com/229762
574}
575
576void SystemTrayDelegateChromeOS::ShowEnterpriseInfo() {
577  ash::user::LoginStatus status = GetUserLoginStatus();
578  if (status == ash::user::LOGGED_IN_NONE ||
579      status == ash::user::LOGGED_IN_LOCKED) {
580    scoped_refptr<chromeos::HelpAppLauncher> help_app(
581        new chromeos::HelpAppLauncher(GetNativeWindow()));
582    help_app->ShowHelpTopic(chromeos::HelpAppLauncher::HELP_ENTERPRISE);
583  } else {
584    GURL url(google_util::StringAppendGoogleLocaleParam(
585        chrome::kLearnMoreEnterpriseURL));
586    chrome::ScopedTabbedBrowserDisplayer displayer(
587        ProfileManager::GetActiveUserProfile(), chrome::HOST_DESKTOP_TYPE_ASH);
588    chrome::ShowSingletonTab(displayer.browser(), url);
589  }
590}
591
592void SystemTrayDelegateChromeOS::ShowUserLogin() {
593  ash::Shell* shell = ash::Shell::GetInstance();
594  if (!shell->delegate()->IsMultiProfilesEnabled())
595    return;
596
597  // Only regular users could add other users to current session.
598  if (UserManager::Get()->GetActiveUser()->GetType() !=
599      User::USER_TYPE_REGULAR) {
600    return;
601  }
602
603  if (static_cast<int>(UserManager::Get()->GetLoggedInUsers().size()) >=
604      shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers())
605    return;
606
607  // Launch sign in screen to add another user to current session.
608  if (UserManager::Get()->GetUsersAdmittedForMultiProfile().size()) {
609    // Don't show dialog if any logged in user in multi-profiles session
610    // dismissed it.
611    bool show_intro = true;
612    const UserList logged_in_users = UserManager::Get()->GetLoggedInUsers();
613    for (UserList::const_iterator it = logged_in_users.begin();
614         it != logged_in_users.end();
615         ++it) {
616      show_intro &= !multi_user_util::GetProfileFromUserID(
617                         multi_user_util::GetUserIDFromEmail((*it)->email()))
618                         ->GetPrefs()
619                         ->GetBoolean(prefs::kMultiProfileNeverShowIntro);
620      if (!show_intro)
621        break;
622    }
623    if (show_intro) {
624      base::Callback<void(bool)> on_accept =
625          base::Bind(&OnAcceptMultiprofilesIntro);
626      ShowMultiprofilesIntroDialog(on_accept);
627    } else {
628      UserAddingScreen::Get()->Start();
629    }
630  }
631}
632
633bool SystemTrayDelegateChromeOS::ShowSpringChargerReplacementDialog() {
634  if (!ChargerReplacementDialog::ShouldShowDialog())
635    return false;
636
637  ChargerReplacementDialog* dialog =
638      new ChargerReplacementDialog(GetNativeWindow());
639  dialog->Show();
640  return true;
641}
642
643bool SystemTrayDelegateChromeOS::IsSpringChargerReplacementDialogVisible() {
644  return ChargerReplacementDialog::IsDialogVisible();
645}
646
647bool SystemTrayDelegateChromeOS::HasUserConfirmedSafeSpringCharger() {
648  return ChargerReplacementHandler::GetChargerStatusPref() ==
649         ChargerReplacementHandler::CONFIRM_SAFE_CHARGER;
650}
651
652void SystemTrayDelegateChromeOS::ShutDown() {
653  ash::Shell::GetInstance()->lock_state_controller()->RequestShutdown();
654}
655
656void SystemTrayDelegateChromeOS::SignOut() {
657  chrome::AttemptUserExit();
658}
659
660void SystemTrayDelegateChromeOS::RequestLockScreen() {
661  // TODO(antrim) : additional logging for crbug/173178
662  LOG(WARNING) << "Requesting screen lock from AshSystemTrayDelegate";
663  DBusThreadManager::Get()->GetSessionManagerClient()->RequestLockScreen();
664}
665
666void SystemTrayDelegateChromeOS::RequestRestartForUpdate() {
667  // We expect that UpdateEngine is in "Reboot for update" state now.
668  chrome::NotifyAndTerminate(true /* fast path */);
669}
670
671void SystemTrayDelegateChromeOS::GetAvailableBluetoothDevices(
672    ash::BluetoothDeviceList* list) {
673  device::BluetoothAdapter::DeviceList devices =
674      bluetooth_adapter_->GetDevices();
675  for (size_t i = 0; i < devices.size(); ++i) {
676    device::BluetoothDevice* device = devices[i];
677    ash::BluetoothDeviceInfo info;
678    info.address = device->GetAddress();
679    info.display_name = device->GetName();
680    info.connected = device->IsConnected();
681    info.connecting = device->IsConnecting();
682    info.paired = device->IsPaired();
683    list->push_back(info);
684  }
685}
686
687void SystemTrayDelegateChromeOS::BluetoothStartDiscovering() {
688  if (GetBluetoothDiscovering()) {
689    LOG(WARNING) << "Already have active Bluetooth device discovery session.";
690    return;
691  }
692  VLOG(1) << "Requesting new Bluetooth device discovery session.";
693  should_run_bluetooth_discovery_ = true;
694  bluetooth_adapter_->StartDiscoverySession(
695      base::Bind(&SystemTrayDelegateChromeOS::OnStartBluetoothDiscoverySession,
696                 weak_ptr_factory_.GetWeakPtr()),
697      base::Bind(&BluetoothSetDiscoveringError));
698}
699
700void SystemTrayDelegateChromeOS::BluetoothStopDiscovering() {
701  should_run_bluetooth_discovery_ = false;
702  if (!GetBluetoothDiscovering()) {
703    LOG(WARNING) << "No active Bluetooth device discovery session.";
704    return;
705  }
706  VLOG(1) << "Stopping Bluetooth device discovery session.";
707  bluetooth_discovery_session_->Stop(
708      base::Bind(&base::DoNothing), base::Bind(&BluetoothSetDiscoveringError));
709}
710
711void SystemTrayDelegateChromeOS::ConnectToBluetoothDevice(
712    const std::string& address) {
713  device::BluetoothDevice* device = bluetooth_adapter_->GetDevice(address);
714  if (!device || device->IsConnecting() ||
715      (device->IsConnected() && device->IsPaired())) {
716    return;
717  }
718  if (device->IsPaired() && !device->IsConnectable())
719    return;
720  if (device->IsPaired() || !device->IsPairable()) {
721    ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
722        ash::UMA_STATUS_AREA_BLUETOOTH_CONNECT_KNOWN_DEVICE);
723    device->Connect(NULL,
724                    base::Bind(&base::DoNothing),
725                    base::Bind(&BluetoothDeviceConnectError));
726  } else {  // Show paring dialog for the unpaired device.
727    ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
728        ash::UMA_STATUS_AREA_BLUETOOTH_CONNECT_UNKNOWN_DEVICE);
729    BluetoothPairingDialog* dialog =
730        new BluetoothPairingDialog(GetNativeWindow(), device);
731    // The dialog deletes itself on close.
732    dialog->Show();
733  }
734}
735
736bool SystemTrayDelegateChromeOS::IsBluetoothDiscovering() {
737  return bluetooth_adapter_->IsDiscovering();
738}
739
740void SystemTrayDelegateChromeOS::GetCurrentIME(ash::IMEInfo* info) {
741  input_method::InputMethodManager* manager =
742      input_method::InputMethodManager::Get();
743  input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
744  input_method::InputMethodDescriptor ime = manager->GetCurrentInputMethod();
745  ExtractIMEInfo(ime, *util, info);
746  info->selected = true;
747}
748
749void SystemTrayDelegateChromeOS::GetAvailableIMEList(ash::IMEInfoList* list) {
750  input_method::InputMethodManager* manager =
751      input_method::InputMethodManager::Get();
752  input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
753  scoped_ptr<input_method::InputMethodDescriptors> ime_descriptors(
754      manager->GetActiveInputMethods());
755  std::string current = manager->GetCurrentInputMethod().id();
756  for (size_t i = 0; i < ime_descriptors->size(); i++) {
757    input_method::InputMethodDescriptor& ime = ime_descriptors->at(i);
758    ash::IMEInfo info;
759    ExtractIMEInfo(ime, *util, &info);
760    info.selected = ime.id() == current;
761    list->push_back(info);
762  }
763}
764
765void SystemTrayDelegateChromeOS::GetCurrentIMEProperties(
766    ash::IMEPropertyInfoList* list) {
767  ash::ime::InputMethodMenuItemList menu_list =
768      ash::ime::InputMethodMenuManager::GetInstance()->
769      GetCurrentInputMethodMenuItemList();
770  for (size_t i = 0; i < menu_list.size(); ++i) {
771    ash::IMEPropertyInfo property;
772    property.key = menu_list[i].key;
773    property.name = base::UTF8ToUTF16(menu_list[i].label);
774    property.selected = menu_list[i].is_selection_item_checked;
775    list->push_back(property);
776  }
777}
778
779void SystemTrayDelegateChromeOS::SwitchIME(const std::string& ime_id) {
780  input_method::InputMethodManager::Get()->ChangeInputMethod(ime_id);
781}
782
783void SystemTrayDelegateChromeOS::ActivateIMEProperty(const std::string& key) {
784  input_method::InputMethodManager::Get()->ActivateInputMethodMenuItem(key);
785}
786
787void SystemTrayDelegateChromeOS::CancelDriveOperation(int32 operation_id) {
788  DriveIntegrationService* integration_service = FindDriveIntegrationService();
789  if (!integration_service)
790    return;
791
792  integration_service->job_list()->CancelJob(operation_id);
793}
794
795void SystemTrayDelegateChromeOS::GetDriveOperationStatusList(
796    ash::DriveOperationStatusList* list) {
797  DriveIntegrationService* integration_service = FindDriveIntegrationService();
798  if (!integration_service)
799    return;
800
801  *list = ConvertToDriveStatusList(
802      integration_service->job_list()->GetJobInfoList());
803}
804
805void SystemTrayDelegateChromeOS::ShowNetworkConfigure(
806    const std::string& network_id,
807    gfx::NativeWindow parent_window) {
808  NetworkConfigView::Show(network_id, parent_window);
809}
810
811bool SystemTrayDelegateChromeOS::EnrollNetwork(
812    const std::string& network_id,
813    gfx::NativeWindow parent_window) {
814  return enrollment::CreateDialog(network_id, parent_window);
815}
816
817void SystemTrayDelegateChromeOS::ManageBluetoothDevices() {
818  content::RecordAction(base::UserMetricsAction("ShowBluetoothSettingsPage"));
819  std::string sub_page =
820      std::string(chrome::kSearchSubPage) + "#" +
821      l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH);
822  ShowSettingsSubPageForActiveUser(sub_page);
823}
824
825void SystemTrayDelegateChromeOS::ToggleBluetooth() {
826  bluetooth_adapter_->SetPowered(!bluetooth_adapter_->IsPowered(),
827                                 base::Bind(&base::DoNothing),
828                                 base::Bind(&BluetoothPowerFailure));
829}
830
831void SystemTrayDelegateChromeOS::ShowMobileSimDialog() {
832  SimDialogDelegate::ShowDialog(GetNativeWindow(),
833                                SimDialogDelegate::SIM_DIALOG_UNLOCK);
834}
835
836void SystemTrayDelegateChromeOS::ShowMobileSetupDialog(
837    const std::string& service_path) {
838  MobileSetupDialog::Show(service_path);
839}
840
841void SystemTrayDelegateChromeOS::ShowOtherNetworkDialog(
842    const std::string& type) {
843  if (type == shill::kTypeCellular) {
844    ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow());
845    return;
846  }
847  NetworkConfigView::ShowForType(type, GetNativeWindow());
848}
849
850bool SystemTrayDelegateChromeOS::GetBluetoothAvailable() {
851  return bluetooth_adapter_->IsPresent();
852}
853
854bool SystemTrayDelegateChromeOS::GetBluetoothEnabled() {
855  return bluetooth_adapter_->IsPowered();
856}
857
858bool SystemTrayDelegateChromeOS::GetBluetoothDiscovering() {
859  return (bluetooth_discovery_session_.get() &&
860      bluetooth_discovery_session_->IsActive());
861}
862
863void SystemTrayDelegateChromeOS::ChangeProxySettings() {
864  CHECK(GetUserLoginStatus() == ash::user::LOGGED_IN_NONE);
865  LoginDisplayHostImpl::default_host()->OpenProxySettings();
866}
867
868ash::VolumeControlDelegate*
869SystemTrayDelegateChromeOS::GetVolumeControlDelegate() const {
870  return volume_control_delegate_.get();
871}
872
873void SystemTrayDelegateChromeOS::SetVolumeControlDelegate(
874    scoped_ptr<ash::VolumeControlDelegate> delegate) {
875  volume_control_delegate_.swap(delegate);
876}
877
878bool SystemTrayDelegateChromeOS::GetSessionStartTime(
879    base::TimeTicks* session_start_time) {
880  *session_start_time = session_start_time_;
881  return have_session_start_time_;
882}
883
884bool SystemTrayDelegateChromeOS::GetSessionLengthLimit(
885    base::TimeDelta* session_length_limit) {
886  *session_length_limit = session_length_limit_;
887  return have_session_length_limit_;
888}
889
890int SystemTrayDelegateChromeOS::GetSystemTrayMenuWidth() {
891  return l10n_util::GetLocalizedContentsWidthInPixels(
892      IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
893}
894
895void SystemTrayDelegateChromeOS::ActiveUserWasChanged() {
896  GetSystemTrayNotifier()->NotifyUserUpdate();
897}
898
899bool SystemTrayDelegateChromeOS::IsNetworkBehindCaptivePortal(
900    const std::string& service_path) const {
901  NetworkPortalDetector::CaptivePortalState state =
902      NetworkPortalDetector::Get()->GetCaptivePortalState(service_path);
903  return state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
904}
905
906bool SystemTrayDelegateChromeOS::IsSearchKeyMappedToCapsLock() {
907  return search_key_mapped_to_ == input_method::kCapsLockKey;
908}
909
910ash::tray::UserAccountsDelegate*
911SystemTrayDelegateChromeOS::GetUserAccountsDelegate(
912    const std::string& user_id) {
913  if (!accounts_delegates_.contains(user_id)) {
914    // TODO(dzhioev): replace stub with real implementation.
915    accounts_delegates_.set(user_id,
916                            scoped_ptr<ash::tray::UserAccountsDelegate>(
917                                new StubUserAccountsDelegate(user_id)));
918    static_cast<StubUserAccountsDelegate*>(accounts_delegates_.get(user_id))
919        ->AddAccount("secondary_account1@gmail.com");
920    static_cast<StubUserAccountsDelegate*>(accounts_delegates_.get(user_id))
921        ->AddAccount("very_long_account_name_for_user@gmail.com");
922    static_cast<StubUserAccountsDelegate*>(accounts_delegates_.get(user_id))
923        ->AddAccount("secondary_account2@gmail.com");
924    static_cast<StubUserAccountsDelegate*>(accounts_delegates_.get(user_id))
925        ->AddAccount("very_very_very_long_account_name_for_user@gmail.com");
926  }
927  return accounts_delegates_.get(user_id);
928}
929
930ash::SystemTray* SystemTrayDelegateChromeOS::GetPrimarySystemTray() {
931  return ash::Shell::GetInstance()->GetPrimarySystemTray();
932}
933
934ash::SystemTrayNotifier* SystemTrayDelegateChromeOS::GetSystemTrayNotifier() {
935  return ash::Shell::GetInstance()->system_tray_notifier();
936}
937
938void SystemTrayDelegateChromeOS::SetProfile(Profile* profile) {
939  // Stop observing the Drive integration status and the AppWindowRegistry of
940  // the current |user_profile_|.
941  UnobserveDriveUpdates();
942  StopObservingAppWindowRegistry();
943
944  user_profile_ = profile;
945
946  // Start observing the Drive integration status and the AppWindowRegistry of
947  // the newly set |user_profile_|.
948  ObserveDriveUpdates();
949  apps::AppWindowRegistry::Get(user_profile_)->AddObserver(this);
950
951  PrefService* prefs = profile->GetPrefs();
952  user_pref_registrar_.reset(new PrefChangeRegistrar);
953  user_pref_registrar_->Init(prefs);
954  user_pref_registrar_->Add(
955      prefs::kUse24HourClock,
956      base::Bind(&SystemTrayDelegateChromeOS::UpdateClockType,
957                 base::Unretained(this)));
958  user_pref_registrar_->Add(
959      prefs::kLanguageRemapSearchKeyTo,
960      base::Bind(&SystemTrayDelegateChromeOS::OnLanguageRemapSearchKeyToChanged,
961                 base::Unretained(this)));
962  user_pref_registrar_->Add(
963      prefs::kShowLogoutButtonInTray,
964      base::Bind(&SystemTrayDelegateChromeOS::UpdateShowLogoutButtonInTray,
965                 base::Unretained(this)));
966  user_pref_registrar_->Add(
967      prefs::kLogoutDialogDurationMs,
968      base::Bind(&SystemTrayDelegateChromeOS::UpdateLogoutDialogDuration,
969                 base::Unretained(this)));
970  user_pref_registrar_->Add(
971      prefs::kLargeCursorEnabled,
972      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
973                 base::Unretained(this),
974                 ash::A11Y_NOTIFICATION_NONE));
975  user_pref_registrar_->Add(
976      prefs::kAutoclickEnabled,
977      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
978                 base::Unretained(this),
979                 ash::A11Y_NOTIFICATION_NONE));
980  user_pref_registrar_->Add(
981      prefs::kShouldAlwaysShowAccessibilityMenu,
982      base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
983                 base::Unretained(this),
984                 ash::A11Y_NOTIFICATION_NONE));
985  user_pref_registrar_->Add(
986      prefs::kPerformanceTracingEnabled,
987      base::Bind(&SystemTrayDelegateChromeOS::UpdatePerformanceTracing,
988                 base::Unretained(this)));
989
990  UpdateClockType();
991  UpdateShowLogoutButtonInTray();
992  UpdateLogoutDialogDuration();
993  UpdatePerformanceTracing();
994  search_key_mapped_to_ =
995      profile->GetPrefs()->GetInteger(prefs::kLanguageRemapSearchKeyTo);
996}
997
998bool SystemTrayDelegateChromeOS::UnsetProfile(Profile* profile) {
999  if (profile != user_profile_)
1000    return false;
1001  user_pref_registrar_.reset();
1002  user_profile_ = NULL;
1003  return true;
1004}
1005
1006void SystemTrayDelegateChromeOS::ObserveDriveUpdates() {
1007  DriveIntegrationService* integration_service = FindDriveIntegrationService();
1008  if (integration_service)
1009    integration_service->job_list()->AddObserver(this);
1010}
1011
1012void SystemTrayDelegateChromeOS::UnobserveDriveUpdates() {
1013  DriveIntegrationService* integration_service = FindDriveIntegrationService();
1014  if (integration_service)
1015    integration_service->job_list()->RemoveObserver(this);
1016}
1017
1018bool SystemTrayDelegateChromeOS::GetShouldUse24HourClockForTesting() const {
1019  return ShouldUse24HourClock();
1020}
1021
1022bool SystemTrayDelegateChromeOS::ShouldUse24HourClock() const {
1023  // On login screen and in guest mode owner default is used for
1024  // kUse24HourClock preference.
1025  const ash::user::LoginStatus status = GetUserLoginStatus();
1026  const CrosSettings* const cros_settings = CrosSettings::Get();
1027  bool system_use_24_hour_clock = true;
1028  const bool system_value_found = cros_settings->GetBoolean(
1029      kSystemUse24HourClock, &system_use_24_hour_clock);
1030
1031  if ((status == ash::user::LOGGED_IN_NONE) || !user_pref_registrar_)
1032    return (system_value_found
1033                ? system_use_24_hour_clock
1034                : (base::GetHourClockType() == base::k24HourClock));
1035
1036  const PrefService::Preference* user_pref =
1037      user_pref_registrar_->prefs()->FindPreference(prefs::kUse24HourClock);
1038  if (status == ash::user::LOGGED_IN_GUEST && user_pref->IsDefaultValue())
1039    return (system_value_found
1040                ? system_use_24_hour_clock
1041                : (base::GetHourClockType() == base::k24HourClock));
1042
1043  bool use_24_hour_clock = true;
1044  user_pref->GetValue()->GetAsBoolean(&use_24_hour_clock);
1045  return use_24_hour_clock;
1046}
1047
1048void SystemTrayDelegateChromeOS::UpdateClockType() {
1049  const bool use_24_hour_clock = ShouldUse24HourClock();
1050  clock_type_ = use_24_hour_clock ? base::k24HourClock : base::k12HourClock;
1051  GetSystemTrayNotifier()->NotifyDateFormatChanged();
1052  // This also works for enterprise-managed devices because they never have
1053  // local owner.
1054  if (chromeos::UserManager::Get()->IsCurrentUserOwner())
1055    CrosSettings::Get()->SetBoolean(kSystemUse24HourClock, use_24_hour_clock);
1056}
1057
1058void SystemTrayDelegateChromeOS::UpdateShowLogoutButtonInTray() {
1059  GetSystemTrayNotifier()->NotifyShowLoginButtonChanged(
1060      user_pref_registrar_->prefs()->GetBoolean(
1061          prefs::kShowLogoutButtonInTray));
1062}
1063
1064void SystemTrayDelegateChromeOS::UpdateLogoutDialogDuration() {
1065  const int duration_ms =
1066      user_pref_registrar_->prefs()->GetInteger(prefs::kLogoutDialogDurationMs);
1067  GetSystemTrayNotifier()->NotifyLogoutDialogDurationChanged(
1068      base::TimeDelta::FromMilliseconds(duration_ms));
1069}
1070
1071void SystemTrayDelegateChromeOS::UpdateSessionStartTime() {
1072  const PrefService* local_state = local_state_registrar_->prefs();
1073  if (local_state->HasPrefPath(prefs::kSessionStartTime)) {
1074    have_session_start_time_ = true;
1075    session_start_time_ = base::TimeTicks::FromInternalValue(
1076        local_state->GetInt64(prefs::kSessionStartTime));
1077  } else {
1078    have_session_start_time_ = false;
1079    session_start_time_ = base::TimeTicks();
1080  }
1081  GetSystemTrayNotifier()->NotifySessionStartTimeChanged();
1082}
1083
1084void SystemTrayDelegateChromeOS::UpdateSessionLengthLimit() {
1085  const PrefService* local_state = local_state_registrar_->prefs();
1086  if (local_state->HasPrefPath(prefs::kSessionLengthLimit)) {
1087    have_session_length_limit_ = true;
1088    session_length_limit_ = base::TimeDelta::FromMilliseconds(
1089        std::min(std::max(local_state->GetInteger(prefs::kSessionLengthLimit),
1090                          kSessionLengthLimitMinMs),
1091                 kSessionLengthLimitMaxMs));
1092  } else {
1093    have_session_length_limit_ = false;
1094    session_length_limit_ = base::TimeDelta();
1095  }
1096  GetSystemTrayNotifier()->NotifySessionLengthLimitChanged();
1097}
1098
1099void SystemTrayDelegateChromeOS::StopObservingAppWindowRegistry() {
1100  if (!user_profile_)
1101    return;
1102
1103  apps::AppWindowRegistry* registry =
1104      apps::AppWindowRegistry::Factory::GetForBrowserContext(user_profile_,
1105                                                             false);
1106  if (registry)
1107    registry->RemoveObserver(this);
1108}
1109
1110void SystemTrayDelegateChromeOS::NotifyIfLastWindowClosed() {
1111  if (!user_profile_)
1112    return;
1113
1114  BrowserList* browser_list =
1115      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
1116  for (BrowserList::const_iterator it = browser_list->begin();
1117       it != browser_list->end();
1118       ++it) {
1119    if ((*it)->profile()->IsSameProfile(user_profile_)) {
1120      // The current user has at least one open browser window.
1121      return;
1122    }
1123  }
1124
1125  if (!apps::AppWindowRegistry::Get(user_profile_)->app_windows().empty()) {
1126    // The current user has at least one open app window.
1127    return;
1128  }
1129
1130  GetSystemTrayNotifier()->NotifyLastWindowClosed();
1131}
1132
1133// LoginState::Observer overrides.
1134void SystemTrayDelegateChromeOS::LoggedInStateChanged() {
1135  // It apparently sometimes takes a while after login before the current user
1136  // is recognized as the owner. Make sure that the system-wide clock setting
1137  // is updated when the recognition eventually happens
1138  // (http://crbug.com/278601).
1139  //
1140  // Note that it isn't safe to blindly call UpdateClockType() from this
1141  // method, as LoggedInStateChanged() is also called before the logged-in
1142  // user's profile has actually been loaded (http://crbug.com/317745). The
1143  // system tray's time format is updated at login via SetProfile().
1144  if (chromeos::UserManager::Get()->IsCurrentUserOwner()) {
1145    CrosSettings::Get()->SetBoolean(kSystemUse24HourClock,
1146                                    ShouldUse24HourClock());
1147  }
1148}
1149
1150// Overridden from SessionManagerClient::Observer.
1151void SystemTrayDelegateChromeOS::ScreenIsLocked() {
1152  screen_locked_ = true;
1153  ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(GetUserLoginStatus());
1154}
1155
1156void SystemTrayDelegateChromeOS::ScreenIsUnlocked() {
1157  screen_locked_ = false;
1158  ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(GetUserLoginStatus());
1159}
1160
1161gfx::NativeWindow SystemTrayDelegateChromeOS::GetNativeWindow() const {
1162  bool session_started = ash::Shell::GetInstance()
1163                             ->session_state_delegate()
1164                             ->IsActiveUserSessionStarted();
1165  return GetNativeWindowByStatus(GetUserLoginStatus(), session_started);
1166}
1167
1168// content::NotificationObserver implementation.
1169void SystemTrayDelegateChromeOS::Observe(
1170    int type,
1171    const content::NotificationSource& source,
1172    const content::NotificationDetails& details) {
1173  switch (type) {
1174    case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: {
1175      UpgradeDetector* detector =
1176          content::Source<UpgradeDetector>(source).ptr();
1177      ash::UpdateObserver::UpdateSeverity severity =
1178          ash::UpdateObserver::UPDATE_NORMAL;
1179      switch (detector->upgrade_notification_stage()) {
1180        case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
1181          severity = ash::UpdateObserver::UPDATE_SEVERE_RED;
1182          break;
1183
1184        case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
1185          severity = ash::UpdateObserver::UPDATE_HIGH_ORANGE;
1186          break;
1187
1188        case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
1189          severity = ash::UpdateObserver::UPDATE_LOW_GREEN;
1190          break;
1191
1192        case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
1193        default:
1194          severity = ash::UpdateObserver::UPDATE_NORMAL;
1195          break;
1196      }
1197      GetSystemTrayNotifier()->NotifyUpdateRecommended(severity);
1198      break;
1199    }
1200    case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
1201      // This notification is also sent on login screen when user avatar
1202      // is loaded from file.
1203      if (GetUserLoginStatus() != ash::user::LOGGED_IN_NONE) {
1204        GetSystemTrayNotifier()->NotifyUserUpdate();
1205      }
1206      break;
1207    }
1208    case chrome::NOTIFICATION_PROFILE_CREATED: {
1209      SetProfile(content::Source<Profile>(source).ptr());
1210      registrar_->Remove(this,
1211                         chrome::NOTIFICATION_PROFILE_CREATED,
1212                         content::NotificationService::AllSources());
1213      break;
1214    }
1215    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
1216      if (UnsetProfile(content::Source<Profile>(source).ptr())) {
1217        registrar_->Remove(this,
1218                           chrome::NOTIFICATION_PROFILE_DESTROYED,
1219                           content::NotificationService::AllSources());
1220      }
1221      break;
1222    }
1223    case chrome::NOTIFICATION_SESSION_STARTED: {
1224      ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(
1225          GetUserLoginStatus());
1226      SetProfile(ProfileManager::GetActiveUserProfile());
1227      break;
1228    }
1229    default:
1230      NOTREACHED();
1231  }
1232}
1233
1234void SystemTrayDelegateChromeOS::OnLanguageRemapSearchKeyToChanged() {
1235  search_key_mapped_to_ = user_pref_registrar_->prefs()->GetInteger(
1236      prefs::kLanguageRemapSearchKeyTo);
1237}
1238
1239void SystemTrayDelegateChromeOS::OnAccessibilityModeChanged(
1240    ash::AccessibilityNotificationVisibility notify) {
1241  GetSystemTrayNotifier()->NotifyAccessibilityModeChanged(notify);
1242}
1243
1244void SystemTrayDelegateChromeOS::UpdatePerformanceTracing() {
1245  if (!user_pref_registrar_)
1246    return;
1247  bool value = user_pref_registrar_->prefs()->GetBoolean(
1248      prefs::kPerformanceTracingEnabled);
1249  GetSystemTrayNotifier()->NotifyTracingModeChanged(value);
1250}
1251
1252// Overridden from InputMethodManager::Observer.
1253void SystemTrayDelegateChromeOS::InputMethodChanged(
1254    input_method::InputMethodManager* manager,
1255    bool show_message) {
1256  GetSystemTrayNotifier()->NotifyRefreshIME();
1257}
1258
1259// Overridden from InputMethodMenuManager::Observer.
1260void SystemTrayDelegateChromeOS::InputMethodMenuItemChanged(
1261    ash::ime::InputMethodMenuManager* manager) {
1262  GetSystemTrayNotifier()->NotifyRefreshIME();
1263}
1264
1265// Overridden from CrasAudioHandler::AudioObserver.
1266void SystemTrayDelegateChromeOS::OnOutputVolumeChanged() {
1267  GetSystemTrayNotifier()->NotifyAudioOutputVolumeChanged();
1268}
1269
1270void SystemTrayDelegateChromeOS::OnOutputMuteChanged() {
1271  GetSystemTrayNotifier()->NotifyAudioOutputMuteChanged();
1272}
1273
1274void SystemTrayDelegateChromeOS::OnInputGainChanged() {
1275}
1276
1277void SystemTrayDelegateChromeOS::OnInputMuteChanged() {
1278}
1279
1280void SystemTrayDelegateChromeOS::OnAudioNodesChanged() {
1281  GetSystemTrayNotifier()->NotifyAudioNodesChanged();
1282}
1283
1284void SystemTrayDelegateChromeOS::OnActiveOutputNodeChanged() {
1285  GetSystemTrayNotifier()->NotifyAudioActiveOutputNodeChanged();
1286}
1287
1288void SystemTrayDelegateChromeOS::OnActiveInputNodeChanged() {
1289  GetSystemTrayNotifier()->NotifyAudioActiveInputNodeChanged();
1290}
1291
1292// drive::JobListObserver overrides.
1293void SystemTrayDelegateChromeOS::OnJobAdded(const drive::JobInfo& job_info) {
1294  OnJobUpdated(job_info);
1295}
1296
1297void SystemTrayDelegateChromeOS::OnJobDone(const drive::JobInfo& job_info,
1298                                           drive::FileError error) {
1299  ash::DriveOperationStatus status;
1300  if (ConvertToFinishedDriveOperationStatus(job_info, error, &status))
1301    GetSystemTrayNotifier()->NotifyDriveJobUpdated(status);
1302}
1303
1304void SystemTrayDelegateChromeOS::OnJobUpdated(const drive::JobInfo& job_info) {
1305  ash::DriveOperationStatus status;
1306  if (ConvertToDriveOperationStatus(job_info, &status))
1307    GetSystemTrayNotifier()->NotifyDriveJobUpdated(status);
1308}
1309
1310DriveIntegrationService*
1311SystemTrayDelegateChromeOS::FindDriveIntegrationService() {
1312  return user_profile_
1313             ? DriveIntegrationServiceFactory::FindForProfile(user_profile_)
1314             : NULL;
1315}
1316
1317// Overridden from BluetoothAdapter::Observer.
1318void SystemTrayDelegateChromeOS::AdapterPresentChanged(
1319    device::BluetoothAdapter* adapter,
1320    bool present) {
1321  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1322}
1323
1324void SystemTrayDelegateChromeOS::AdapterPoweredChanged(
1325    device::BluetoothAdapter* adapter,
1326    bool powered) {
1327  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1328}
1329
1330void SystemTrayDelegateChromeOS::AdapterDiscoveringChanged(
1331    device::BluetoothAdapter* adapter,
1332    bool discovering) {
1333  GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
1334}
1335
1336void SystemTrayDelegateChromeOS::DeviceAdded(device::BluetoothAdapter* adapter,
1337                                             device::BluetoothDevice* device) {
1338  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1339}
1340
1341void SystemTrayDelegateChromeOS::DeviceChanged(
1342    device::BluetoothAdapter* adapter,
1343    device::BluetoothDevice* device) {
1344  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1345}
1346
1347void SystemTrayDelegateChromeOS::DeviceRemoved(
1348    device::BluetoothAdapter* adapter,
1349    device::BluetoothDevice* device) {
1350  GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1351}
1352
1353void SystemTrayDelegateChromeOS::OnStartBluetoothDiscoverySession(
1354    scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
1355  // If the discovery session was returned after a request to stop discovery
1356  // (e.g. the user dismissed the Bluetooth detailed view before the call
1357  // returned), don't claim the discovery session and let it clean up.
1358  if (!should_run_bluetooth_discovery_)
1359    return;
1360  VLOG(1) << "Claiming new Bluetooth device discovery session.";
1361  bluetooth_discovery_session_ = discovery_session.Pass();
1362  GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
1363}
1364
1365void SystemTrayDelegateChromeOS::UpdateEnterpriseDomain() {
1366  policy::BrowserPolicyConnectorChromeOS* connector =
1367      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1368  std::string enterprise_domain = connector->GetEnterpriseDomain();
1369  if (enterprise_domain_ != enterprise_domain) {
1370    enterprise_domain_ = enterprise_domain;
1371    GetSystemTrayNotifier()->NotifyEnterpriseDomainChanged();
1372  }
1373}
1374
1375// Overridden from CloudPolicyStore::Observer
1376void SystemTrayDelegateChromeOS::OnStoreLoaded(
1377    policy::CloudPolicyStore* store) {
1378  UpdateEnterpriseDomain();
1379}
1380
1381void SystemTrayDelegateChromeOS::OnStoreError(policy::CloudPolicyStore* store) {
1382  UpdateEnterpriseDomain();
1383}
1384
1385// Overridden from ash::SessionStateObserver
1386void SystemTrayDelegateChromeOS::UserAddedToSession(
1387    const std::string& user_id) {
1388  GetSystemTrayNotifier()->NotifyUserAddedToSession();
1389}
1390
1391// Overridden from chrome::BrowserListObserver.
1392void SystemTrayDelegateChromeOS::OnBrowserRemoved(Browser* browser) {
1393  NotifyIfLastWindowClosed();
1394}
1395
1396// Overridden from apps::AppWindowRegistry::Observer.
1397void SystemTrayDelegateChromeOS::OnAppWindowAdded(apps::AppWindow* app_window) {
1398}
1399
1400void SystemTrayDelegateChromeOS::OnAppWindowIconChanged(
1401    apps::AppWindow* app_window) {}
1402
1403void SystemTrayDelegateChromeOS::OnAppWindowRemoved(
1404    apps::AppWindow* app_window) {
1405  NotifyIfLastWindowClosed();
1406}
1407
1408void SystemTrayDelegateChromeOS::OnAccessibilityStatusChanged(
1409    const AccessibilityStatusEventDetails& details) {
1410  if (details.notification_type == ACCESSIBILITY_MANAGER_SHUTDOWN)
1411    accessibility_subscription_.reset();
1412  else
1413    OnAccessibilityModeChanged(details.notify);
1414}
1415
1416ash::SystemTrayDelegate* CreateSystemTrayDelegate() {
1417  return new SystemTrayDelegateChromeOS();
1418}
1419
1420}  // namespace chromeos
1421