1// Copyright (c) 2012 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/chromeos/system/ash_system_tray_delegate.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/session_state_delegate.h"
15#include "ash/session_state_observer.h"
16#include "ash/shell.h"
17#include "ash/shell_delegate.h"
18#include "ash/shell_window_ids.h"
19#include "ash/system/bluetooth/bluetooth_observer.h"
20#include "ash/system/brightness/brightness_observer.h"
21#include "ash/system/chromeos/network/network_observer.h"
22#include "ash/system/chromeos/network/network_tray_delegate.h"
23#include "ash/system/date/clock_observer.h"
24#include "ash/system/drive/drive_observer.h"
25#include "ash/system/ime/ime_observer.h"
26#include "ash/system/logout_button/logout_button_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/tray_caps_lock.h"
32#include "ash/system/user/login_status.h"
33#include "ash/system/user/update_observer.h"
34#include "ash/system/user/user_observer.h"
35#include "ash/volume_control_delegate.h"
36#include "ash/wm/lock_state_controller.h"
37#include "base/bind_helpers.h"
38#include "base/callback.h"
39#include "base/chromeos/chromeos_version.h"
40#include "base/command_line.h"
41#include "base/logging.h"
42#include "base/memory/weak_ptr.h"
43#include "base/prefs/pref_service.h"
44#include "base/strings/stringprintf.h"
45#include "base/strings/utf_string_conversions.h"
46#include "base/time/time.h"
47#include "chrome/browser/browser_process.h"
48#include "chrome/browser/chrome_notification_types.h"
49#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
50#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
51#include "chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.h"
52#include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
53#include "chrome/browser/chromeos/cros/network_library.h"
54#include "chrome/browser/chromeos/drive/drive_integration_service.h"
55#include "chrome/browser/chromeos/drive/job_list.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/user.h"
64#include "chrome/browser/chromeos/login/user_adding_screen.h"
65#include "chrome/browser/chromeos/login/user_manager.h"
66#include "chrome/browser/chromeos/mobile_config.h"
67#include "chrome/browser/chromeos/options/network_config_view.h"
68#include "chrome/browser/chromeos/options/network_connect.h"
69#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
70#include "chrome/browser/chromeos/settings/cros_settings.h"
71#include "chrome/browser/chromeos/sim_dialog_delegate.h"
72#include "chrome/browser/chromeos/status/data_promo_notification.h"
73#include "chrome/browser/chromeos/system/timezone_settings.h"
74#include "chrome/browser/chromeos/system_key_event_listener.h"
75#include "chrome/browser/drive/drive_service_interface.h"
76#include "chrome/browser/feedback/tracing_manager.h"
77#include "chrome/browser/google/google_util.h"
78#include "chrome/browser/lifetime/application_lifetime.h"
79#include "chrome/browser/policy/browser_policy_connector.h"
80#include "chrome/browser/policy/cloud/cloud_policy_store.h"
81#include "chrome/browser/profiles/profile_manager.h"
82#include "chrome/browser/ui/ash/volume_controller_chromeos.h"
83#include "chrome/browser/ui/browser.h"
84#include "chrome/browser/ui/browser_finder.h"
85#include "chrome/browser/ui/chrome_pages.h"
86#include "chrome/browser/ui/host_desktop.h"
87#include "chrome/browser/ui/singleton_tabs.h"
88#include "chrome/browser/ui/tabs/tab_strip_model.h"
89#include "chrome/browser/upgrade_detector.h"
90#include "chrome/common/pref_names.h"
91#include "chrome/common/url_constants.h"
92#include "chromeos/chromeos_switches.h"
93#include "chromeos/dbus/dbus_thread_manager.h"
94#include "chromeos/dbus/power_manager_client.h"
95#include "chromeos/dbus/session_manager_client.h"
96#include "chromeos/dbus/system_clock_client.h"
97#include "chromeos/ime/extension_ime_util.h"
98#include "chromeos/ime/input_method_manager.h"
99#include "chromeos/ime/xkeyboard.h"
100#include "chromeos/login/login_state.h"
101#include "chromeos/network/network_state.h"
102#include "chromeos/network/network_state_handler.h"
103#include "content/public/browser/browser_thread.h"
104#include "content/public/browser/notification_observer.h"
105#include "content/public/browser/notification_service.h"
106#include "content/public/browser/user_metrics.h"
107#include "content/public/browser/web_contents.h"
108#include "device/bluetooth/bluetooth_adapter.h"
109#include "device/bluetooth/bluetooth_adapter_factory.h"
110#include "device/bluetooth/bluetooth_device.h"
111#include "grit/ash_strings.h"
112#include "grit/generated_resources.h"
113#include "grit/locale_settings.h"
114#include "net/base/escape.h"
115#include "third_party/cros_system_api/dbus/service_constants.h"
116#include "ui/base/l10n/l10n_util.h"
117#include "ui/base/l10n/time_format.h"
118
119using drive::DriveIntegrationService;
120using drive::DriveIntegrationServiceFactory;
121
122namespace chromeos {
123
124namespace {
125
126// The minimum session length limit that can be set.
127const int kSessionLengthLimitMinMs = 30 * 1000;  // 30 seconds.
128
129// The maximum session length limit that can be set.
130const int kSessionLengthLimitMaxMs = 24 * 60 * 60 * 1000;  // 24 hours.
131
132const char kDisplaySettingsSubPageName[] = "display";
133const char kDisplayOverscanSettingsSubPageName[] = "displayOverscan";
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(
146    ash::user::LoginStatus login_status) {
147  int container_id =
148      (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 BluetoothDiscoveryFailure() {
213  // TODO(sad): Show an error bubble?
214}
215
216void BluetoothSetDiscoveringError() {
217  LOG(ERROR) << "BluetoothSetDiscovering failed.";
218}
219
220void BluetoothDeviceConnectError(
221    device::BluetoothDevice::ConnectErrorCode error_code) {
222  // TODO(sad): Do something?
223}
224
225ash::NetworkObserver::NetworkType NetworkTypeForCellular(
226    const CellularNetwork* cellular) {
227  if (cellular->network_technology() == NETWORK_TECHNOLOGY_LTE ||
228      cellular->network_technology() == NETWORK_TECHNOLOGY_LTE_ADVANCED)
229    return ash::NetworkObserver::NETWORK_CELLULAR_LTE;
230  return ash::NetworkObserver::NETWORK_CELLULAR;
231}
232
233class SystemTrayDelegate : public ash::SystemTrayDelegate,
234                           public PowerManagerClient::Observer,
235                           public SessionManagerClient::Observer,
236                           public NetworkLibrary::NetworkManagerObserver,
237                           public drive::JobListObserver,
238                           public content::NotificationObserver,
239                           public input_method::InputMethodManager::Observer,
240                           public system::TimezoneSettings::Observer,
241                           public chromeos::LoginState::Observer,
242                           public chromeos::SystemClockClient::Observer,
243                           public device::BluetoothAdapter::Observer,
244                           public SystemKeyEventListener::CapsLockObserver,
245                           public ash::NetworkTrayDelegate,
246                           public policy::CloudPolicyStore::Observer,
247                           public ash::SessionStateObserver {
248 public:
249  SystemTrayDelegate()
250      : ui_weak_ptr_factory_(
251          new base::WeakPtrFactory<SystemTrayDelegate>(this)),
252        user_profile_(NULL),
253        clock_type_(base::GetHourClockType()),
254        search_key_mapped_to_(input_method::kSearchKey),
255        screen_locked_(false),
256        have_session_start_time_(false),
257        have_session_length_limit_(false),
258        data_promo_notification_(new DataPromoNotification()),
259        cellular_activating_(false),
260        cellular_out_of_credits_(false),
261        volume_control_delegate_(new VolumeController()) {
262    // Register notifications on construction so that events such as
263    // PROFILE_CREATED do not get missed if they happen before Initialize().
264    registrar_.reset(new content::NotificationRegistrar);
265    registrar_->Add(this,
266                   chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
267                   content::NotificationService::AllSources());
268    registrar_->Add(this,
269                   chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
270                   content::NotificationService::AllSources());
271    if (GetUserLoginStatus() == ash::user::LOGGED_IN_NONE) {
272      registrar_->Add(this,
273                     chrome::NOTIFICATION_SESSION_STARTED,
274                     content::NotificationService::AllSources());
275    }
276    registrar_->Add(this,
277                   chrome::NOTIFICATION_PROFILE_CREATED,
278                   content::NotificationService::AllSources());
279    registrar_->Add(this,
280                   chrome::NOTIFICATION_PROFILE_DESTROYED,
281                   content::NotificationService::AllSources());
282    registrar_->Add(
283        this,
284        chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER,
285        content::NotificationService::AllSources());
286    registrar_->Add(
287        this,
288        chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK,
289        content::NotificationService::AllSources());
290    registrar_->Add(
291        this,
292        chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE,
293        content::NotificationService::AllSources());
294  }
295
296  virtual void Initialize() OVERRIDE {
297    DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
298    DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
299
300    NetworkLibrary* crosnet = NetworkLibrary::Get();
301    crosnet->AddNetworkManagerObserver(this);
302    OnNetworkManagerChanged(crosnet);
303
304    input_method::InputMethodManager::Get()->AddObserver(this);
305    UpdateClockType();
306
307    system::TimezoneSettings::GetInstance()->AddObserver(this);
308    DBusThreadManager::Get()->GetSystemClockClient()->AddObserver(this);
309
310    if (SystemKeyEventListener::GetInstance())
311      SystemKeyEventListener::GetInstance()->AddCapsLockObserver(this);
312
313    device::BluetoothAdapterFactory::GetAdapter(
314        base::Bind(&SystemTrayDelegate::InitializeOnAdapterReady,
315                   ui_weak_ptr_factory_->GetWeakPtr()));
316
317    ash::Shell::GetInstance()->session_state_delegate()->
318        AddSessionStateObserver(this);
319
320    if (LoginState::IsInitialized())
321      LoginState::Get()->AddObserver(this);
322  }
323
324  virtual void Shutdown() OVERRIDE {
325    data_promo_notification_.reset();
326  }
327
328  void InitializeOnAdapterReady(
329      scoped_refptr<device::BluetoothAdapter> adapter) {
330    bluetooth_adapter_ = adapter;
331    CHECK(bluetooth_adapter_.get());
332    bluetooth_adapter_->AddObserver(this);
333
334    local_state_registrar_.reset(new PrefChangeRegistrar);
335    local_state_registrar_->Init(g_browser_process->local_state());
336
337    UpdateSessionStartTime();
338    UpdateSessionLengthLimit();
339
340    local_state_registrar_->Add(
341        prefs::kSessionStartTime,
342        base::Bind(&SystemTrayDelegate::UpdateSessionStartTime,
343                   base::Unretained(this)));
344    local_state_registrar_->Add(
345        prefs::kSessionLengthLimit,
346        base::Bind(&SystemTrayDelegate::UpdateSessionLengthLimit,
347                   base::Unretained(this)));
348
349    policy::BrowserPolicyConnector* policy_connector =
350        g_browser_process->browser_policy_connector();
351    policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
352        policy_connector->GetDeviceCloudPolicyManager();
353    if (policy_manager)
354      policy_manager->core()->store()->AddObserver(this);
355    UpdateEnterpriseDomain();
356  }
357
358  virtual ~SystemTrayDelegate() {
359    // Unregister PrefChangeRegistrars.
360    local_state_registrar_.reset();
361    user_pref_registrar_.reset();
362
363    // Unregister content notifications befure destroying any components.
364    registrar_.reset();
365
366    DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
367    DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
368    DBusThreadManager::Get()->GetSystemClockClient()->RemoveObserver(this);
369    NetworkLibrary* crosnet = NetworkLibrary::Get();
370    if (crosnet)
371      crosnet->RemoveNetworkManagerObserver(this);
372    input_method::InputMethodManager::Get()->RemoveObserver(this);
373    system::TimezoneSettings::GetInstance()->RemoveObserver(this);
374    if (SystemKeyEventListener::GetInstance())
375      SystemKeyEventListener::GetInstance()->RemoveCapsLockObserver(this);
376    bluetooth_adapter_->RemoveObserver(this);
377    ash::Shell::GetInstance()->session_state_delegate()->
378        RemoveSessionStateObserver(this);
379    LoginState::Get()->RemoveObserver(this);
380
381    // Stop observing Drive operations.
382    UnobserveDriveUpdates();
383
384    policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
385        g_browser_process->browser_policy_connector()->
386           GetDeviceCloudPolicyManager();
387    if (policy_manager)
388      policy_manager->core()->store()->RemoveObserver(this);
389  }
390
391  // Overridden from ash::SystemTrayDelegate:
392  virtual bool GetTrayVisibilityOnStartup() OVERRIDE {
393    // In case of OOBE / sign in screen tray will be shown later.
394    return LoginState::Get()->IsUserLoggedIn();
395  }
396
397  virtual ash::user::LoginStatus GetUserLoginStatus() const OVERRIDE {
398    // Map ChromeOS specific LOGGED_IN states to Ash LOGGED_IN states.
399    LoginState::LoggedInState state = LoginState::Get()->GetLoggedInState();
400    if (state == LoginState::LOGGED_IN_OOBE ||
401        state == LoginState::LOGGED_IN_NONE) {
402      return ash::user::LOGGED_IN_NONE;
403    }
404    if (screen_locked_)
405      return ash::user::LOGGED_IN_LOCKED;
406
407    LoginState::LoggedInUserType user_type =
408        LoginState::Get()->GetLoggedInUserType();
409    switch (user_type) {
410      case LoginState::LOGGED_IN_USER_NONE:
411        return ash::user::LOGGED_IN_NONE;
412      case LoginState::LOGGED_IN_USER_REGULAR:
413        return ash::user::LOGGED_IN_USER;
414      case LoginState::LOGGED_IN_USER_OWNER:
415        return ash::user::LOGGED_IN_OWNER;
416      case LoginState::LOGGED_IN_USER_GUEST:
417        return ash::user::LOGGED_IN_GUEST;
418      case LoginState::LOGGED_IN_USER_RETAIL_MODE:
419        return ash::user::LOGGED_IN_RETAIL_MODE;
420      case LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT:
421        return ash::user::LOGGED_IN_PUBLIC;
422      case LoginState::LOGGED_IN_USER_LOCALLY_MANAGED:
423        return ash::user::LOGGED_IN_LOCALLY_MANAGED;
424      case LoginState::LOGGED_IN_USER_KIOSK_APP:
425        return ash::user::LOGGED_IN_KIOSK_APP;
426    }
427    NOTREACHED();
428    return ash::user::LOGGED_IN_NONE;
429  }
430
431  virtual bool IsOobeCompleted() const OVERRIDE {
432    if (!base::chromeos::IsRunningOnChromeOS() &&
433        LoginState::Get()->GetLoggedInState() == LoginState::LOGGED_IN_ACTIVE)
434      return true;
435    return StartupUtils::IsOobeCompleted();
436  }
437
438  virtual void ChangeProfilePicture() OVERRIDE {
439    content::RecordAction(
440        content::UserMetricsAction("OpenChangeProfilePictureDialog"));
441    chrome::ShowSettingsSubPage(GetAppropriateBrowser(),
442                                chrome::kChangeProfilePictureSubPage);
443  }
444
445  virtual const std::string GetEnterpriseDomain() const OVERRIDE {
446    return enterprise_domain_;
447  }
448
449  virtual const string16 GetEnterpriseMessage() const OVERRIDE {
450    if (GetEnterpriseDomain().empty())
451        return string16();
452    return l10n_util::GetStringFUTF16(IDS_DEVICE_OWNED_BY_NOTICE,
453                                      UTF8ToUTF16(GetEnterpriseDomain()));
454  }
455
456  virtual const std::string GetLocallyManagedUserManager() const OVERRIDE {
457    if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
458      return std::string();
459    return UserManager::Get()->GetManagerDisplayEmailForManagedUser(
460        chromeos::UserManager::Get()->GetActiveUser()->email());
461  }
462
463  virtual const string16 GetLocallyManagedUserManagerName() const OVERRIDE {
464    if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
465      return string16();
466    return UserManager::Get()->GetManagerDisplayNameForManagedUser(
467        chromeos::UserManager::Get()->GetActiveUser()->email());
468  }
469
470  virtual const string16 GetLocallyManagedUserMessage() const OVERRIDE {
471    if (GetUserLoginStatus() != ash::user::LOGGED_IN_LOCALLY_MANAGED)
472        return string16();
473    return l10n_util::GetStringFUTF16(
474        IDS_USER_IS_LOCALLY_MANAGED_BY_NOTICE,
475        UTF8ToUTF16(GetLocallyManagedUserManager()));
476  }
477
478  virtual bool SystemShouldUpgrade() const OVERRIDE {
479    return UpgradeDetector::GetInstance()->notify_upgrade();
480  }
481
482  virtual base::HourClockType GetHourClockType() const OVERRIDE {
483    return clock_type_;
484  }
485
486  virtual void ShowSettings() OVERRIDE {
487    chrome::ShowSettings(GetAppropriateBrowser());
488  }
489
490  virtual bool ShouldShowSettings() OVERRIDE {
491    return UserManager::Get()->GetCurrentUserFlow()->ShouldShowSettings();
492  }
493
494  virtual void ShowDateSettings() OVERRIDE {
495    content::RecordAction(content::UserMetricsAction("ShowDateOptions"));
496    std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
497        l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
498    chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page);
499  }
500
501  virtual void ShowNetworkSettings(const std::string& service_path) OVERRIDE {
502    if (!LoginState::Get()->IsUserLoggedIn())
503      return;
504    network_connect::ShowNetworkSettings(service_path);
505  }
506
507  virtual void ShowBluetoothSettings() OVERRIDE {
508    // TODO(sad): Make this work.
509  }
510
511  virtual void ShowDisplaySettings() OVERRIDE {
512    content::RecordAction(content::UserMetricsAction("ShowDisplayOptions"));
513    chrome::ShowSettingsSubPage(GetAppropriateBrowser(),
514                                kDisplaySettingsSubPageName);
515  }
516
517  virtual void ShowChromeSlow() OVERRIDE {
518    chrome::ShowSlow(GetAppropriateBrowser());
519  }
520
521  virtual bool ShouldShowDisplayNotification() OVERRIDE {
522    // Packaged app is not counted as 'last active', so if a browser opening the
523    // display settings is in background of a packaged app, it will return true.
524    // TODO(mukai): fix this.
525    Browser* active_browser = chrome::FindLastActiveWithHostDesktopType(
526        chrome::HOST_DESKTOP_TYPE_ASH);
527    if (!active_browser)
528      return true;
529
530    content::WebContents* active_contents =
531        active_browser->tab_strip_model()->GetActiveWebContents();
532    if (!active_contents)
533      return true;
534
535    GURL visible_url = active_contents->GetLastCommittedURL();
536    std::string display_settings_url =
537        std::string(chrome::kChromeUISettingsURL) + kDisplaySettingsSubPageName;
538    std::string display_overscan_url =
539        std::string(chrome::kChromeUISettingsURL) +
540        kDisplayOverscanSettingsSubPageName;
541    return (visible_url.spec() != display_settings_url) &&
542        (visible_url.spec() != display_overscan_url);
543  }
544
545  virtual void ShowDriveSettings() OVERRIDE {
546    // TODO(hshi): Open the drive-specific settings page once we put it in.
547    // For now just show search result for downoads settings.
548    std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
549        l10n_util::GetStringUTF8(IDS_OPTIONS_DOWNLOADLOCATION_GROUP_NAME);
550    chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page);
551  }
552
553  virtual void ShowIMESettings() OVERRIDE {
554    content::RecordAction(
555        content::UserMetricsAction("OpenLanguageOptionsDialog"));
556    chrome::ShowSettingsSubPage(GetAppropriateBrowser(),
557                                chrome::kLanguageOptionsSubPage);
558  }
559
560  virtual void ShowHelp() OVERRIDE {
561    chrome::ShowHelp(GetAppropriateBrowser(), chrome::HELP_SOURCE_MENU);
562  }
563
564  virtual void ShowAccessibilityHelp() OVERRIDE {
565    accessibility::ShowAccessibilityHelp(GetAppropriateBrowser());
566  }
567
568  virtual void ShowAccessibilitySettings() OVERRIDE {
569    content::RecordAction(
570        content::UserMetricsAction("ShowAccessibilitySettings"));
571    std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
572        l10n_util::GetStringUTF8(
573            IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY);
574    chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page);
575  }
576
577  virtual void ShowPublicAccountInfo() OVERRIDE {
578    chrome::ShowPolicy(GetAppropriateBrowser());
579  }
580
581  virtual void ShowLocallyManagedUserInfo() OVERRIDE {
582    // TODO(antrim): find out what should we show in this case.
583    // http://crbug.com/229762
584  }
585
586  virtual void ShowEnterpriseInfo() OVERRIDE {
587    ash::user::LoginStatus status = GetUserLoginStatus();
588    if (status == ash::user::LOGGED_IN_NONE ||
589        status == ash::user::LOGGED_IN_LOCKED) {
590      scoped_refptr<chromeos::HelpAppLauncher> help_app(
591         new chromeos::HelpAppLauncher(GetNativeWindow()));
592      help_app->ShowHelpTopic(chromeos::HelpAppLauncher::HELP_ENTERPRISE);
593    } else {
594      GURL url(google_util::StringAppendGoogleLocaleParam(
595          chrome::kLearnMoreEnterpriseURL));
596      chrome::ShowSingletonTab(GetAppropriateBrowser(), url);
597    }
598  }
599
600  virtual void ShowUserLogin() OVERRIDE {
601    if (!ash::Shell::GetInstance()->delegate()->IsMultiProfilesEnabled())
602      return;
603
604    // Only regular users could add other users to current session.
605    if (UserManager::Get()->GetActiveUser()->GetType() !=
606            User::USER_TYPE_REGULAR) {
607      return;
608    }
609
610    // TODO(nkostylev): Show some UI messages why no more users could be added
611    // to this session. http://crbug.com/230863
612    // We limit list of logged in users to 3 due to memory constraints.
613    // TODO(nkostylev): Adjust this limitation based on device capabilites.
614    // http://crbug.com/230865
615    if (UserManager::Get()->GetLoggedInUsers().size() >= 3)
616      return;
617
618    // Launch sign in screen to add another user to current session.
619    if (UserManager::Get()->GetUsersAdmittedForMultiProfile().size())
620      UserAddingScreen::Get()->Start();
621  }
622
623  virtual void ShutDown() OVERRIDE {
624    ash::Shell::GetInstance()->lock_state_controller()->RequestShutdown();
625  }
626
627  virtual void SignOut() OVERRIDE {
628    chrome::AttemptUserExit();
629  }
630
631  virtual void RequestLockScreen() OVERRIDE {
632    // TODO(antrim) : additional logging for crbug/173178
633    LOG(WARNING) << "Requesting screen lock from AshSystemTrayDelegate";
634    DBusThreadManager::Get()->GetSessionManagerClient()->RequestLockScreen();
635  }
636
637  virtual void RequestRestartForUpdate() OVERRIDE {
638    // We expect that UpdateEngine is in "Reboot for update" state now.
639    chrome::NotifyAndTerminate(true /* fast path */);
640  }
641
642  virtual void GetAvailableBluetoothDevices(
643      ash::BluetoothDeviceList* list) OVERRIDE {
644    device::BluetoothAdapter::DeviceList devices =
645        bluetooth_adapter_->GetDevices();
646    for (size_t i = 0; i < devices.size(); ++i) {
647      device::BluetoothDevice* device = devices[i];
648      ash::BluetoothDeviceInfo info;
649      info.address = device->GetAddress();
650      info.display_name = device->GetName();
651      info.connected = device->IsConnected();
652      info.connecting = device->IsConnecting();
653      info.paired = device->IsPaired();
654      list->push_back(info);
655    }
656  }
657
658  virtual void BluetoothStartDiscovering() OVERRIDE {
659    bluetooth_adapter_->StartDiscovering(
660        base::Bind(&base::DoNothing),
661        base::Bind(&BluetoothSetDiscoveringError));
662  }
663
664  virtual void BluetoothStopDiscovering() OVERRIDE {
665    bluetooth_adapter_->StopDiscovering(
666        base::Bind(&base::DoNothing),
667        base::Bind(&BluetoothSetDiscoveringError));
668  }
669
670  virtual void ConnectToBluetoothDevice(const std::string& address) OVERRIDE {
671    device::BluetoothDevice* device = bluetooth_adapter_->GetDevice(address);
672    if (!device || device->IsConnecting() ||
673        (device->IsConnected() && device->IsPaired())) {
674      return;
675    }
676    if (device->IsPaired() && !device->IsConnectable())
677      return;
678    if (device->IsPaired() || !device->IsPairable()) {
679      device->Connect(
680          NULL,
681          base::Bind(&base::DoNothing),
682          base::Bind(&BluetoothDeviceConnectError));
683    } else {  // Show paring dialog for the unpaired device.
684      BluetoothPairingDialog* dialog =
685          new BluetoothPairingDialog(GetNativeWindow(), device);
686      // The dialog deletes itself on close.
687      dialog->Show();
688    }
689  }
690
691  virtual bool IsBluetoothDiscovering() OVERRIDE {
692    return bluetooth_adapter_->IsDiscovering();
693  }
694
695  virtual void GetCurrentIME(ash::IMEInfo* info) OVERRIDE {
696    input_method::InputMethodManager* manager =
697        input_method::InputMethodManager::Get();
698    input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
699    input_method::InputMethodDescriptor ime = manager->GetCurrentInputMethod();
700    ExtractIMEInfo(ime, *util, info);
701    info->selected = true;
702  }
703
704  virtual void GetAvailableIMEList(ash::IMEInfoList* list) OVERRIDE {
705    input_method::InputMethodManager* manager =
706        input_method::InputMethodManager::Get();
707    input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
708    scoped_ptr<input_method::InputMethodDescriptors> ime_descriptors(
709        manager->GetActiveInputMethods());
710    std::string current = manager->GetCurrentInputMethod().id();
711    for (size_t i = 0; i < ime_descriptors->size(); i++) {
712      input_method::InputMethodDescriptor& ime = ime_descriptors->at(i);
713      ash::IMEInfo info;
714      ExtractIMEInfo(ime, *util, &info);
715      info.selected = ime.id() == current;
716      list->push_back(info);
717    }
718  }
719
720  virtual void GetCurrentIMEProperties(
721      ash::IMEPropertyInfoList* list) OVERRIDE {
722    input_method::InputMethodManager* manager =
723        input_method::InputMethodManager::Get();
724    input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
725    input_method::InputMethodPropertyList properties =
726        manager->GetCurrentInputMethodProperties();
727    for (size_t i = 0; i < properties.size(); ++i) {
728      ash::IMEPropertyInfo property;
729      property.key = properties[i].key;
730      property.name = util->TranslateString(properties[i].label);
731      property.selected = properties[i].is_selection_item_checked;
732      list->push_back(property);
733    }
734  }
735
736  virtual void SwitchIME(const std::string& ime_id) OVERRIDE {
737    input_method::InputMethodManager::Get()->ChangeInputMethod(ime_id);
738  }
739
740  virtual void ActivateIMEProperty(const std::string& key) OVERRIDE {
741    input_method::InputMethodManager::Get()->
742        ActivateInputMethodProperty(key);
743  }
744
745  virtual void CancelDriveOperation(int32 operation_id) OVERRIDE {
746    DriveIntegrationService* integration_service =
747        FindDriveIntegrationService();
748    if (!integration_service)
749      return;
750
751    integration_service->job_list()->CancelJob(operation_id);
752  }
753
754  virtual void GetDriveOperationStatusList(
755      ash::DriveOperationStatusList* list) OVERRIDE {
756    DriveIntegrationService* integration_service =
757        FindDriveIntegrationService();
758    if (!integration_service)
759      return;
760
761    *list = ConvertToDriveStatusList(
762        integration_service->job_list()->GetJobInfoList());
763  }
764
765  virtual void ConfigureNetwork(const std::string& network_id) OVERRIDE {
766    network_connect::HandleUnconfiguredNetwork(network_id, GetNativeWindow());
767  }
768
769  virtual void EnrollOrConfigureNetwork(
770      const std::string& network_id,
771      gfx::NativeWindow parent_window) OVERRIDE {
772    if (network_connect::EnrollNetwork(network_id, parent_window))
773      return;
774    network_connect::HandleUnconfiguredNetwork(network_id, parent_window);
775  }
776
777  virtual void ManageBluetoothDevices() OVERRIDE {
778    content::RecordAction(
779        content::UserMetricsAction("ShowBluetoothSettingsPage"));
780    std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
781        l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH);
782    chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page);
783  }
784
785  virtual void ToggleBluetooth() OVERRIDE {
786    bluetooth_adapter_->SetPowered(!bluetooth_adapter_->IsPowered(),
787                                   base::Bind(&base::DoNothing),
788                                   base::Bind(&BluetoothPowerFailure));
789  }
790
791  virtual void ShowMobileSimDialog() OVERRIDE {
792    SimDialogDelegate::ShowDialog(GetNativeWindow(),
793                                  SimDialogDelegate::SIM_DIALOG_UNLOCK);
794  }
795
796  virtual void ShowMobileSetup(const std::string& network_id) OVERRIDE {
797    network_connect::ShowMobileSetup(network_id);
798  }
799
800  virtual void ShowOtherWifi() OVERRIDE {
801    NetworkConfigView::ShowForType(flimflam::kTypeWifi, GetNativeWindow());
802  }
803
804  virtual void ShowOtherVPN() OVERRIDE {
805    NetworkConfigView::ShowForType(flimflam::kTypeVPN, GetNativeWindow());
806  }
807
808  virtual void ShowOtherCellular() OVERRIDE {
809    ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow());
810  }
811
812  virtual bool GetBluetoothAvailable() OVERRIDE {
813    return bluetooth_adapter_->IsPresent();
814  }
815
816  virtual bool GetBluetoothEnabled() OVERRIDE {
817    return bluetooth_adapter_->IsPowered();
818  }
819
820  virtual bool GetCellularCarrierInfo(std::string* carrier_id,
821                                      std::string* topup_url,
822                                      std::string* setup_url) OVERRIDE {
823    bool result = false;
824    NetworkLibrary* crosnet = NetworkLibrary::Get();
825    const NetworkDevice* cellular = crosnet->FindCellularDevice();
826    if (!cellular)
827      return false;
828
829    MobileConfig* config = MobileConfig::GetInstance();
830    if (config->IsReady()) {
831      *carrier_id = crosnet->GetCellularHomeCarrierId();
832      const MobileConfig::Carrier* carrier = config->GetCarrier(*carrier_id);
833      if (carrier) {
834        *topup_url = carrier->top_up_url();
835        result = true;
836      }
837      const MobileConfig::LocaleConfig* locale_config =
838          config->GetLocaleConfig();
839      if (locale_config) {
840        // Only link to setup URL if SIM card is not inserted.
841        if (cellular->is_sim_absent()) {
842          *setup_url = locale_config->setup_url();
843          result = true;
844        }
845      }
846    }
847    return result;
848  }
849
850  virtual void ShowCellularURL(const std::string& url) OVERRIDE {
851    chrome::ShowSingletonTab(GetAppropriateBrowser(), GURL(url));
852  }
853
854  virtual void ChangeProxySettings() OVERRIDE {
855    CHECK(GetUserLoginStatus() == ash::user::LOGGED_IN_NONE);
856    LoginDisplayHostImpl::default_host()->OpenProxySettings();
857  }
858
859  virtual ash::VolumeControlDelegate*
860  GetVolumeControlDelegate() const OVERRIDE {
861    return volume_control_delegate_.get();
862  }
863
864  virtual void SetVolumeControlDelegate(
865      scoped_ptr<ash::VolumeControlDelegate> delegate) OVERRIDE {
866    volume_control_delegate_.swap(delegate);
867  }
868
869  virtual bool GetSessionStartTime(
870      base::TimeTicks* session_start_time) OVERRIDE {
871    *session_start_time = session_start_time_;
872    return have_session_start_time_;
873  }
874
875  virtual bool GetSessionLengthLimit(
876      base::TimeDelta* session_length_limit) OVERRIDE {
877    *session_length_limit = session_length_limit_;
878    return have_session_length_limit_;
879  }
880
881  virtual int GetSystemTrayMenuWidth() OVERRIDE {
882    return l10n_util::GetLocalizedContentsWidthInPixels(
883        IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
884  }
885
886  virtual string16 FormatTimeDuration(
887      const base::TimeDelta& delta) const OVERRIDE {
888    return ui::TimeFormat::TimeDurationLong(delta);
889  }
890
891  virtual void MaybeSpeak(const std::string& utterance) const OVERRIDE {
892    AccessibilityManager::Get()->MaybeSpeak(utterance);
893  }
894
895 private:
896  ash::SystemTray* GetPrimarySystemTray() {
897    return ash::Shell::GetInstance()->GetPrimarySystemTray();
898  }
899
900  ash::SystemTrayNotifier* GetSystemTrayNotifier() {
901    return ash::Shell::GetInstance()->system_tray_notifier();
902  }
903
904  // Returns the last active browser. If there is no such browser, creates a new
905  // browser window with an empty tab and returns it.
906  Browser* GetAppropriateBrowser() {
907    return chrome::FindOrCreateTabbedBrowser(
908        ProfileManager::GetDefaultProfileOrOffTheRecord(),
909        chrome::HOST_DESKTOP_TYPE_ASH);
910  }
911
912  void SetProfile(Profile* profile) {
913    // Stop observing the current |user_profile_| on Drive integration status.
914    UnobserveDriveUpdates();
915
916    user_profile_ = profile;
917
918    // Restart observation, now for the newly set |profile|.
919    ObserveDriveUpdates();
920
921    PrefService* prefs = profile->GetPrefs();
922    user_pref_registrar_.reset(new PrefChangeRegistrar);
923    user_pref_registrar_->Init(prefs);
924    user_pref_registrar_->Add(
925        prefs::kUse24HourClock,
926        base::Bind(&SystemTrayDelegate::UpdateClockType,
927                   base::Unretained(this)));
928    user_pref_registrar_->Add(
929        prefs::kLanguageRemapSearchKeyTo,
930        base::Bind(&SystemTrayDelegate::OnLanguageRemapSearchKeyToChanged,
931                   base::Unretained(this)));
932    user_pref_registrar_->Add(
933        prefs::kShowLogoutButtonInTray,
934        base::Bind(&SystemTrayDelegate::UpdateShowLogoutButtonInTray,
935                   base::Unretained(this)));
936    user_pref_registrar_->Add(
937        prefs::kLargeCursorEnabled,
938        base::Bind(&SystemTrayDelegate::OnAccessibilityModeChanged,
939                   base::Unretained(this),
940                   ash::A11Y_NOTIFICATION_NONE));
941    user_pref_registrar_->Add(
942        prefs::kShouldAlwaysShowAccessibilityMenu,
943        base::Bind(&SystemTrayDelegate::OnAccessibilityModeChanged,
944                   base::Unretained(this),
945                   ash::A11Y_NOTIFICATION_NONE));
946    user_pref_registrar_->Add(
947        prefs::kPerformanceTracingEnabled,
948        base::Bind(&SystemTrayDelegate::UpdatePerformanceTracing,
949                   base::Unretained(this)));
950
951    UpdateClockType();
952    UpdateShowLogoutButtonInTray();
953    UpdatePerformanceTracing();
954    search_key_mapped_to_ =
955        profile->GetPrefs()->GetInteger(prefs::kLanguageRemapSearchKeyTo);
956  }
957
958  bool UnsetProfile(Profile* profile) {
959    if (profile != user_profile_)
960      return false;
961    user_pref_registrar_.reset();
962    return true;
963  }
964
965  void ObserveDriveUpdates() {
966    DriveIntegrationService* integration_service =
967        FindDriveIntegrationService();
968    if (integration_service)
969      integration_service->job_list()->AddObserver(this);
970  }
971
972  void UnobserveDriveUpdates() {
973    DriveIntegrationService* integration_service =
974        FindDriveIntegrationService();
975    if (integration_service)
976      integration_service->job_list()->RemoveObserver(this);
977  }
978
979  bool ShouldUse24HourClock() const {
980    // On login screen and in guest mode owner default is used for
981    // kUse24HourClock preference.
982    // All other modes default to the default locale value.
983    const ash::user::LoginStatus status = GetUserLoginStatus();
984    const CrosSettings* const cros_settings = CrosSettings::Get();
985    bool system_use_24_hour_clock = true;
986    const bool system_value_found = cros_settings->GetBoolean(
987        kSystemUse24HourClock, &system_use_24_hour_clock);
988
989    if (status == ash::user::LOGGED_IN_NONE)
990      return (system_value_found
991                  ? system_use_24_hour_clock
992                  : (base::GetHourClockType() == base::k24HourClock));
993
994    const PrefService::Preference* user_pref =
995        user_pref_registrar_->prefs()->FindPreference(prefs::kUse24HourClock);
996    if (status == ash::user::LOGGED_IN_GUEST && user_pref->IsDefaultValue())
997      return (system_value_found
998                  ? system_use_24_hour_clock
999                  : (base::GetHourClockType() == base::k24HourClock));
1000
1001    bool use_24_hour_clock = true;
1002    user_pref->GetValue()->GetAsBoolean(&use_24_hour_clock);
1003    return use_24_hour_clock;
1004  }
1005
1006  void UpdateClockType() {
1007    if (!user_pref_registrar_)
1008      return;
1009
1010    const bool use_24_hour_clock = ShouldUse24HourClock();
1011    clock_type_ = use_24_hour_clock ? base::k24HourClock : base::k12HourClock;
1012    GetSystemTrayNotifier()->NotifyDateFormatChanged();
1013    // This also works for enterprise-managed devices because they never have
1014    // local owner.
1015    if (chromeos::UserManager::Get()->IsCurrentUserOwner())
1016      CrosSettings::Get()->SetBoolean(kSystemUse24HourClock, use_24_hour_clock);
1017  }
1018
1019  void UpdateShowLogoutButtonInTray() {
1020    GetSystemTrayNotifier()->NotifyShowLoginButtonChanged(
1021        user_pref_registrar_->prefs()->GetBoolean(
1022            prefs::kShowLogoutButtonInTray));
1023  }
1024
1025  void UpdateSessionStartTime() {
1026    const PrefService* local_state = local_state_registrar_->prefs();
1027    if (local_state->HasPrefPath(prefs::kSessionStartTime)) {
1028      have_session_start_time_ = true;
1029      session_start_time_ = base::TimeTicks::FromInternalValue(
1030          local_state->GetInt64(prefs::kSessionStartTime));
1031    } else {
1032      have_session_start_time_ = false;
1033      session_start_time_ = base::TimeTicks();
1034    }
1035    GetSystemTrayNotifier()->NotifySessionStartTimeChanged();
1036  }
1037
1038  void UpdateSessionLengthLimit() {
1039    const PrefService* local_state = local_state_registrar_->prefs();
1040    if (local_state->HasPrefPath(prefs::kSessionLengthLimit)) {
1041      have_session_length_limit_ = true;
1042      session_length_limit_ = base::TimeDelta::FromMilliseconds(
1043          std::min(std::max(local_state->GetInteger(prefs::kSessionLengthLimit),
1044                            kSessionLengthLimitMinMs),
1045                   kSessionLengthLimitMaxMs));
1046    } else {
1047      have_session_length_limit_ = false;
1048      session_length_limit_ = base::TimeDelta();
1049    }
1050    GetSystemTrayNotifier()->NotifySessionLengthLimitChanged();
1051  }
1052
1053  // LoginState::Observer overrides.
1054  virtual void LoggedInStateChanged(
1055      chromeos::LoginState::LoggedInState state) OVERRIDE {
1056    UpdateClockType();
1057  }
1058
1059  // Overridden from PowerManagerClient::Observer.
1060  virtual void BrightnessChanged(int level, bool user_initiated) OVERRIDE {
1061    double leveld = static_cast<double>(level);
1062    GetSystemTrayNotifier()->NotifyBrightnessChanged(leveld, user_initiated);
1063  }
1064
1065  // Overridden from PowerManagerClient::Observer:
1066  virtual void SystemResumed(const base::TimeDelta& sleep_duration) OVERRIDE {
1067    GetSystemTrayNotifier()->NotifyRefreshClock();
1068  }
1069
1070  // Overridden from SessionManagerClient::Observer.
1071  virtual void LockScreen() OVERRIDE {
1072    screen_locked_ = true;
1073    ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(
1074        GetUserLoginStatus());
1075  }
1076
1077  virtual void UnlockScreen() OVERRIDE {
1078    screen_locked_ = false;
1079    ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(
1080        GetUserLoginStatus());
1081  }
1082
1083  // TODO(sad): Override more from PowerManagerClient::Observer here.
1084
1085  gfx::NativeWindow GetNativeWindow() const {
1086    return GetNativeWindowByStatus(GetUserLoginStatus());
1087  }
1088
1089  // Overridden from NetworkLibrary::NetworkManagerObserver.
1090  virtual void OnNetworkManagerChanged(NetworkLibrary* crosnet) OVERRIDE {
1091    // TODO(stevenjb): Migrate to NetworkStateHandler.
1092    data_promo_notification_->ShowOptionalMobileDataPromoNotification(
1093        crosnet, GetPrimarySystemTray(), this);
1094    UpdateCellular();
1095  }
1096
1097  // content::NotificationObserver implementation.
1098  virtual void Observe(int type,
1099                       const content::NotificationSource& source,
1100                       const content::NotificationDetails& details) OVERRIDE {
1101    switch (type) {
1102      case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: {
1103        UpgradeDetector* detector =
1104            content::Source<UpgradeDetector>(source).ptr();
1105        ash::UpdateObserver::UpdateSeverity severity =
1106            ash::UpdateObserver::UPDATE_NORMAL;
1107        switch (detector->upgrade_notification_stage()) {
1108          case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
1109            severity = ash::UpdateObserver::UPDATE_SEVERE_RED;
1110            break;
1111
1112          case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
1113            severity = ash::UpdateObserver::UPDATE_HIGH_ORANGE;
1114            break;
1115
1116          case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
1117            severity = ash::UpdateObserver::UPDATE_LOW_GREEN;
1118            break;
1119
1120          case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
1121          default:
1122            severity = ash::UpdateObserver::UPDATE_NORMAL;
1123            break;
1124        }
1125        GetSystemTrayNotifier()->NotifyUpdateRecommended(severity);
1126        break;
1127      }
1128      case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
1129        // This notification is also sent on login screen when user avatar
1130        // is loaded from file.
1131        if (GetUserLoginStatus() != ash::user::LOGGED_IN_NONE) {
1132          GetSystemTrayNotifier()->NotifyUserUpdate();
1133        }
1134        break;
1135      }
1136      case chrome::NOTIFICATION_PROFILE_CREATED: {
1137        SetProfile(content::Source<Profile>(source).ptr());
1138        registrar_->Remove(this,
1139                           chrome::NOTIFICATION_PROFILE_CREATED,
1140                           content::NotificationService::AllSources());
1141        break;
1142      }
1143      case chrome::NOTIFICATION_PROFILE_DESTROYED: {
1144        if (UnsetProfile(content::Source<Profile>(source).ptr())) {
1145          registrar_->Remove(this,
1146                             chrome::NOTIFICATION_PROFILE_DESTROYED,
1147                             content::NotificationService::AllSources());
1148        }
1149        break;
1150      }
1151      case chrome::NOTIFICATION_SESSION_STARTED: {
1152        ash::Shell::GetInstance()->UpdateAfterLoginStatusChange(
1153            GetUserLoginStatus());
1154        SetProfile(ProfileManager::GetDefaultProfile());
1155        break;
1156      }
1157      case chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK:
1158      case chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE:
1159      case chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER: {
1160        AccessibilityStatusEventDetails* accessibility_status =
1161            content::Details<AccessibilityStatusEventDetails>(details).ptr();
1162        OnAccessibilityModeChanged(accessibility_status->notify);
1163        break;
1164      }
1165      default:
1166        NOTREACHED();
1167    }
1168  }
1169
1170  void OnLanguageRemapSearchKeyToChanged() {
1171    search_key_mapped_to_ = user_pref_registrar_->prefs()->GetInteger(
1172        prefs::kLanguageRemapSearchKeyTo);
1173  }
1174
1175  void OnAccessibilityModeChanged(
1176      ash::AccessibilityNotificationVisibility notify) {
1177    GetSystemTrayNotifier()->NotifyAccessibilityModeChanged(notify);
1178  }
1179
1180  void UpdatePerformanceTracing() {
1181    if (!user_pref_registrar_)
1182      return;
1183    bool value =
1184        user_pref_registrar_->prefs()->GetBoolean(
1185            prefs::kPerformanceTracingEnabled);
1186    GetSystemTrayNotifier()->NotifyTracingModeChanged(value);
1187  }
1188
1189  // Overridden from InputMethodManager::Observer.
1190  virtual void InputMethodChanged(
1191      input_method::InputMethodManager* manager, bool show_message) OVERRIDE {
1192    GetSystemTrayNotifier()->NotifyRefreshIME(show_message);
1193  }
1194
1195  virtual void InputMethodPropertyChanged(
1196      input_method::InputMethodManager* manager) OVERRIDE {
1197    GetSystemTrayNotifier()->NotifyRefreshIME(false);
1198  }
1199
1200  // drive::JobListObserver overrides.
1201  virtual void OnJobAdded(const drive::JobInfo& job_info) OVERRIDE {
1202    OnJobUpdated(job_info);
1203  }
1204
1205  virtual void OnJobDone(const drive::JobInfo& job_info,
1206                         drive::FileError error) OVERRIDE {
1207    ash::DriveOperationStatus status;
1208    if (ConvertToFinishedDriveOperationStatus(job_info, error, &status))
1209      GetSystemTrayNotifier()->NotifyDriveJobUpdated(status);
1210  }
1211
1212  virtual void OnJobUpdated(const drive::JobInfo& job_info) OVERRIDE {
1213    ash::DriveOperationStatus status;
1214    if (ConvertToDriveOperationStatus(job_info, &status))
1215      GetSystemTrayNotifier()->NotifyDriveJobUpdated(status);
1216  }
1217
1218  DriveIntegrationService* FindDriveIntegrationService() {
1219    return user_profile_ ?
1220        DriveIntegrationServiceFactory::FindForProfile(user_profile_) : NULL;
1221  }
1222
1223  // Overridden from system::TimezoneSettings::Observer.
1224  virtual void TimezoneChanged(const icu::TimeZone& timezone) OVERRIDE {
1225    GetSystemTrayNotifier()->NotifyRefreshClock();
1226  }
1227
1228  // Overridden from SystemClockClient::Observer.
1229  virtual void SystemClockUpdated() OVERRIDE {
1230    GetSystemTrayNotifier()->NotifySystemClockTimeUpdated();
1231  }
1232
1233  // Overridden from BluetoothAdapter::Observer.
1234  virtual void AdapterPresentChanged(device::BluetoothAdapter* adapter,
1235                                     bool present) OVERRIDE {
1236    GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1237  }
1238
1239  virtual void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
1240                                     bool powered) OVERRIDE {
1241    GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1242  }
1243
1244  virtual void AdapterDiscoveringChanged(device::BluetoothAdapter* adapter,
1245                                         bool discovering) OVERRIDE {
1246    GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
1247  }
1248
1249  virtual void DeviceAdded(device::BluetoothAdapter* adapter,
1250                           device::BluetoothDevice* device) OVERRIDE {
1251    GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1252  }
1253
1254  virtual void DeviceChanged(device::BluetoothAdapter* adapter,
1255                             device::BluetoothDevice* device) OVERRIDE {
1256    GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1257  }
1258
1259  virtual void DeviceRemoved(device::BluetoothAdapter* adapter,
1260                             device::BluetoothDevice* device) OVERRIDE {
1261    GetSystemTrayNotifier()->NotifyRefreshBluetooth();
1262  }
1263
1264  // Overridden from SystemKeyEventListener::CapsLockObserver.
1265  virtual void OnCapsLockChange(bool enabled) OVERRIDE {
1266    bool search_mapped_to_caps_lock = false;
1267    if (!base::chromeos::IsRunningOnChromeOS() ||
1268        search_key_mapped_to_ == input_method::kCapsLockKey)
1269      search_mapped_to_caps_lock = true;
1270    GetSystemTrayNotifier()->NotifyCapsLockChanged(
1271        enabled, search_mapped_to_caps_lock);
1272  }
1273
1274  // Overridden from ash::NetworkTrayDelegate
1275  virtual void NotificationLinkClicked(
1276      ash::NetworkObserver::MessageType message_type,
1277      size_t link_index) OVERRIDE {
1278    if (message_type == ash::NetworkObserver::ERROR_OUT_OF_CREDITS) {
1279      const NetworkState* cellular =
1280          NetworkHandler::Get()->network_state_handler()->
1281          FirstNetworkByType(flimflam::kTypeCellular);
1282      std::string service_path = cellular ? cellular->path() : "";
1283      ShowNetworkSettings(service_path);
1284
1285      ash::Shell::GetInstance()->system_tray_notifier()->
1286          NotifyClearNetworkMessage(message_type);
1287    }
1288    if (message_type != ash::NetworkObserver::MESSAGE_DATA_PROMO)
1289      return;
1290    // If we have deal info URL defined that means that there're
1291    // 2 links in bubble. Let the user close it manually then thus giving
1292    // ability to navigate to second link.
1293    // mobile_data_bubble_ will be set to NULL in BubbleClosing callback.
1294    std::string deal_info_url = data_promo_notification_->deal_info_url();
1295    std::string deal_topup_url = data_promo_notification_->deal_topup_url();
1296    if (deal_info_url.empty())
1297      data_promo_notification_->CloseNotification();
1298
1299    std::string deal_url_to_open;
1300    if (link_index == 0) {
1301      if (!deal_topup_url.empty()) {
1302        deal_url_to_open = deal_topup_url;
1303      } else {
1304        const Network* cellular =
1305            NetworkLibrary::Get()->cellular_network();
1306        if (!cellular)
1307          return;
1308        ShowNetworkSettings(cellular->service_path());
1309        return;
1310      }
1311    } else if (link_index == 1) {
1312      deal_url_to_open = deal_info_url;
1313    }
1314
1315    if (!deal_url_to_open.empty()) {
1316      Browser* browser = GetAppropriateBrowser();
1317      if (!browser)
1318        return;
1319      chrome::ShowSingletonTab(browser, GURL(deal_url_to_open));
1320    }
1321  }
1322
1323  virtual void UpdateEnterpriseDomain() {
1324    std::string enterprise_domain =
1325        g_browser_process->browser_policy_connector()->GetEnterpriseDomain();
1326    if (enterprise_domain_ != enterprise_domain) {
1327       enterprise_domain_ = enterprise_domain;
1328       GetSystemTrayNotifier()->NotifyEnterpriseDomainChanged();
1329    }
1330  }
1331
1332  // Overridden from CloudPolicyStore::Observer
1333  virtual void OnStoreLoaded(policy::CloudPolicyStore* store) OVERRIDE {
1334    UpdateEnterpriseDomain();
1335  }
1336
1337  virtual void OnStoreError(policy::CloudPolicyStore* store) OVERRIDE {
1338    UpdateEnterpriseDomain();
1339  }
1340
1341  // Overridden from ash::SessionStateObserver
1342  virtual void ActiveUserChanged(const std::string& user_id) OVERRIDE {
1343    GetSystemTrayNotifier()->NotifyUserUpdate();
1344  }
1345
1346  void UpdateCellular() {
1347    const CellularNetworkVector& cellular_networks =
1348        NetworkLibrary::Get()->cellular_networks();
1349    if (cellular_networks.empty())
1350      return;
1351    // We only care about the first cellular network (in practice there will
1352    // only ever be one)
1353    const CellularNetwork* cellular = cellular_networks[0];
1354    if (cellular->activation_state() == ACTIVATION_STATE_ACTIVATING) {
1355      cellular_activating_ = true;
1356    } else if (cellular->activated() && cellular_activating_) {
1357      cellular_activating_ = false;
1358      ash::NetworkObserver::NetworkType type = NetworkTypeForCellular(cellular);
1359      ash::Shell::GetInstance()->system_tray_notifier()->
1360          NotifySetNetworkMessage(
1361              NULL,
1362              ash::NetworkObserver::MESSAGE_DATA_PROMO,
1363              type,
1364              l10n_util::GetStringUTF16(IDS_NETWORK_CELLULAR_ACTIVATED_TITLE),
1365              l10n_util::GetStringFUTF16(IDS_NETWORK_CELLULAR_ACTIVATED,
1366                                         UTF8ToUTF16((cellular->name()))),
1367              std::vector<string16>());
1368    }
1369  }
1370
1371  scoped_ptr<base::WeakPtrFactory<SystemTrayDelegate> > ui_weak_ptr_factory_;
1372  scoped_ptr<content::NotificationRegistrar> registrar_;
1373  scoped_ptr<PrefChangeRegistrar> local_state_registrar_;
1374  scoped_ptr<PrefChangeRegistrar> user_pref_registrar_;
1375  Profile* user_profile_;
1376  std::string active_network_path_;
1377  base::HourClockType clock_type_;
1378  int search_key_mapped_to_;
1379  bool screen_locked_;
1380  bool have_session_start_time_;
1381  base::TimeTicks session_start_time_;
1382  bool have_session_length_limit_;
1383  base::TimeDelta session_length_limit_;
1384  std::string enterprise_domain_;
1385
1386  scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
1387
1388  scoped_ptr<DataPromoNotification> data_promo_notification_;
1389  bool cellular_activating_;
1390  bool cellular_out_of_credits_;
1391
1392  scoped_ptr<ash::VolumeControlDelegate> volume_control_delegate_;
1393
1394  DISALLOW_COPY_AND_ASSIGN(SystemTrayDelegate);
1395};
1396
1397}  // namespace
1398
1399ash::SystemTrayDelegate* CreateSystemTrayDelegate() {
1400  return new chromeos::SystemTrayDelegate();
1401}
1402
1403}  // namespace chromeos
1404