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