| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "chrome/browser/chromeos/system/ash_system_tray_delegate.h" | 
 |  | 
 | #include "ash/shell.h" | 
 | #include "ash/shell_window_ids.h" | 
 | #include "ash/system/audio/audio_observer.h" | 
 | #include "ash/system/bluetooth/bluetooth_observer.h" | 
 | #include "ash/system/brightness/brightness_observer.h" | 
 | #include "ash/system/date/clock_observer.h" | 
 | #include "ash/system/drive/drive_observer.h" | 
 | #include "ash/system/ime/ime_observer.h" | 
 | #include "ash/system/network/network_observer.h" | 
 | #include "ash/system/power/power_status_observer.h" | 
 | #include "ash/system/status_area_widget.h" | 
 | #include "ash/system/tray/system_tray.h" | 
 | #include "ash/system/tray/system_tray_delegate.h" | 
 | #include "ash/system/tray_accessibility.h" | 
 | #include "ash/system/tray_caps_lock.h" | 
 | #include "ash/system/user/update_observer.h" | 
 | #include "ash/system/user/user_observer.h" | 
 | #include "ash/volume_control_delegate.h" | 
 | #include "base/bind_helpers.h" | 
 | #include "base/callback.h" | 
 | #include "base/chromeos/chromeos_version.h" | 
 | #include "base/logging.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "base/utf_string_conversions.h" | 
 | #include "chrome/browser/browser_process.h" | 
 | #include "chrome/browser/chromeos/accessibility/accessibility_util.h" | 
 | #include "chrome/browser/chromeos/audio/audio_handler.h" | 
 | #include "chrome/browser/chromeos/bluetooth/bluetooth_adapter.h" | 
 | #include "chrome/browser/chromeos/bluetooth/bluetooth_device.h" | 
 | #include "chrome/browser/chromeos/cros/cros_library.h" | 
 | #include "chrome/browser/chromeos/cros/network_library.h" | 
 | #include "chrome/browser/chromeos/gdata/drive_service_interface.h" | 
 | #include "chrome/browser/chromeos/gdata/drive_system_service.h" | 
 | #include "chrome/browser/chromeos/input_method/input_method_manager.h" | 
 | #include "chrome/browser/chromeos/input_method/input_method_util.h" | 
 | #include "chrome/browser/chromeos/input_method/xkeyboard.h" | 
 | #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" | 
 | #include "chrome/browser/chromeos/login/base_login_display_host.h" | 
 | #include "chrome/browser/chromeos/login/login_display_host.h" | 
 | #include "chrome/browser/chromeos/login/message_bubble.h" | 
 | #include "chrome/browser/chromeos/login/user.h" | 
 | #include "chrome/browser/chromeos/login/user_manager.h" | 
 | #include "chrome/browser/chromeos/mobile_config.h" | 
 | #include "chrome/browser/chromeos/status/data_promo_notification.h" | 
 | #include "chrome/browser/chromeos/status/network_menu.h" | 
 | #include "chrome/browser/chromeos/status/network_menu_icon.h" | 
 | #include "chrome/browser/chromeos/system/timezone_settings.h" | 
 | #include "chrome/browser/chromeos/system_key_event_listener.h" | 
 | #include "chrome/browser/google_apis/gdata_util.h" | 
 | #include "chrome/browser/lifetime/application_lifetime.h" | 
 | #include "chrome/browser/prefs/pref_service.h" | 
 | #include "chrome/browser/profiles/profile_manager.h" | 
 | #include "chrome/browser/ui/ash/volume_controller_chromeos.h" | 
 | #include "chrome/browser/ui/browser.h" | 
 | #include "chrome/browser/ui/browser_finder.h" | 
 | #include "chrome/browser/ui/chrome_pages.h" | 
 | #include "chrome/browser/ui/singleton_tabs.h" | 
 | #include "chrome/browser/upgrade_detector.h" | 
 | #include "chrome/common/chrome_notification_types.h" | 
 | #include "chrome/common/pref_names.h" | 
 | #include "chrome/common/url_constants.h" | 
 | #include "chromeos/dbus/dbus_thread_manager.h" | 
 | #include "chromeos/dbus/power_manager_client.h" | 
 | #include "chromeos/dbus/session_manager_client.h" | 
 | #include "content/public/browser/browser_thread.h" | 
 | #include "content/public/browser/notification_observer.h" | 
 | #include "content/public/browser/notification_service.h" | 
 | #include "content/public/browser/user_metrics.h" | 
 | #include "grit/generated_resources.h" | 
 | #include "ui/base/l10n/l10n_util.h" | 
 |  | 
 | using gdata::DriveSystemService; | 
 | using gdata::DriveSystemServiceFactory; | 
 |  | 
 | namespace chromeos { | 
 |  | 
 | namespace { | 
 |  | 
 | // Time delay for rechecking gdata operation when we suspect that there will | 
 | // be no upcoming activity notifications that need to be pushed to UI. | 
 | const int kGDataOperationRecheckDelayMs = 5000; | 
 |  | 
 | ash::NetworkIconInfo CreateNetworkIconInfo(const Network* network, | 
 |                                            NetworkMenu* network_menu) { | 
 |   ash::NetworkIconInfo info; | 
 |   info.name = UTF8ToUTF16(network->name()); | 
 |   info.image = NetworkMenuIcon::GetImage(network, NetworkMenuIcon::COLOR_DARK); | 
 |   info.service_path = network->service_path(); | 
 |   info.highlight = network->connected() || network->connecting(); | 
 |   return info; | 
 | } | 
 |  | 
 | void ExtractIMEInfo(const input_method::InputMethodDescriptor& ime, | 
 |                     const input_method::InputMethodUtil& util, | 
 |                     ash::IMEInfo* info) { | 
 |   info->id = ime.id(); | 
 |   info->name = util.GetInputMethodLongName(ime); | 
 |   info->medium_name = util.GetInputMethodMediumName(ime); | 
 |   info->short_name = util.GetInputMethodShortName(ime); | 
 |   info->third_party = ime.third_party(); | 
 | } | 
 |  | 
 | ash::DriveOperationStatusList GetDriveStatusList( | 
 |     const gdata::OperationProgressStatusList& list) { | 
 |   ash::DriveOperationStatusList results; | 
 |   for (gdata::OperationProgressStatusList::const_iterator it = list.begin(); | 
 |        it != list.end(); ++it) { | 
 |     ash::DriveOperationStatus status; | 
 |     status.file_path = it->file_path; | 
 |     status.progress = it->progress_total == 0 ? 0.0 : | 
 |         static_cast<double>(it->progress_current) / | 
 |             static_cast<double>(it->progress_total); | 
 |     status.type = static_cast<ash::DriveOperationStatus::OperationType>( | 
 |         it->operation_type); | 
 |     status.state = static_cast<ash::DriveOperationStatus::OperationState>( | 
 |         it->transfer_state); | 
 |     results.push_back(status); | 
 |   } | 
 |   return results; | 
 | } | 
 |  | 
 | void BluetoothPowerFailure() { | 
 |   // TODO(sad): Show an error bubble? | 
 | } | 
 |  | 
 | void BluetoothDiscoveryFailure() { | 
 |   // TODO(sad): Show an error bubble? | 
 | } | 
 |  | 
 | void BluetoothDeviceDisconnectError() { | 
 |   // TODO(sad): Do something? | 
 | } | 
 |  | 
 | void BluetoothDeviceConnectError() { | 
 |   // TODO(sad): Do something? | 
 | } | 
 |  | 
 | class SystemTrayDelegate : public ash::SystemTrayDelegate, | 
 |                            public AudioHandler::VolumeObserver, | 
 |                            public PowerManagerClient::Observer, | 
 |                            public SessionManagerClient::Observer, | 
 |                            public NetworkMenuIcon::Delegate, | 
 |                            public NetworkMenu::Delegate, | 
 |                            public NetworkLibrary::NetworkManagerObserver, | 
 |                            public NetworkLibrary::NetworkObserver, | 
 |                            public NetworkLibrary::CellularDataPlanObserver, | 
 |                            public gdata::DriveServiceObserver, | 
 |                            public content::NotificationObserver, | 
 |                            public input_method::InputMethodManager::Observer, | 
 |                            public system::TimezoneSettings::Observer, | 
 |                            public BluetoothAdapter::Observer, | 
 |                            public SystemKeyEventListener::CapsLockObserver, | 
 |                            public ash::NetworkTrayDelegate { | 
 |  public: | 
 |   explicit SystemTrayDelegate(ash::SystemTray* tray) | 
 |       : tray_(tray), | 
 |         ui_weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST( | 
 |             new base::WeakPtrFactory<SystemTrayDelegate>(this))), | 
 |         network_icon_(ALLOW_THIS_IN_INITIALIZER_LIST( | 
 |                       new NetworkMenuIcon(this, NetworkMenuIcon::MENU_MODE))), | 
 |         network_icon_dark_(ALLOW_THIS_IN_INITIALIZER_LIST( | 
 |                       new NetworkMenuIcon(this, NetworkMenuIcon::MENU_MODE))), | 
 |         network_menu_(ALLOW_THIS_IN_INITIALIZER_LIST(new NetworkMenu(this))), | 
 |         clock_type_(base::k24HourClock), | 
 |         search_key_mapped_to_(input_method::kSearchKey), | 
 |         screen_locked_(false), | 
 |         connected_network_state_(STATE_UNKNOWN), | 
 |         data_promo_notification_(new DataPromoNotification()), | 
 |         volume_control_delegate_(ALLOW_THIS_IN_INITIALIZER_LIST( | 
 |             new VolumeController)) { | 
 |     AudioHandler::GetInstance()->AddVolumeObserver(this); | 
 |     DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); | 
 |     DBusThreadManager::Get()->GetPowerManagerClient()->RequestStatusUpdate( | 
 |         PowerManagerClient::UPDATE_INITIAL); | 
 |     DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); | 
 |  | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     crosnet->AddNetworkManagerObserver(this); | 
 |     OnNetworkManagerChanged(crosnet); | 
 |     crosnet->AddCellularDataPlanObserver(this); | 
 |  | 
 |     input_method::InputMethodManager::GetInstance()->AddObserver(this); | 
 |  | 
 |     system::TimezoneSettings::GetInstance()->AddObserver(this); | 
 |  | 
 |     if (SystemKeyEventListener::GetInstance()) | 
 |       SystemKeyEventListener::GetInstance()->AddCapsLockObserver(this); | 
 |  | 
 |     registrar_.Add(this, | 
 |                    chrome::NOTIFICATION_UPGRADE_RECOMMENDED, | 
 |                    content::NotificationService::AllSources()); | 
 |     registrar_.Add(this, | 
 |                    chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED, | 
 |                    content::NotificationService::AllSources()); | 
 |     if (GetUserLoginStatus() == ash::user::LOGGED_IN_NONE) { | 
 |       registrar_.Add(this, | 
 |                      chrome::NOTIFICATION_SESSION_STARTED, | 
 |                      content::NotificationService::AllSources()); | 
 |     } | 
 |     registrar_.Add(this, | 
 |                    chrome::NOTIFICATION_PROFILE_CREATED, | 
 |                    content::NotificationService::AllSources()); | 
 |     registrar_.Add(this, | 
 |                    chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, | 
 |                    content::NotificationService::AllSources()); | 
 |  | 
 |     accessibility_enabled_.Init(prefs::kSpokenFeedbackEnabled, | 
 |                                 g_browser_process->local_state(), this); | 
 |  | 
 |     network_icon_->SetResourceColorTheme(NetworkMenuIcon::COLOR_LIGHT); | 
 |     network_icon_dark_->SetResourceColorTheme(NetworkMenuIcon::COLOR_DARK); | 
 |  | 
 |     bluetooth_adapter_ = BluetoothAdapter::DefaultAdapter(); | 
 |     bluetooth_adapter_->AddObserver(this); | 
 |   } | 
 |  | 
 |   virtual ~SystemTrayDelegate() { | 
 |     AudioHandler* audiohandler = AudioHandler::GetInstance(); | 
 |     if (audiohandler) | 
 |       audiohandler->RemoveVolumeObserver(this); | 
 |     DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this); | 
 |     DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     if (crosnet) { | 
 |       crosnet->RemoveNetworkManagerObserver(this); | 
 |       crosnet->RemoveCellularDataPlanObserver(this); | 
 |     } | 
 |     input_method::InputMethodManager::GetInstance()->RemoveObserver(this); | 
 |     system::TimezoneSettings::GetInstance()->RemoveObserver(this); | 
 |     if (SystemKeyEventListener::GetInstance()) | 
 |       SystemKeyEventListener::GetInstance()->RemoveCapsLockObserver(this); | 
 |     bluetooth_adapter_->RemoveObserver(this); | 
 |  | 
 |     // Stop observing gdata operations. | 
 |     DriveSystemService* system_service = FindDriveSystemService(); | 
 |     if (system_service) { | 
 |       system_service->drive_service()->RemoveObserver(this); | 
 |     } | 
 |   } | 
 |  | 
 |   // Overridden from ash::SystemTrayDelegate: | 
 |   virtual bool GetTrayVisibilityOnStartup() OVERRIDE { | 
 |     // In case of OOBE / sign in screen tray will be shown later. | 
 |     return UserManager::Get()->IsUserLoggedIn(); | 
 |   } | 
 |  | 
 |   virtual const string16 GetUserDisplayName() const OVERRIDE { | 
 |     return UserManager::Get()->GetLoggedInUser().GetDisplayName(); | 
 |   } | 
 |  | 
 |   virtual const std::string GetUserEmail() const OVERRIDE { | 
 |     return UserManager::Get()->GetLoggedInUser().display_email(); | 
 |   } | 
 |  | 
 |   virtual const gfx::ImageSkia& GetUserImage() const OVERRIDE { | 
 |     return UserManager::Get()->GetLoggedInUser().image(); | 
 |   } | 
 |  | 
 |   virtual ash::user::LoginStatus GetUserLoginStatus() const OVERRIDE { | 
 |     UserManager* manager = UserManager::Get(); | 
 |     // At new user image screen manager->IsUserLoggedIn() would return true | 
 |     // but there's no browser session available yet so use SessionStarted(). | 
 |     if (!manager->IsSessionStarted()) | 
 |       return ash::user::LOGGED_IN_NONE; | 
 |     if (screen_locked_) | 
 |       return ash::user::LOGGED_IN_LOCKED; | 
 |     if (manager->IsCurrentUserOwner()) | 
 |       return ash::user::LOGGED_IN_OWNER; | 
 |     if (manager->IsLoggedInAsGuest()) | 
 |       return ash::user::LOGGED_IN_GUEST; | 
 |     if (manager->IsLoggedInAsDemoUser()) | 
 |       return ash::user::LOGGED_IN_KIOSK; | 
 |     return ash::user::LOGGED_IN_USER; | 
 |   } | 
 |  | 
 |   virtual bool SystemShouldUpgrade() const OVERRIDE { | 
 |     return UpgradeDetector::GetInstance()->notify_upgrade(); | 
 |   } | 
 |  | 
 |   virtual base::HourClockType GetHourClockType() const OVERRIDE { | 
 |     return clock_type_; | 
 |   } | 
 |  | 
 |   virtual PowerSupplyStatus GetPowerSupplyStatus() const OVERRIDE { | 
 |     return power_supply_status_; | 
 |   } | 
 |  | 
 |   virtual void RequestStatusUpdate() const OVERRIDE { | 
 |     DBusThreadManager::Get()->GetPowerManagerClient()->RequestStatusUpdate( | 
 |         PowerManagerClient::UPDATE_USER); | 
 |   } | 
 |  | 
 |   virtual void ShowSettings() OVERRIDE { | 
 |     chrome::ShowSettings(GetAppropriateBrowser()); | 
 |   } | 
 |  | 
 |   virtual void ShowDateSettings() OVERRIDE { | 
 |     content::RecordAction(content::UserMetricsAction("ShowDateOptions")); | 
 |     std::string sub_page = std::string(chrome::kSearchSubPage) + "#" + | 
 |         l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME); | 
 |     chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page); | 
 |   } | 
 |  | 
 |   virtual void ShowNetworkSettings() OVERRIDE { | 
 |     content::RecordAction( | 
 |         content::UserMetricsAction("OpenInternetOptionsDialog")); | 
 |     chrome::ShowSettingsSubPage(GetAppropriateBrowser(), | 
 |                                 chrome::kInternetOptionsSubPage); | 
 |   } | 
 |  | 
 |   virtual void ShowBluetoothSettings() OVERRIDE { | 
 |     // TODO(sad): Make this work. | 
 |   } | 
 |  | 
 |   virtual void ShowDisplaySettings() OVERRIDE { | 
 |     content::RecordAction(content::UserMetricsAction("ShowDisplayOptions")); | 
 |     chrome::ShowSettingsSubPage(GetAppropriateBrowser(), "display"); | 
 |   } | 
 |  | 
 |   virtual void ShowDriveSettings() OVERRIDE { | 
 |     // TODO(hshi): Open the drive-specific settings page once we put it in. | 
 |     // For now just show search result for downoads settings. | 
 |     std::string sub_page = std::string(chrome::kSearchSubPage) + "#" + | 
 |         l10n_util::GetStringUTF8(IDS_OPTIONS_DOWNLOADLOCATION_GROUP_NAME); | 
 |     chrome::ShowSettingsSubPage(GetAppropriateBrowser(), sub_page); | 
 |   } | 
 |  | 
 |   virtual void ShowIMESettings() OVERRIDE { | 
 |     content::RecordAction( | 
 |         content::UserMetricsAction("OpenLanguageOptionsDialog")); | 
 |     chrome::ShowSettingsSubPage(GetAppropriateBrowser(), | 
 |                                 chrome::kLanguageOptionsSubPage); | 
 |   } | 
 |  | 
 |   virtual void ShowHelp() OVERRIDE { | 
 |     chrome::ShowHelp(GetAppropriateBrowser(), chrome::HELP_SOURCE_MENU); | 
 |   } | 
 |  | 
 |   virtual void ShutDown() OVERRIDE { | 
 |     DBusThreadManager::Get()->GetPowerManagerClient()->RequestShutdown(); | 
 |     if (!base::chromeos::IsRunningOnChromeOS()) | 
 |       browser::AttemptUserExit(); | 
 |   } | 
 |  | 
 |   virtual void SignOut() OVERRIDE { | 
 |     browser::AttemptUserExit(); | 
 |   } | 
 |  | 
 |   virtual void RequestLockScreen() OVERRIDE { | 
 |     DBusThreadManager::Get()->GetSessionManagerClient()->RequestLockScreen(); | 
 |   } | 
 |  | 
 |   virtual void RequestRestart() OVERRIDE { | 
 |     DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); | 
 |   } | 
 |  | 
 |   virtual void GetAvailableBluetoothDevices( | 
 |       ash::BluetoothDeviceList* list) OVERRIDE { | 
 |     BluetoothAdapter::DeviceList devices = bluetooth_adapter_->GetDevices(); | 
 |     for (size_t i = 0; i < devices.size(); ++i) { | 
 |       BluetoothDevice* device = devices[i]; | 
 |       if (!device->IsPaired()) | 
 |         continue; | 
 |       ash::BluetoothDeviceInfo info; | 
 |       info.address = device->address(); | 
 |       info.display_name = device->GetName(); | 
 |       info.connected = device->IsConnected(); | 
 |       list->push_back(info); | 
 |     } | 
 |   } | 
 |  | 
 |   virtual void ToggleBluetoothConnection(const std::string& address) OVERRIDE { | 
 |     BluetoothDevice* device = bluetooth_adapter_->GetDevice(address); | 
 |     if (!device) | 
 |       return; | 
 |     if (device->IsConnected()) { | 
 |       device->Disconnect( | 
 |           base::Bind(&base::DoNothing), | 
 |           base::Bind(&BluetoothDeviceDisconnectError)); | 
 |     } else if (device->IsPaired()) { | 
 |       device->Connect( | 
 |           NULL, | 
 |           base::Bind(&base::DoNothing), | 
 |           base::Bind(&BluetoothDeviceConnectError)); | 
 |     } | 
 |   } | 
 |  | 
 |   virtual void GetCurrentIME(ash::IMEInfo* info) OVERRIDE { | 
 |     input_method::InputMethodManager* manager = | 
 |         input_method::InputMethodManager::GetInstance(); | 
 |     input_method::InputMethodUtil* util = manager->GetInputMethodUtil(); | 
 |     input_method::InputMethodDescriptor ime = manager->GetCurrentInputMethod(); | 
 |     ExtractIMEInfo(ime, *util, info); | 
 |     info->selected = true; | 
 |   } | 
 |  | 
 |   virtual void GetAvailableIMEList(ash::IMEInfoList* list) OVERRIDE { | 
 |     input_method::InputMethodManager* manager = | 
 |         input_method::InputMethodManager::GetInstance(); | 
 |     input_method::InputMethodUtil* util = manager->GetInputMethodUtil(); | 
 |     scoped_ptr<input_method::InputMethodDescriptors> ime_descriptors( | 
 |         manager->GetActiveInputMethods()); | 
 |     std::string current = manager->GetCurrentInputMethod().id(); | 
 |     for (size_t i = 0; i < ime_descriptors->size(); i++) { | 
 |       input_method::InputMethodDescriptor& ime = ime_descriptors->at(i); | 
 |       ash::IMEInfo info; | 
 |       ExtractIMEInfo(ime, *util, &info); | 
 |       info.selected = ime.id() == current; | 
 |       list->push_back(info); | 
 |     } | 
 |   } | 
 |  | 
 |   virtual void GetCurrentIMEProperties( | 
 |       ash::IMEPropertyInfoList* list) OVERRIDE { | 
 |     input_method::InputMethodManager* manager = | 
 |         input_method::InputMethodManager::GetInstance(); | 
 |     input_method::InputMethodUtil* util = manager->GetInputMethodUtil(); | 
 |     input_method::InputMethodPropertyList properties = | 
 |         manager->GetCurrentInputMethodProperties(); | 
 |     for (size_t i = 0; i < properties.size(); ++i) { | 
 |       ash::IMEPropertyInfo property; | 
 |       property.key = properties[i].key; | 
 |       property.name = util->TranslateString(properties[i].label); | 
 |       property.selected = properties[i].is_selection_item_checked; | 
 |       list->push_back(property); | 
 |     } | 
 |   } | 
 |  | 
 |   virtual void SwitchIME(const std::string& ime_id) OVERRIDE { | 
 |     input_method::InputMethodManager::GetInstance()->ChangeInputMethod(ime_id); | 
 |   } | 
 |  | 
 |   virtual void ActivateIMEProperty(const std::string& key) OVERRIDE { | 
 |     input_method::InputMethodManager::GetInstance()-> | 
 |         ActivateInputMethodProperty(key); | 
 |   } | 
 |  | 
 |   virtual void CancelDriveOperation(const FilePath& file_path) OVERRIDE { | 
 |     DriveSystemService* system_service = FindDriveSystemService(); | 
 |     if (!system_service) | 
 |       return; | 
 |  | 
 |     system_service->drive_service()->CancelForFilePath(file_path); | 
 |   } | 
 |  | 
 |   virtual void GetDriveOperationStatusList( | 
 |       ash::DriveOperationStatusList* list) OVERRIDE { | 
 |     DriveSystemService* system_service = FindDriveSystemService(); | 
 |     if (!system_service) | 
 |       return; | 
 |  | 
 |     *list = GetDriveStatusList( | 
 |         system_service->drive_service()->GetProgressStatusList()); | 
 |   } | 
 |  | 
 |  | 
 |   virtual void GetMostRelevantNetworkIcon(ash::NetworkIconInfo* info, | 
 |                                           bool dark) OVERRIDE { | 
 |     NetworkMenuIcon* icon = | 
 |         dark ? network_icon_dark_.get() : network_icon_.get(); | 
 |     info->image = icon->GetIconAndText(&info->description); | 
 |     info->tray_icon_visible = icon->ShouldShowIconInTray(); | 
 |   } | 
 |  | 
 |   virtual void GetAvailableNetworks( | 
 |       std::vector<ash::NetworkIconInfo>* list) OVERRIDE { | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |  | 
 |     std::set<const Network*> added; | 
 |  | 
 |     // Add the active network first. | 
 |  | 
 |     if (crosnet->active_network()) { | 
 |       AddNetworkToList(list, &added, crosnet->active_network()); | 
 |     } | 
 |  | 
 |     // Add connected/connecting network(s) second, by type. | 
 |  | 
 |     if (crosnet->virtual_network() | 
 |         && crosnet->virtual_network()->connecting_or_connected()) { | 
 |       AddNetworkToList(list, &added, crosnet->virtual_network()); | 
 |     } | 
 |     if (crosnet->ethernet_network() && | 
 |         crosnet->ethernet_network()->connecting_or_connected()) { | 
 |       AddNetworkToList(list, &added, crosnet->ethernet_network()); | 
 |     } | 
 |     if (crosnet->cellular_network() | 
 |         && crosnet->cellular_network()->connecting_or_connected()) { | 
 |       AddNetworkToList(list, &added, crosnet->cellular_network()); | 
 |     } | 
 |     if (crosnet->wimax_network() | 
 |         && crosnet->wimax_network()->connecting_or_connected()) { | 
 |       AddNetworkToList(list, &added, crosnet->wimax_network()); | 
 |     } | 
 |     if (crosnet->wifi_network() | 
 |         && crosnet->wifi_network()->connecting_or_connected()) { | 
 |       AddNetworkToList(list, &added, crosnet->wifi_network()); | 
 |     } | 
 |  | 
 |     // Add remaining networks by type. | 
 |  | 
 |     // Ethernet. | 
 |     if (crosnet->ethernet_available() && crosnet->ethernet_enabled()) { | 
 |       const EthernetNetwork* ethernet_network = crosnet->ethernet_network(); | 
 |       if (ethernet_network) | 
 |         AddNetworkToList(list, &added, ethernet_network); | 
 |     } | 
 |  | 
 |     // VPN (only if logged in). | 
 |     if (GetUserLoginStatus() != ash::user::LOGGED_IN_NONE && | 
 |         (crosnet->connected_network() || | 
 |          crosnet->virtual_network_connected())) { | 
 |       const VirtualNetworkVector& vpns = crosnet->virtual_networks(); | 
 |       for (size_t i = 0; i < vpns.size(); ++i) | 
 |         AddNetworkToList(list, &added, vpns[i]); | 
 |     } | 
 |  | 
 |     // Cellular. | 
 |     if (crosnet->cellular_available() && crosnet->cellular_enabled()) { | 
 |       const CellularNetworkVector& cell = crosnet->cellular_networks(); | 
 |       for (size_t i = 0; i < cell.size(); ++i) | 
 |         AddNetworkToList(list, &added, cell[i]); | 
 |     } | 
 |  | 
 |     // Wimax. | 
 |     if (crosnet->wimax_available() && crosnet->wimax_enabled()) { | 
 |       const WimaxNetworkVector& wimax = crosnet->wimax_networks(); | 
 |       for (size_t i = 0; i < wimax.size(); ++i) | 
 |         AddNetworkToList(list, &added, wimax[i]); | 
 |     } | 
 |  | 
 |     // Wifi. | 
 |     if (crosnet->wifi_available() && crosnet->wifi_enabled()) { | 
 |       const WifiNetworkVector& wifi = crosnet->wifi_networks(); | 
 |       for (size_t i = 0; i < wifi.size(); ++i) | 
 |         AddNetworkToList(list, &added, wifi[i]); | 
 |     } | 
 |   } | 
 |  | 
 |   virtual void GetNetworkAddresses(std::string* ip_address, | 
 |                                    std::string* ethernet_mac_address, | 
 |                                    std::string* wifi_mac_address) OVERRIDE { | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     if (crosnet->Connected()) | 
 |       *ip_address = crosnet->IPAddress(); | 
 |     else | 
 |       *ip_address = std::string(); | 
 |  | 
 |     *ethernet_mac_address = std::string(); | 
 |     const NetworkDevice* ether = crosnet->FindEthernetDevice(); | 
 |     if (ether) | 
 |       crosnet->GetIPConfigs(ether->device_path(), ethernet_mac_address, | 
 |           NetworkLibrary::FORMAT_COLON_SEPARATED_HEX); | 
 |  | 
 |     *wifi_mac_address = std::string(); | 
 |     const NetworkDevice* wifi = crosnet->wifi_enabled() ? | 
 |         crosnet->FindWifiDevice() : NULL; | 
 |     if (wifi) | 
 |       crosnet->GetIPConfigs(wifi->device_path(), wifi_mac_address, | 
 |           NetworkLibrary::FORMAT_COLON_SEPARATED_HEX); | 
 |   } | 
 |  | 
 |   virtual void ConnectToNetwork(const std::string& network_id) OVERRIDE { | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     Network* network = crosnet->FindNetworkByPath(network_id); | 
 |     if (network) | 
 |       network_menu_->ConnectToNetwork(network); | 
 |   } | 
 |  | 
 |   virtual void RequestNetworkScan() OVERRIDE { | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     crosnet->RequestNetworkScan(); | 
 |   } | 
 |  | 
 |   virtual void AddBluetoothDevice() OVERRIDE { | 
 |     // Open the Bluetooth device dialog, which automatically starts the | 
 |     // discovery process. | 
 |     content::RecordAction( | 
 |         content::UserMetricsAction("OpenAddBluetoothDeviceDialog")); | 
 |     chrome::ShowSettingsSubPage(GetAppropriateBrowser(), | 
 |                                 chrome::kBluetoothAddDeviceSubPage); | 
 |   } | 
 |  | 
 |   virtual void ToggleAirplaneMode() OVERRIDE { | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     crosnet->EnableOfflineMode(!crosnet->offline_mode()); | 
 |   } | 
 |  | 
 |   virtual void ToggleWifi() OVERRIDE { | 
 |     tray_->network_observer()->OnWillToggleWifi(); | 
 |     network_menu_->ToggleWifi(); | 
 |   } | 
 |  | 
 |   virtual void ToggleMobile() OVERRIDE { | 
 |     network_menu_->ToggleMobile(); | 
 |   } | 
 |  | 
 |   virtual void ToggleBluetooth() OVERRIDE { | 
 |     bluetooth_adapter_->SetPowered(!bluetooth_adapter_->IsPowered(), | 
 |                                    base::Bind(&base::DoNothing), | 
 |                                    base::Bind(&BluetoothPowerFailure)); | 
 |   } | 
 |  | 
 |   virtual void ShowOtherWifi() OVERRIDE { | 
 |     network_menu_->ShowOtherWifi(); | 
 |   } | 
 |  | 
 |   virtual void ShowOtherCellular() OVERRIDE { | 
 |     network_menu_->ShowOtherCellular(); | 
 |   } | 
 |  | 
 |   virtual bool IsNetworkConnected() OVERRIDE { | 
 |     return CrosLibrary::Get()->GetNetworkLibrary()->Connected(); | 
 |   } | 
 |  | 
 |   virtual bool GetWifiAvailable() OVERRIDE { | 
 |     return CrosLibrary::Get()->GetNetworkLibrary()->wifi_available(); | 
 |   } | 
 |  | 
 |   virtual bool GetMobileAvailable() OVERRIDE { | 
 |     return CrosLibrary::Get()->GetNetworkLibrary()->mobile_available(); | 
 |   } | 
 |  | 
 |   virtual bool GetBluetoothAvailable() OVERRIDE { | 
 |     return bluetooth_adapter_->IsPresent(); | 
 |   } | 
 |  | 
 |   virtual bool GetWifiEnabled() OVERRIDE { | 
 |     return CrosLibrary::Get()->GetNetworkLibrary()->wifi_enabled(); | 
 |   } | 
 |  | 
 |   virtual bool GetMobileEnabled() OVERRIDE { | 
 |     return CrosLibrary::Get()->GetNetworkLibrary()->mobile_enabled(); | 
 |   } | 
 |  | 
 |   virtual bool GetBluetoothEnabled() OVERRIDE { | 
 |     return bluetooth_adapter_->IsPowered(); | 
 |   } | 
 |  | 
 |   virtual bool GetMobileScanSupported() OVERRIDE { | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     const NetworkDevice* mobile = crosnet->FindMobileDevice(); | 
 |     return mobile ? mobile->support_network_scan() : false; | 
 |   } | 
 |  | 
 |   virtual bool GetCellularCarrierInfo(std::string* carrier_id, | 
 |                                       std::string* topup_url, | 
 |                                       std::string* setup_url) OVERRIDE { | 
 |     bool result = false; | 
 |     NetworkLibrary* crosnet = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     const NetworkDevice* cellular = crosnet->FindCellularDevice(); | 
 |     if (!cellular) | 
 |       return false; | 
 |  | 
 |     MobileConfig* config = MobileConfig::GetInstance(); | 
 |     if (config->IsReady()) { | 
 |       *carrier_id = crosnet->GetCellularHomeCarrierId(); | 
 |       const MobileConfig::Carrier* carrier = config->GetCarrier(*carrier_id); | 
 |       if (carrier) { | 
 |         *topup_url = carrier->top_up_url(); | 
 |         result = true; | 
 |       } | 
 |       const MobileConfig::LocaleConfig* locale_config = | 
 |           config->GetLocaleConfig(); | 
 |       if (locale_config) { | 
 |         // Only link to setup URL if SIM card is not inserted. | 
 |         if (cellular->is_sim_absent()) { | 
 |           *setup_url = locale_config->setup_url(); | 
 |           result = true; | 
 |         } | 
 |       } | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 |   virtual void ShowCellularURL(const std::string& url) OVERRIDE { | 
 |     chrome::ShowSingletonTab(GetAppropriateBrowser(), GURL(url)); | 
 |   } | 
 |  | 
 |   virtual void ChangeProxySettings() OVERRIDE { | 
 |     CHECK(GetUserLoginStatus() == ash::user::LOGGED_IN_NONE); | 
 |     BaseLoginDisplayHost::default_host()->OpenProxySettings(); | 
 |   } | 
 |  | 
 |   virtual ash::VolumeControlDelegate* GetVolumeControlDelegate() const OVERRIDE | 
 |   { | 
 |     return volume_control_delegate_.get(); | 
 |   } | 
 |  | 
 |   virtual void SetVolumeControlDelegate( | 
 |       scoped_ptr<ash::VolumeControlDelegate> delegate) OVERRIDE { | 
 |     volume_control_delegate_.swap(delegate); | 
 |   } | 
 |  private: | 
 |   // Returns the last active browser. If there is no such browser, creates a new | 
 |   // browser window with an empty tab and returns it. | 
 |   Browser* GetAppropriateBrowser() { | 
 |     return browser::FindOrCreateTabbedBrowser( | 
 |         ProfileManager::GetDefaultProfileOrOffTheRecord()); | 
 |   } | 
 |  | 
 |   void SetProfile(Profile* profile) { | 
 |     pref_registrar_.reset(new PrefChangeRegistrar); | 
 |     pref_registrar_->Init(profile->GetPrefs()); | 
 |     pref_registrar_->Add(prefs::kUse24HourClock, this); | 
 |     pref_registrar_->Add(prefs::kLanguageXkbRemapSearchKeyTo, this); | 
 |     UpdateClockType(profile->GetPrefs()); | 
 |     search_key_mapped_to_ = | 
 |         profile->GetPrefs()->GetInteger(prefs::kLanguageXkbRemapSearchKeyTo); | 
 |   } | 
 |  | 
 |   void ObserveGDataUpdates() { | 
 |     DriveSystemService* system_service = FindDriveSystemService(); | 
 |     if (!system_service) | 
 |       return; | 
 |  | 
 |     system_service->drive_service()->AddObserver(this); | 
 |   } | 
 |  | 
 |   void UpdateClockType(PrefService* service) { | 
 |     clock_type_ = service->GetBoolean(prefs::kUse24HourClock) ? | 
 |         base::k24HourClock : base::k12HourClock; | 
 |     ash::ClockObserver* observer = tray_->clock_observer(); | 
 |     if (observer) | 
 |       observer->OnDateFormatChanged(); | 
 |   } | 
 |  | 
 |   void NotifyRefreshClock() { | 
 |     ash::ClockObserver* observer = tray_->clock_observer(); | 
 |     if (observer) | 
 |       observer->Refresh(); | 
 |   } | 
 |  | 
 |   void NotifyRefreshNetwork() { | 
 |     ash::NetworkObserver* observer = tray_->network_observer(); | 
 |     chromeos::NetworkLibrary* crosnet = | 
 |         chromeos::CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     if (observer) { | 
 |       ash::NetworkIconInfo info; | 
 |       info.image = network_icon_->GetIconAndText(&info.description); | 
 |       info.tray_icon_visible = network_icon_->ShouldShowIconInTray(); | 
 |       observer->OnNetworkRefresh(info); | 
 |     } | 
 |  | 
 |     // Update Accessibility. | 
 |  | 
 |     std::string connected_network_path; | 
 |     ConnectionState connected_network_state(STATE_UNKNOWN); | 
 |     if (crosnet->connected_network()) { | 
 |       connected_network_path = crosnet->connected_network()->service_path(); | 
 |       connected_network_state = crosnet->connected_network()->state(); | 
 |     } | 
 |     if (accessibility::IsSpokenFeedbackEnabled()) { | 
 |       bool speak = false; | 
 |       if ((connected_network_path_ != connected_network_path) || | 
 |           (Network::IsConnectedState(connected_network_state_) && | 
 |            !Network::IsConnectedState(connected_network_state)) || | 
 |           (Network::IsConnectingState(connected_network_state_) && | 
 |            !Network::IsConnectingState(connected_network_state)) || | 
 |           (Network::IsDisconnectedState(connected_network_state_) && | 
 |            !Network::IsDisconnectedState(connected_network_state))) { | 
 |         speak = true; | 
 |       } | 
 |  | 
 |       if (speak) | 
 |         AccessibilitySpeak(crosnet->connected_network()); | 
 |     } | 
 |  | 
 |     connected_network_path_ = connected_network_path_; | 
 |     connected_network_state_ = connected_network_state; | 
 |   } | 
 |  | 
 |   void NotifyRefreshBluetooth() { | 
 |     ash::BluetoothObserver* observer = tray_->bluetooth_observer(); | 
 |     if (observer) | 
 |       observer->OnBluetoothRefresh(); | 
 |   } | 
 |  | 
 |   void NotifyRefreshIME(bool show_message) { | 
 |     ash::IMEObserver* observer = tray_->ime_observer(); | 
 |     if (observer) | 
 |       observer->OnIMERefresh(show_message); | 
 |   } | 
 |  | 
 |   void NotifyRefreshDrive(ash::DriveOperationStatusList& list) { | 
 |     ash::DriveObserver* observer = tray_->drive_observer(); | 
 |     if (observer) | 
 |       observer->OnDriveRefresh(list); | 
 |   } | 
 |  | 
 |   void RefreshNetworkObserver(NetworkLibrary* crosnet) { | 
 |     const Network* network = crosnet->active_network(); | 
 |     std::string new_path = network ? network->service_path() : std::string(); | 
 |     if (active_network_path_ != new_path) { | 
 |       if (!active_network_path_.empty()) | 
 |         crosnet->RemoveNetworkObserver(active_network_path_, this); | 
 |       if (!new_path.empty()) | 
 |         crosnet->AddNetworkObserver(new_path, this); | 
 |       active_network_path_ = new_path; | 
 |     } | 
 |   } | 
 |  | 
 |   void RefreshNetworkDeviceObserver(NetworkLibrary* crosnet) { | 
 |     const NetworkDevice* cellular = crosnet->FindCellularDevice(); | 
 |     std::string new_cellular_device_path = cellular ? | 
 |         cellular->device_path() : std::string(); | 
 |     if (cellular_device_path_ != new_cellular_device_path) | 
 |       cellular_device_path_ = new_cellular_device_path; | 
 |   } | 
 |  | 
 |   // Generate accessability text and call Speak(). | 
 |   void AccessibilitySpeak(const Network* network) { | 
 |     if (!network) | 
 |       return; | 
 |     NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); | 
 |     std::string connection_string; | 
 |     if (Network::IsConnectedState(network->state())) { | 
 |       switch (network->type()) { | 
 |         case TYPE_ETHERNET: | 
 |           connection_string = l10n_util::GetStringFUTF8( | 
 |               IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP, | 
 |               l10n_util::GetStringUTF16( | 
 |                   IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET)); | 
 |           break; | 
 |         default: | 
 |           connection_string = l10n_util::GetStringFUTF8( | 
 |               IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP, | 
 |               UTF8ToUTF16(network->name())); | 
 |           break; | 
 |       } | 
 |     } else if (Network::IsConnectingState(network->state())) { | 
 |       const Network* connecting_network = cros->connecting_network(); | 
 |       if (connecting_network && connecting_network->type() != TYPE_ETHERNET) { | 
 |         connection_string = l10n_util::GetStringFUTF8( | 
 |             IDS_STATUSBAR_NETWORK_CONNECTING_TOOLTIP, | 
 |             UTF8ToUTF16(connecting_network->name())); | 
 |       } | 
 |     } else if (Network::IsDisconnectedState(network->state())) { | 
 |       connection_string = l10n_util::GetStringUTF8( | 
 |           IDS_STATUSBAR_NETWORK_NO_NETWORK_TOOLTIP); | 
 |     } | 
 |     if (connection_string != last_connection_string_) { | 
 |       last_connection_string_ = connection_string; | 
 |       accessibility::Speak(connection_string); | 
 |     } | 
 |   } | 
 |  | 
 |   void AddNetworkToList(std::vector<ash::NetworkIconInfo>* list, | 
 |                         std::set<const Network*>* added, | 
 |                         const Network* network) { | 
 |     // Only add networks to the list once. | 
 |     if (added->find(network) != added->end()) | 
 |       return; | 
 |  | 
 |     ash::NetworkIconInfo info = CreateNetworkIconInfo(network, | 
 |                                                       network_menu_.get()); | 
 |     switch (network->type()) { | 
 |       case TYPE_ETHERNET: | 
 |         if (info.name.empty()) { | 
 |           info.name = | 
 |               l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET); | 
 |         } | 
 |         break; | 
 |       case TYPE_CELLULAR: { | 
 |         const CellularNetwork* cellular = | 
 |             static_cast<const CellularNetwork*>(network); | 
 |         ActivationState state = cellular->activation_state(); | 
 |         if (state == ACTIVATION_STATE_NOT_ACTIVATED || | 
 |             state == ACTIVATION_STATE_PARTIALLY_ACTIVATED) { | 
 |           // If a cellular network needs to be activated, | 
 |           // then do not show it in the lock screen. | 
 |           if (GetUserLoginStatus() == ash::user::LOGGED_IN_LOCKED) | 
 |             return; | 
 |  | 
 |           info.description = l10n_util::GetStringFUTF16( | 
 |               IDS_STATUSBAR_NETWORK_DEVICE_ACTIVATE, | 
 |               info.name); | 
 |         } else if (state == ACTIVATION_STATE_ACTIVATING) { | 
 |           info.description = l10n_util::GetStringFUTF16( | 
 |               IDS_STATUSBAR_NETWORK_DEVICE_STATUS, | 
 |               info.name, l10n_util::GetStringUTF16( | 
 |                   IDS_STATUSBAR_NETWORK_DEVICE_ACTIVATING)); | 
 |         } else if (network->connecting()) { | 
 |           info.description = l10n_util::GetStringFUTF16( | 
 |               IDS_STATUSBAR_NETWORK_DEVICE_STATUS, | 
 |               info.name, l10n_util::GetStringUTF16( | 
 |                   IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING)); | 
 |         } | 
 |         break; | 
 |       } | 
 |       case TYPE_VPN: | 
 |       case TYPE_WIFI: | 
 |       case TYPE_WIMAX: | 
 |       case TYPE_BLUETOOTH: | 
 |       case TYPE_UNKNOWN: | 
 |         break; | 
 |     } | 
 |     if (network->connecting()) { | 
 |       info.description = l10n_util::GetStringFUTF16( | 
 |           IDS_STATUSBAR_NETWORK_DEVICE_STATUS, | 
 |           info.name, | 
 |           l10n_util::GetStringUTF16( | 
 |               IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING)); | 
 |     } | 
 |     added->insert(network); | 
 |     list->push_back(info); | 
 |   } | 
 |  | 
 |   // Overridden from AudioHandler::VolumeObserver. | 
 |   virtual void OnVolumeChanged() OVERRIDE { | 
 |     float level = AudioHandler::GetInstance()->GetVolumePercent() / 100.f; | 
 |     tray_->audio_observer()->OnVolumeChanged(level); | 
 |   } | 
 |  | 
 |   // Overridden from AudioHandler::VolumeObserver. | 
 |   virtual void OnMuteToggled() OVERRIDE { | 
 |     tray_->audio_observer()->OnMuteToggled(); | 
 |   } | 
 |  | 
 |   // Overridden from PowerManagerClient::Observer. | 
 |   virtual void BrightnessChanged(int level, bool user_initiated) OVERRIDE { | 
 |     tray_->brightness_observer()-> | 
 |         OnBrightnessChanged(static_cast<double>(level), user_initiated); | 
 |   } | 
 |  | 
 |   virtual void PowerChanged(const PowerSupplyStatus& power_status) OVERRIDE { | 
 |     power_supply_status_ = power_status; | 
 |     FOR_EACH_OBSERVER(ash::PowerStatusObserver, tray_->power_status_observers(), | 
 |         OnPowerStatusChanged(power_status)); | 
 |   } | 
 |  | 
 |   virtual void SystemResumed() OVERRIDE { | 
 |     NotifyRefreshClock(); | 
 |   } | 
 |  | 
 |   // Overridden from SessionManagerClient::Observer. | 
 |   virtual void LockScreen() OVERRIDE { | 
 |     screen_locked_ = true; | 
 |     ash::Shell::GetInstance()->status_area_widget()-> | 
 |         UpdateAfterLoginStatusChange(GetUserLoginStatus()); | 
 |   } | 
 |  | 
 |   virtual void UnlockScreen() OVERRIDE { | 
 |     screen_locked_ = false; | 
 |     ash::Shell::GetInstance()->status_area_widget()-> | 
 |         UpdateAfterLoginStatusChange(GetUserLoginStatus()); | 
 |   } | 
 |  | 
 |   // TODO(sad): Override more from PowerManagerClient::Observer here (e.g. | 
 |   // PowerButtonStateChanged etc.). | 
 |  | 
 |   // Overridden from NetworkMenuIcon::Delegate. | 
 |   virtual void NetworkMenuIconChanged() OVERRIDE { | 
 |     NotifyRefreshNetwork(); | 
 |   } | 
 |  | 
 |   // Overridden from NetworkMenu::Delegate. | 
 |   virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE { | 
 |     return ash::Shell::GetContainer( | 
 |         ash::Shell::GetPrimaryRootWindow(), | 
 |         GetUserLoginStatus() == ash::user::LOGGED_IN_NONE ? | 
 |             ash::internal::kShellWindowId_LockSystemModalContainer : | 
 |             ash::internal::kShellWindowId_SystemModalContainer); | 
 |   } | 
 |  | 
 |   virtual void OpenButtonOptions() OVERRIDE { | 
 |   } | 
 |  | 
 |   virtual bool ShouldOpenButtonOptions() const OVERRIDE { | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Overridden from NetworkLibrary::NetworkManagerObserver. | 
 |   virtual void OnNetworkManagerChanged(NetworkLibrary* crosnet) OVERRIDE { | 
 |     RefreshNetworkObserver(crosnet); | 
 |     RefreshNetworkDeviceObserver(crosnet); | 
 |     data_promo_notification_->ShowOptionalMobileDataPromoNotification( | 
 |         crosnet, tray_, this); | 
 |  | 
 |     NotifyRefreshNetwork(); | 
 |   } | 
 |  | 
 |   // Overridden from NetworkLibrary::NetworkObserver. | 
 |   virtual void OnNetworkChanged(NetworkLibrary* crosnet, | 
 |       const Network* network) OVERRIDE { | 
 |     NotifyRefreshNetwork(); | 
 |   } | 
 |  | 
 |   // Overridden from NetworkLibrary::CellularDataPlanObserver. | 
 |   virtual void OnCellularDataPlanChanged(NetworkLibrary* crosnet) OVERRIDE { | 
 |     NotifyRefreshNetwork(); | 
 |   } | 
 |  | 
 |   // content::NotificationObserver implementation. | 
 |   virtual void Observe(int type, | 
 |                        const content::NotificationSource& source, | 
 |                        const content::NotificationDetails& details) OVERRIDE { | 
 |     switch (type) { | 
 |       case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: { | 
 |         UpgradeDetector* detector = | 
 |             content::Source<UpgradeDetector>(source).ptr(); | 
 |         ash::UpdateObserver::UpdateSeverity severity = | 
 |             ash::UpdateObserver::UPDATE_NORMAL; | 
 |         switch (detector->upgrade_notification_stage()) { | 
 |           case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE: | 
 |             severity = ash::UpdateObserver::UPDATE_SEVERE_RED; | 
 |             break; | 
 |  | 
 |           case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH: | 
 |             severity = ash::UpdateObserver::UPDATE_HIGH_ORANGE; | 
 |             break; | 
 |  | 
 |           case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED: | 
 |             severity = ash::UpdateObserver::UPDATE_LOW_GREEN; | 
 |             break; | 
 |  | 
 |           case UpgradeDetector::UPGRADE_ANNOYANCE_LOW: | 
 |           default: | 
 |             severity = ash::UpdateObserver::UPDATE_NORMAL; | 
 |             break; | 
 |         } | 
 |         ash::UpdateObserver* observer = tray_->update_observer(); | 
 |         if (observer) | 
 |           observer->OnUpdateRecommended(severity); | 
 |         break; | 
 |       } | 
 |       case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: { | 
 |         // This notification is also sent on login screen when user avatar | 
 |         // is loaded from file. | 
 |         if (GetUserLoginStatus() != ash::user::LOGGED_IN_NONE) { | 
 |           ash::UserObserver* observer = tray_->user_observer(); | 
 |           if (observer) | 
 |             observer->OnUserUpdate(); | 
 |         } | 
 |         break; | 
 |       } | 
 |       case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED: { | 
 |         // GData system service exists by the time if enabled. | 
 |         ObserveGDataUpdates(); | 
 |         break; | 
 |       } | 
 |       case chrome::NOTIFICATION_PREF_CHANGED: { | 
 |         std::string pref = *content::Details<std::string>(details).ptr(); | 
 |         PrefService* service = content::Source<PrefService>(source).ptr(); | 
 |         if (pref == prefs::kUse24HourClock) { | 
 |           UpdateClockType(service); | 
 |         } else if (pref == prefs::kLanguageXkbRemapSearchKeyTo) { | 
 |           search_key_mapped_to_ = | 
 |               service->GetInteger(prefs::kLanguageXkbRemapSearchKeyTo); | 
 |         } else if (pref == prefs::kSpokenFeedbackEnabled) { | 
 |           ash::AccessibilityObserver* observer = | 
 |               tray_->accessibility_observer(); | 
 |           if (observer) { | 
 |             observer->OnAccessibilityModeChanged( | 
 |                 service->GetBoolean(prefs::kSpokenFeedbackEnabled)); | 
 |           } | 
 |         } else { | 
 |           NOTREACHED(); | 
 |         } | 
 |         break; | 
 |       } | 
 |       case chrome::NOTIFICATION_PROFILE_CREATED: { | 
 |         SetProfile(content::Source<Profile>(source).ptr()); | 
 |         registrar_.Remove(this, | 
 |                           chrome::NOTIFICATION_PROFILE_CREATED, | 
 |                           content::NotificationService::AllSources()); | 
 |         break; | 
 |       } | 
 |       case chrome::NOTIFICATION_SESSION_STARTED: { | 
 |         ash::Shell::GetInstance()->status_area_widget()-> | 
 |             UpdateAfterLoginStatusChange(GetUserLoginStatus()); | 
 |         SetProfile(ProfileManager::GetDefaultProfile()); | 
 |         break; | 
 |       } | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |   // Overridden from InputMethodManager::Observer. | 
 |   virtual void InputMethodChanged( | 
 |       input_method::InputMethodManager* manager, bool show_message) OVERRIDE { | 
 |     NotifyRefreshIME(show_message); | 
 |   } | 
 |  | 
 |   virtual void InputMethodPropertyChanged( | 
 |       input_method::InputMethodManager* manager) OVERRIDE { | 
 |     NotifyRefreshIME(false); | 
 |   } | 
 |  | 
 |   // gdata::DriveServiceObserver overrides. | 
 |   virtual void OnProgressUpdate( | 
 |       const gdata::OperationProgressStatusList& list) OVERRIDE { | 
 |     std::vector<ash::DriveOperationStatus> ui_list = GetDriveStatusList(list); | 
 |     NotifyRefreshDrive(ui_list); | 
 |  | 
 |     // If we have something to report right now (i.e. completion status only), | 
 |     // we need to delayed re-check the status in few seconds to ensure we | 
 |     // raise events that will let us properly clear the uber tray state. | 
 |     if (list.size() > 0) { | 
 |       bool has_in_progress_items = false; | 
 |       for (gdata::OperationProgressStatusList::const_iterator it = list.begin(); | 
 |           it != list.end(); ++it) { | 
 |         if (it->transfer_state == gdata::OPERATION_STARTED || | 
 |             it->transfer_state == gdata::OPERATION_IN_PROGRESS || | 
 |             it->transfer_state == gdata::OPERATION_SUSPENDED) { | 
 |           has_in_progress_items = true; | 
 |           break; | 
 |         } | 
 |       } | 
 |  | 
 |       if (!has_in_progress_items) { | 
 |         content::BrowserThread::PostDelayedTask( | 
 |             content::BrowserThread::UI, | 
 |             FROM_HERE, | 
 |             base::Bind(&SystemTrayDelegate::RecheckGDataOperations, | 
 |                        ui_weak_ptr_factory_->GetWeakPtr()), | 
 |             base::TimeDelta::FromMilliseconds(kGDataOperationRecheckDelayMs)); | 
 |       } | 
 |     } | 
 |  | 
 |   } | 
 |  | 
 |   // Pulls the list of ongoing drive operations and initiates status update. | 
 |   // This method is needed to ensure delayed cleanup of the latest reported | 
 |   // status in UI in cases when there are no new changes coming (i.e. when the | 
 |   // last set of transfer operations completed). | 
 |   void RecheckGDataOperations() { | 
 |     DriveSystemService* system_service = FindDriveSystemService(); | 
 |     if (!system_service) | 
 |       return; | 
 |  | 
 |     OnProgressUpdate(system_service->drive_service()->GetProgressStatusList()); | 
 |   } | 
 |  | 
 |   DriveSystemService* FindDriveSystemService() { | 
 |     Profile* profile = ProfileManager::GetDefaultProfile(); | 
 |     if (!gdata::util::IsGDataAvailable(profile)) | 
 |       return NULL; | 
 |     return DriveSystemServiceFactory::FindForProfile(profile); | 
 |   } | 
 |  | 
 |   // Overridden from system::TimezoneSettings::Observer. | 
 |   virtual void TimezoneChanged(const icu::TimeZone& timezone) OVERRIDE { | 
 |     NotifyRefreshClock(); | 
 |   } | 
 |  | 
 |   // Overridden from BluetoothAdapter::Observer. | 
 |   virtual void AdapterPresentChanged(BluetoothAdapter* adapter, | 
 |                                      bool present) OVERRIDE { | 
 |     NotifyRefreshBluetooth(); | 
 |   } | 
 |  | 
 |   virtual void AdapterPoweredChanged(BluetoothAdapter* adapter, | 
 |                                      bool powered) OVERRIDE { | 
 |     NotifyRefreshBluetooth(); | 
 |   } | 
 |  | 
 |   virtual void AdapterDiscoveringChanged(BluetoothAdapter* adapter, | 
 |                                          bool discovering) OVERRIDE { | 
 |     // TODO: Perhaps start/stop throbbing the icon, or some other visual | 
 |     // effects? | 
 |   } | 
 |  | 
 |   virtual void DeviceAdded(BluetoothAdapter* adapter, | 
 |                            BluetoothDevice* device) OVERRIDE { | 
 |     NotifyRefreshBluetooth(); | 
 |   } | 
 |  | 
 |   virtual void DeviceChanged(BluetoothAdapter* adapter, | 
 |                              BluetoothDevice* device) OVERRIDE { | 
 |     NotifyRefreshBluetooth(); | 
 |   } | 
 |  | 
 |   virtual void DeviceRemoved(BluetoothAdapter* adapter, | 
 |                              BluetoothDevice* device) OVERRIDE { | 
 |     NotifyRefreshBluetooth(); | 
 |   } | 
 |  | 
 |   // Overridden from SystemKeyEventListener::CapsLockObserver. | 
 |   virtual void OnCapsLockChange(bool enabled) OVERRIDE { | 
 |     bool search_mapped_to_caps_lock = false; | 
 |     if (!base::chromeos::IsRunningOnChromeOS() || | 
 |         search_key_mapped_to_ == input_method::kCapsLockKey) | 
 |       search_mapped_to_caps_lock = true; | 
 |  | 
 |     ash::CapsLockObserver* observer = tray_->caps_lock_observer(); | 
 |     if (observer) | 
 |       observer->OnCapsLockChanged(enabled, search_mapped_to_caps_lock); | 
 |   } | 
 |  | 
 |   // Overridden from ash::NetworkTrayDelegate | 
 |   virtual void NotificationLinkClicked(size_t index) OVERRIDE { | 
 |     // If we have deal info URL defined that means that there're | 
 |     // 2 links in bubble. Let the user close it manually then thus giving | 
 |     // ability to navigate to second link. | 
 |     // mobile_data_bubble_ will be set to NULL in BubbleClosing callback. | 
 |     std::string deal_info_url = data_promo_notification_->deal_info_url(); | 
 |     std::string deal_topup_url = data_promo_notification_->deal_topup_url(); | 
 |     if (deal_info_url.empty()) | 
 |       data_promo_notification_->CloseNotification(); | 
 |  | 
 |     std::string deal_url_to_open; | 
 |     if (index == 0) { | 
 |       if (!deal_topup_url.empty()) { | 
 |         deal_url_to_open = deal_topup_url; | 
 |       } else { | 
 |         const Network* cellular = | 
 |             CrosLibrary::Get()->GetNetworkLibrary()->cellular_network(); | 
 |         if (!cellular) | 
 |           return; | 
 |         network_menu_->ShowTabbedNetworkSettings(cellular); | 
 |         return; | 
 |       } | 
 |     } else if (index == 1) { | 
 |       deal_url_to_open = deal_info_url; | 
 |     } | 
 |  | 
 |     if (!deal_url_to_open.empty()) { | 
 |       Browser* browser = GetAppropriateBrowser(); | 
 |       if (!browser) | 
 |         return; | 
 |       chrome::ShowSingletonTab(browser, GURL(deal_url_to_open)); | 
 |     } | 
 |   } | 
 |  | 
 |   ash::SystemTray* tray_; | 
 |   scoped_ptr<base::WeakPtrFactory<SystemTrayDelegate> > ui_weak_ptr_factory_; | 
 |   scoped_ptr<NetworkMenuIcon> network_icon_; | 
 |   scoped_ptr<NetworkMenuIcon> network_icon_dark_; | 
 |   scoped_ptr<NetworkMenu> network_menu_; | 
 |   content::NotificationRegistrar registrar_; | 
 |   scoped_ptr<PrefChangeRegistrar> pref_registrar_; | 
 |   std::string cellular_device_path_; | 
 |   std::string active_network_path_; | 
 |   PowerSupplyStatus power_supply_status_; | 
 |   base::HourClockType clock_type_; | 
 |   int search_key_mapped_to_; | 
 |   bool screen_locked_; | 
 |   ConnectionState connected_network_state_; | 
 |   std::string connected_network_path_; | 
 |  | 
 |   std::string last_connection_string_; | 
 |  | 
 |   scoped_refptr<BluetoothAdapter> bluetooth_adapter_; | 
 |  | 
 |   BooleanPrefMember accessibility_enabled_; | 
 |  | 
 |   scoped_ptr<DataPromoNotification> data_promo_notification_; | 
 |  | 
 |   scoped_ptr<ash::VolumeControlDelegate> volume_control_delegate_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(SystemTrayDelegate); | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | ash::SystemTrayDelegate* CreateSystemTrayDelegate(ash::SystemTray* tray) { | 
 |   return new chromeos::SystemTrayDelegate(tray); | 
 | } | 
 |  | 
 | }  // namespace chromeos |