summaryrefslogtreecommitdiff
path: root/chromium/ash/system/bluetooth/tray_bluetooth.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ash/system/bluetooth/tray_bluetooth.cc')
-rw-r--r--chromium/ash/system/bluetooth/tray_bluetooth.cc463
1 files changed, 463 insertions, 0 deletions
diff --git a/chromium/ash/system/bluetooth/tray_bluetooth.cc b/chromium/ash/system/bluetooth/tray_bluetooth.cc
new file mode 100644
index 00000000000..5d75e945ab0
--- /dev/null
+++ b/chromium/ash/system/bluetooth/tray_bluetooth.cc
@@ -0,0 +1,463 @@
+// 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 "ash/system/bluetooth/tray_bluetooth.h"
+
+#include "ash/shell.h"
+#include "ash/system/tray/fixed_sized_scroll_view.h"
+#include "ash/system/tray/hover_highlight_view.h"
+#include "ash/system/tray/system_tray.h"
+#include "ash/system/tray/system_tray_delegate.h"
+#include "ash/system/tray/system_tray_notifier.h"
+#include "ash/system/tray/throbber_view.h"
+#include "ash/system/tray/tray_constants.h"
+#include "ash/system/tray/tray_details_view.h"
+#include "ash/system/tray/tray_item_more.h"
+#include "ash/system/tray/tray_popup_header_button.h"
+#include "grit/ash_resources.h"
+#include "grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace ash {
+namespace internal {
+
+namespace tray {
+
+namespace {
+
+// Updates bluetooth device |device| in the |list|. If it is new, append to the
+// end of the |list|; otherwise, keep it at the same place, but update the data
+// with new device info provided by |device|.
+void UpdateBluetoothDeviceList(BluetoothDeviceList* list,
+ const BluetoothDeviceInfo& device) {
+ for (BluetoothDeviceList::iterator it = list->begin(); it != list->end();
+ ++it) {
+ if ((*it).address == device.address) {
+ *it = device;
+ return;
+ }
+ }
+
+ list->push_back(device);
+}
+
+// Removes the obsolete BluetoothDevices from |list|, if they are not in the
+// |new_list|.
+void RemoveObsoleteBluetoothDevicesFromList(
+ BluetoothDeviceList* list,
+ const std::set<std::string>& new_list) {
+ for (BluetoothDeviceList::iterator it = list->begin(); it != list->end();
+ ++it) {
+ if (new_list.find((*it).address) == new_list.end()) {
+ it = list->erase(it);
+ if (it == list->end())
+ return;
+ }
+ }
+}
+
+} // namespace
+
+class BluetoothDefaultView : public TrayItemMore {
+ public:
+ BluetoothDefaultView(SystemTrayItem* owner, bool show_more)
+ : TrayItemMore(owner, show_more) {
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_BLUETOOTH).ToImageSkia());
+ UpdateLabel();
+ }
+
+ virtual ~BluetoothDefaultView() {}
+
+ void UpdateLabel() {
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ if (delegate->GetBluetoothAvailable()) {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ const base::string16 label =
+ rb.GetLocalizedString(delegate->GetBluetoothEnabled() ?
+ IDS_ASH_STATUS_TRAY_BLUETOOTH_ENABLED :
+ IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED);
+ SetLabel(label);
+ SetAccessibleName(label);
+ SetVisible(true);
+ } else {
+ SetVisible(false);
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDefaultView);
+};
+
+class BluetoothDetailedView : public TrayDetailsView,
+ public ViewClickListener,
+ public views::ButtonListener {
+ public:
+ BluetoothDetailedView(SystemTrayItem* owner, user::LoginStatus login)
+ : TrayDetailsView(owner),
+ login_(login),
+ manage_devices_(NULL),
+ toggle_bluetooth_(NULL),
+ enable_bluetooth_(NULL),
+ bluetooth_discovering_(false) {
+ CreateItems();
+ Update();
+ }
+
+ virtual ~BluetoothDetailedView() {
+ // Stop discovering bluetooth devices when exiting BT detailed view.
+ BluetoothStopDiscovering();
+ }
+
+ void Update() {
+ BluetoothStartDiscovering();
+ UpdateBlueToothDeviceList();
+
+ // Update UI.
+ UpdateDeviceScrollList();
+ UpdateHeaderEntry();
+ Layout();
+ }
+
+ private:
+ void CreateItems() {
+ CreateScrollableList();
+ AppendSettingsEntries();
+ AppendHeaderEntry();
+ }
+
+ void BluetoothStartDiscovering() {
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ bool bluetooth_enabled = delegate->GetBluetoothEnabled();
+ if (!bluetooth_discovering_ && bluetooth_enabled) {
+ bluetooth_discovering_ = true;
+ delegate->BluetoothStartDiscovering();
+ throbber_->Start();
+ } else if(!bluetooth_enabled) {
+ bluetooth_discovering_ = false;
+ throbber_->Stop();
+ }
+ }
+
+ void BluetoothStopDiscovering() {
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ if (delegate && bluetooth_discovering_) {
+ bluetooth_discovering_ = false;
+ delegate->BluetoothStopDiscovering();
+ throbber_->Stop();
+ }
+ }
+
+ void UpdateBlueToothDeviceList() {
+ std::set<std::string> new_connecting_devices;
+ std::set<std::string> new_connected_devices;
+ std::set<std::string> new_paired_not_connected_devices;
+ std::set<std::string> new_discovered_not_paired_devices;
+
+ BluetoothDeviceList list;
+ Shell::GetInstance()->system_tray_delegate()->
+ GetAvailableBluetoothDevices(&list);
+ for (size_t i = 0; i < list.size(); ++i) {
+ if (list[i].connecting) {
+ list[i].display_name = l10n_util::GetStringFUTF16(
+ IDS_ASH_STATUS_TRAY_BLUETOOTH_CONNECTING, list[i].display_name);
+ new_connecting_devices.insert(list[i].address);
+ UpdateBluetoothDeviceList(&connecting_devices_, list[i]);
+ } else if (list[i].connected && list[i].paired) {
+ new_connected_devices.insert(list[i].address);
+ UpdateBluetoothDeviceList(&connected_devices_, list[i]);
+ } else if (list[i].paired) {
+ new_paired_not_connected_devices.insert(list[i].address);
+ UpdateBluetoothDeviceList(&paired_not_connected_devices_, list[i]);
+ } else {
+ new_discovered_not_paired_devices.insert(list[i].address);
+ UpdateBluetoothDeviceList(&discovered_not_paired_devices_, list[i]);
+ }
+ }
+ RemoveObsoleteBluetoothDevicesFromList(&connecting_devices_,
+ new_connecting_devices);
+ RemoveObsoleteBluetoothDevicesFromList(&connected_devices_,
+ new_connected_devices);
+ RemoveObsoleteBluetoothDevicesFromList(&paired_not_connected_devices_,
+ new_paired_not_connected_devices);
+ RemoveObsoleteBluetoothDevicesFromList(&discovered_not_paired_devices_,
+ new_discovered_not_paired_devices);
+ }
+
+ void AppendHeaderEntry() {
+ CreateSpecialRow(IDS_ASH_STATUS_TRAY_BLUETOOTH, this);
+
+ if (login_ == user::LOGGED_IN_LOCKED)
+ return;
+
+ throbber_ = new ThrobberView;
+ throbber_->SetTooltipText(
+ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING));
+ footer()->AddThrobber(throbber_);
+
+ // Do not allow toggling bluetooth in the lock screen.
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ toggle_bluetooth_ = new TrayPopupHeaderButton(this,
+ IDR_AURA_UBER_TRAY_BLUETOOTH_ENABLED,
+ IDR_AURA_UBER_TRAY_BLUETOOTH_DISABLED,
+ IDR_AURA_UBER_TRAY_BLUETOOTH_ENABLED_HOVER,
+ IDR_AURA_UBER_TRAY_BLUETOOTH_DISABLED_HOVER,
+ IDS_ASH_STATUS_TRAY_BLUETOOTH);
+ toggle_bluetooth_->SetToggled(!delegate->GetBluetoothEnabled());
+ toggle_bluetooth_->SetTooltipText(
+ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_BLUETOOTH));
+ toggle_bluetooth_->SetToggledTooltipText(
+ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_BLUETOOTH));
+ footer()->AddButton(toggle_bluetooth_);
+ }
+
+ void UpdateHeaderEntry() {
+ if (toggle_bluetooth_) {
+ toggle_bluetooth_->SetToggled(
+ !ash::Shell::GetInstance()->system_tray_delegate()->
+ GetBluetoothEnabled());
+ }
+ }
+
+ void UpdateDeviceScrollList() {
+ device_map_.clear();
+ scroll_content()->RemoveAllChildViews(true);
+ enable_bluetooth_ = NULL;
+
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ bool bluetooth_enabled = delegate->GetBluetoothEnabled();
+ bool blueooth_available = delegate->GetBluetoothAvailable();
+ if (blueooth_available && !bluetooth_enabled &&
+ toggle_bluetooth_) {
+ enable_bluetooth_ =
+ AddScrollListItem(
+ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_BLUETOOTH),
+ gfx::Font::NORMAL, false, true);
+ }
+
+ AppendSameTypeDevicesToScrollList(
+ connected_devices_, true, true, bluetooth_enabled);
+ AppendSameTypeDevicesToScrollList(
+ connecting_devices_, true, false, bluetooth_enabled);
+ AppendSameTypeDevicesToScrollList(
+ paired_not_connected_devices_, false, false, bluetooth_enabled);
+ if (discovered_not_paired_devices_.size() > 0)
+ AddScrollSeparator();
+ AppendSameTypeDevicesToScrollList(
+ discovered_not_paired_devices_, false, false, bluetooth_enabled);
+
+ // Show user Bluetooth state if there is no bluetooth devices in list.
+ if (device_map_.size() == 0) {
+ if (blueooth_available && bluetooth_enabled) {
+ AddScrollListItem(
+ l10n_util::GetStringUTF16(
+ IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING),
+ gfx::Font::NORMAL, false, true);
+ }
+ }
+
+ scroll_content()->SizeToPreferredSize();
+ static_cast<views::View*>(scroller())->Layout();
+ }
+
+ void AppendSameTypeDevicesToScrollList(const BluetoothDeviceList& list,
+ bool bold,
+ bool checked,
+ bool enabled) {
+ for (size_t i = 0; i < list.size(); ++i) {
+ HoverHighlightView* container = AddScrollListItem(
+ list[i].display_name,
+ bold? gfx::Font::BOLD : gfx::Font::NORMAL,
+ checked, enabled);
+ device_map_[container] = list[i].address;
+ }
+ }
+
+ HoverHighlightView* AddScrollListItem(const base::string16& text,
+ gfx::Font::FontStyle style,
+ bool checked,
+ bool enabled) {
+ HoverHighlightView* container = new HoverHighlightView(this);
+ views::Label* label = container->AddCheckableLabel(text, style, checked);
+ label->SetEnabled(enabled);
+ scroll_content()->AddChildView(container);
+ return container;
+ }
+
+ // Add settings entries.
+ void AppendSettingsEntries() {
+ // Add bluetooth device requires a browser window, hide it for non logged in
+ // user.
+ if (login_ == user::LOGGED_IN_NONE ||
+ login_ == user::LOGGED_IN_LOCKED)
+ return;
+
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ HoverHighlightView* container = new HoverHighlightView(this);
+ container->AddLabel(
+ rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_BLUETOOTH_MANAGE_DEVICES),
+ gfx::Font::NORMAL);
+ container->SetEnabled(delegate->GetBluetoothAvailable());
+ AddChildView(container);
+ manage_devices_ = container;
+ }
+
+ // Returns true if the device with |device_id| is found in |device_list|,
+ // and the display_name of the device will be returned in |display_name| if
+ // it's not NULL.
+ bool FoundDevice(const std::string& device_id,
+ const BluetoothDeviceList& device_list,
+ base::string16* display_name) {
+ for (size_t i = 0; i < device_list.size(); ++i) {
+ if (device_list[i].address == device_id) {
+ if (display_name)
+ *display_name = device_list[i].display_name;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Updates UI of the clicked bluetooth device to show it is being connected
+ // or disconnected if such an operation is going to be performed underway.
+ void UpdateClickedDevice(std::string device_id, views::View* item_container) {
+ base::string16 display_name;
+ if (FoundDevice(device_id, paired_not_connected_devices_,
+ &display_name)) {
+ display_name = l10n_util::GetStringFUTF16(
+ IDS_ASH_STATUS_TRAY_BLUETOOTH_CONNECTING, display_name);
+
+ item_container->RemoveAllChildViews(true);
+ static_cast<HoverHighlightView*>(item_container)->
+ AddCheckableLabel(display_name, gfx::Font::BOLD, false);
+ scroll_content()->SizeToPreferredSize();
+ static_cast<views::View*>(scroller())->Layout();
+ }
+ }
+
+ // Overridden from ViewClickListener.
+ virtual void OnViewClicked(views::View* sender) OVERRIDE {
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ if (sender == footer()->content()) {
+ owner()->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
+ } else if (sender == manage_devices_) {
+ delegate->ManageBluetoothDevices();
+ } else if (sender == enable_bluetooth_) {
+ delegate->ToggleBluetooth();
+ } else {
+ if (!delegate->GetBluetoothEnabled())
+ return;
+ std::map<views::View*, std::string>::iterator find;
+ find = device_map_.find(sender);
+ if (find == device_map_.end())
+ return;
+ std::string device_id = find->second;
+ if (FoundDevice(device_id, connecting_devices_, NULL))
+ return;
+ UpdateClickedDevice(device_id, sender);
+ delegate->ConnectToBluetoothDevice(device_id);
+ }
+ }
+
+ // Overridden from ButtonListener.
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE {
+ ash::SystemTrayDelegate* delegate =
+ ash::Shell::GetInstance()->system_tray_delegate();
+ if (sender == toggle_bluetooth_)
+ delegate->ToggleBluetooth();
+ else
+ NOTREACHED();
+ }
+
+ user::LoginStatus login_;
+
+ std::map<views::View*, std::string> device_map_;
+ views::View* manage_devices_;
+ ThrobberView* throbber_;
+ TrayPopupHeaderButton* toggle_bluetooth_;
+ HoverHighlightView* enable_bluetooth_;
+ BluetoothDeviceList connected_devices_;
+ BluetoothDeviceList connecting_devices_;
+ BluetoothDeviceList paired_not_connected_devices_;
+ BluetoothDeviceList discovered_not_paired_devices_;
+ bool bluetooth_discovering_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDetailedView);
+};
+
+} // namespace tray
+
+TrayBluetooth::TrayBluetooth(SystemTray* system_tray)
+ : SystemTrayItem(system_tray),
+ default_(NULL),
+ detailed_(NULL) {
+ Shell::GetInstance()->system_tray_notifier()->AddBluetoothObserver(this);
+}
+
+TrayBluetooth::~TrayBluetooth() {
+ Shell::GetInstance()->system_tray_notifier()->RemoveBluetoothObserver(this);
+}
+
+views::View* TrayBluetooth::CreateTrayView(user::LoginStatus status) {
+ return NULL;
+}
+
+views::View* TrayBluetooth::CreateDefaultView(user::LoginStatus status) {
+ CHECK(default_ == NULL);
+ default_ = new tray::BluetoothDefaultView(
+ this, status != user::LOGGED_IN_LOCKED);
+ return default_;
+}
+
+views::View* TrayBluetooth::CreateDetailedView(user::LoginStatus status) {
+ if (!Shell::GetInstance()->system_tray_delegate()->GetBluetoothAvailable())
+ return NULL;
+ CHECK(detailed_ == NULL);
+ detailed_ = new tray::BluetoothDetailedView(this, status);
+ return detailed_;
+}
+
+void TrayBluetooth::DestroyTrayView() {
+}
+
+void TrayBluetooth::DestroyDefaultView() {
+ default_ = NULL;
+}
+
+void TrayBluetooth::DestroyDetailedView() {
+ detailed_ = NULL;
+}
+
+void TrayBluetooth::UpdateAfterLoginStatusChange(user::LoginStatus status) {
+}
+
+void TrayBluetooth::OnBluetoothRefresh() {
+ if (default_)
+ default_->UpdateLabel();
+ else if (detailed_)
+ detailed_->Update();
+}
+
+void TrayBluetooth::OnBluetoothDiscoveringChanged() {
+ if (!detailed_)
+ return;
+ detailed_->Update();
+}
+
+} // namespace internal
+} // namespace ash