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