// 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 "device/bluetooth/bluetooth_device.h"
#include <string>
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "device/bluetooth/bluetooth_gatt_service.h"
#include "grit/device_bluetooth_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace device {
BluetoothDevice::BluetoothDevice() {
}
BluetoothDevice::~BluetoothDevice() {
STLDeleteValues(&gatt_services_);
}
base::string16 BluetoothDevice::GetName() const {
std::string name = GetDeviceName();
if (!name.empty()) {
return base::UTF8ToUTF16(name);
} else {
return GetAddressWithLocalizedDeviceTypeName();
}
}
base::string16 BluetoothDevice::GetAddressWithLocalizedDeviceTypeName() const {
base::string16 address_utf16 = base::UTF8ToUTF16(GetAddress());
BluetoothDevice::DeviceType device_type = GetDeviceType();
switch (device_type) {
case DEVICE_COMPUTER:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_COMPUTER,
address_utf16);
case DEVICE_PHONE:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_PHONE,
address_utf16);
case DEVICE_MODEM:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MODEM,
address_utf16);
case DEVICE_AUDIO:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_AUDIO,
address_utf16);
case DEVICE_CAR_AUDIO:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_CAR_AUDIO,
address_utf16);
case DEVICE_VIDEO:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_VIDEO,
address_utf16);
case DEVICE_JOYSTICK:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_JOYSTICK,
address_utf16);
case DEVICE_GAMEPAD:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_GAMEPAD,
address_utf16);
case DEVICE_KEYBOARD:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_KEYBOARD,
address_utf16);
case DEVICE_MOUSE:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MOUSE,
address_utf16);
case DEVICE_TABLET:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_TABLET,
address_utf16);
case DEVICE_KEYBOARD_MOUSE_COMBO:
return l10n_util::GetStringFUTF16(
IDS_BLUETOOTH_DEVICE_KEYBOARD_MOUSE_COMBO, address_utf16);
default:
return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_UNKNOWN,
address_utf16);
}
}
BluetoothDevice::DeviceType BluetoothDevice::GetDeviceType() const {
// https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
uint32 bluetooth_class = GetBluetoothClass();
switch ((bluetooth_class & 0x1f00) >> 8) {
case 0x01:
// Computer major device class.
return DEVICE_COMPUTER;
case 0x02:
// Phone major device class.
switch ((bluetooth_class & 0xfc) >> 2) {
case 0x01:
case 0x02:
case 0x03:
// Cellular, cordless and smart phones.
return DEVICE_PHONE;
case 0x04:
case 0x05:
// Modems: wired or voice gateway and common ISDN access.
return DEVICE_MODEM;
}
break;
case 0x04:
// Audio major device class.
switch ((bluetooth_class & 0xfc) >> 2) {
case 0x08:
// Car audio.
return DEVICE_CAR_AUDIO;
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
case 0x010:
// Video devices.
return DEVICE_VIDEO;
default:
return DEVICE_AUDIO;
}
break;
case 0x05:
// Peripheral major device class.
switch ((bluetooth_class & 0xc0) >> 6) {
case 0x00:
// "Not a keyboard or pointing device."
switch ((bluetooth_class & 0x01e) >> 2) {
case 0x01:
// Joystick.
return DEVICE_JOYSTICK;
case 0x02:
// Gamepad.
return DEVICE_GAMEPAD;
default:
return DEVICE_PERIPHERAL;
}
break;
case 0x01:
// Keyboard.
return DEVICE_KEYBOARD;
case 0x02:
// Pointing device.
switch ((bluetooth_class & 0x01e) >> 2) {
case 0x05:
// Digitizer tablet.
return DEVICE_TABLET;
default:
// Mouse.
return DEVICE_MOUSE;
}
break;
case 0x03:
// Combo device.
return DEVICE_KEYBOARD_MOUSE_COMBO;
}
break;
}
return DEVICE_UNKNOWN;
}
bool BluetoothDevice::IsPairable() const {
DeviceType type = GetDeviceType();
// Get the vendor part of the address: "00:11:22" for "00:11:22:33:44:55"
std::string vendor = GetAddress().substr(0, 8);
// Verbatim "Bluetooth Mouse", model 96674
if (type == DEVICE_MOUSE && vendor == "00:12:A1")
return false;
// Microsoft "Microsoft Bluetooth Notebook Mouse 5000", model X807028-001
if (type == DEVICE_MOUSE && vendor == "7C:ED:8D")
return false;
// Sony PlayStation Dualshock3
if (IsTrustable())
return false;
// TODO: Move this database into a config file.
return true;
}
bool BluetoothDevice::IsTrustable() const {
// Sony PlayStation Dualshock3
if ((GetVendorID() == 0x054c && GetProductID() == 0x0268 &&
GetDeviceName() == "PLAYSTATION(R)3 Controller"))
return true;
return false;
}
std::vector<BluetoothGattService*>
BluetoothDevice::GetGattServices() const {
std::vector<BluetoothGattService*> services;
for (GattServiceMap::const_iterator iter = gatt_services_.begin();
iter != gatt_services_.end(); ++iter)
services.push_back(iter->second);
return services;
}
BluetoothGattService* BluetoothDevice::GetGattService(
const std::string& identifier) const {
GattServiceMap::const_iterator iter = gatt_services_.find(identifier);
if (iter != gatt_services_.end())
return iter->second;
return NULL;
}
// static
std::string BluetoothDevice::CanonicalizeAddress(const std::string& address) {
std::string canonicalized = address;
if (address.size() == 12) {
// Might be an address in the format "1A2B3C4D5E6F". Add separators.
for (size_t i = 2; i < canonicalized.size(); i += 3) {
canonicalized.insert(i, ":");
}
}
// Verify that the length matches the canonical format "1A:2B:3C:4D:5E:6F".
const size_t kCanonicalAddressLength = 17;
if (canonicalized.size() != kCanonicalAddressLength)
return std::string();
const char separator = canonicalized[2];
for (size_t i = 0; i < canonicalized.size(); ++i) {
bool is_separator = (i + 1) % 3 == 0;
if (is_separator) {
// All separators in the input |address| should be consistent.
if (canonicalized[i] != separator)
return std::string();
canonicalized[i] = ':';
} else {
if (!IsHexDigit(canonicalized[i]))
return std::string();
canonicalized[i] = base::ToUpperASCII(canonicalized[i]);
}
}
return canonicalized;
}
} // namespace device