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 "device/bluetooth/bluetooth_device.h"
6
7#include <string>
8
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "device/bluetooth/bluetooth_gatt_service.h"
12#include "grit/device_bluetooth_strings.h"
13#include "ui/base/l10n/l10n_util.h"
14
15namespace device {
16
17BluetoothDevice::BluetoothDevice() {
18}
19
20BluetoothDevice::~BluetoothDevice() {
21  STLDeleteValues(&gatt_services_);
22}
23
24base::string16 BluetoothDevice::GetName() const {
25  std::string name = GetDeviceName();
26  if (!name.empty()) {
27    return base::UTF8ToUTF16(name);
28  } else {
29    return GetAddressWithLocalizedDeviceTypeName();
30  }
31}
32
33base::string16 BluetoothDevice::GetAddressWithLocalizedDeviceTypeName() const {
34  base::string16 address_utf16 = base::UTF8ToUTF16(GetAddress());
35  BluetoothDevice::DeviceType device_type = GetDeviceType();
36  switch (device_type) {
37    case DEVICE_COMPUTER:
38      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_COMPUTER,
39                                        address_utf16);
40    case DEVICE_PHONE:
41      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_PHONE,
42                                        address_utf16);
43    case DEVICE_MODEM:
44      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MODEM,
45                                        address_utf16);
46    case DEVICE_AUDIO:
47      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_AUDIO,
48                                        address_utf16);
49    case DEVICE_CAR_AUDIO:
50      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_CAR_AUDIO,
51                                        address_utf16);
52    case DEVICE_VIDEO:
53      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_VIDEO,
54                                        address_utf16);
55    case DEVICE_JOYSTICK:
56      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_JOYSTICK,
57                                        address_utf16);
58    case DEVICE_GAMEPAD:
59      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_GAMEPAD,
60                                        address_utf16);
61    case DEVICE_KEYBOARD:
62      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_KEYBOARD,
63                                        address_utf16);
64    case DEVICE_MOUSE:
65      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MOUSE,
66                                        address_utf16);
67    case DEVICE_TABLET:
68      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_TABLET,
69                                        address_utf16);
70    case DEVICE_KEYBOARD_MOUSE_COMBO:
71      return l10n_util::GetStringFUTF16(
72          IDS_BLUETOOTH_DEVICE_KEYBOARD_MOUSE_COMBO, address_utf16);
73    default:
74      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_UNKNOWN,
75                                        address_utf16);
76  }
77}
78
79BluetoothDevice::DeviceType BluetoothDevice::GetDeviceType() const {
80  // https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
81  uint32 bluetooth_class = GetBluetoothClass();
82  switch ((bluetooth_class & 0x1f00) >> 8) {
83    case 0x01:
84      // Computer major device class.
85      return DEVICE_COMPUTER;
86    case 0x02:
87      // Phone major device class.
88      switch ((bluetooth_class & 0xfc) >> 2) {
89        case 0x01:
90        case 0x02:
91        case 0x03:
92          // Cellular, cordless and smart phones.
93          return DEVICE_PHONE;
94        case 0x04:
95        case 0x05:
96          // Modems: wired or voice gateway and common ISDN access.
97          return DEVICE_MODEM;
98      }
99      break;
100    case 0x04:
101      // Audio major device class.
102      switch ((bluetooth_class & 0xfc) >> 2) {
103        case 0x08:
104          // Car audio.
105          return DEVICE_CAR_AUDIO;
106        case 0x0b:
107        case 0x0c:
108        case 0x0d:
109        case 0x0e:
110        case 0x0f:
111        case 0x010:
112          // Video devices.
113          return DEVICE_VIDEO;
114        default:
115          return DEVICE_AUDIO;
116      }
117      break;
118    case 0x05:
119      // Peripheral major device class.
120      switch ((bluetooth_class & 0xc0) >> 6) {
121        case 0x00:
122          // "Not a keyboard or pointing device."
123          switch ((bluetooth_class & 0x01e) >> 2) {
124            case 0x01:
125              // Joystick.
126              return DEVICE_JOYSTICK;
127            case 0x02:
128              // Gamepad.
129              return DEVICE_GAMEPAD;
130            default:
131              return DEVICE_PERIPHERAL;
132          }
133          break;
134        case 0x01:
135          // Keyboard.
136          return DEVICE_KEYBOARD;
137        case 0x02:
138          // Pointing device.
139          switch ((bluetooth_class & 0x01e) >> 2) {
140            case 0x05:
141              // Digitizer tablet.
142              return DEVICE_TABLET;
143            default:
144              // Mouse.
145              return DEVICE_MOUSE;
146          }
147          break;
148        case 0x03:
149          // Combo device.
150          return DEVICE_KEYBOARD_MOUSE_COMBO;
151      }
152      break;
153  }
154
155  return DEVICE_UNKNOWN;
156}
157
158bool BluetoothDevice::IsPairable() const {
159  DeviceType type = GetDeviceType();
160
161  // Get the vendor part of the address: "00:11:22" for "00:11:22:33:44:55"
162  std::string vendor = GetAddress().substr(0, 8);
163
164  // Verbatim "Bluetooth Mouse", model 96674
165  if (type == DEVICE_MOUSE && vendor == "00:12:A1")
166    return false;
167  // Microsoft "Microsoft Bluetooth Notebook Mouse 5000", model X807028-001
168  if (type == DEVICE_MOUSE && vendor == "7C:ED:8D")
169    return false;
170  // Sony PlayStation Dualshock3
171  if (IsTrustable())
172    return false;
173
174  // TODO: Move this database into a config file.
175
176  return true;
177}
178
179bool BluetoothDevice::IsTrustable() const {
180  // Sony PlayStation Dualshock3
181  if ((GetVendorID() == 0x054c && GetProductID() == 0x0268 &&
182       GetDeviceName() == "PLAYSTATION(R)3 Controller"))
183    return true;
184
185  return false;
186}
187
188std::vector<BluetoothGattService*>
189    BluetoothDevice::GetGattServices() const {
190  std::vector<BluetoothGattService*> services;
191  for (GattServiceMap::const_iterator iter = gatt_services_.begin();
192       iter != gatt_services_.end(); ++iter)
193    services.push_back(iter->second);
194  return services;
195}
196
197BluetoothGattService* BluetoothDevice::GetGattService(
198    const std::string& identifier) const {
199  GattServiceMap::const_iterator iter = gatt_services_.find(identifier);
200  if (iter != gatt_services_.end())
201    return iter->second;
202  return NULL;
203}
204
205// static
206std::string BluetoothDevice::CanonicalizeAddress(const std::string& address) {
207  std::string canonicalized = address;
208  if (address.size() == 12) {
209    // Might be an address in the format "1A2B3C4D5E6F". Add separators.
210    for (size_t i = 2; i < canonicalized.size(); i += 3) {
211      canonicalized.insert(i, ":");
212    }
213  }
214
215  // Verify that the length matches the canonical format "1A:2B:3C:4D:5E:6F".
216  const size_t kCanonicalAddressLength = 17;
217  if (canonicalized.size() != kCanonicalAddressLength)
218    return std::string();
219
220  const char separator = canonicalized[2];
221  for (size_t i = 0; i < canonicalized.size(); ++i) {
222    bool is_separator = (i + 1) % 3 == 0;
223    if (is_separator) {
224      // All separators in the input |address| should be consistent.
225      if (canonicalized[i] != separator)
226        return std::string();
227
228      canonicalized[i] = ':';
229    } else {
230      if (!IsHexDigit(canonicalized[i]))
231        return std::string();
232
233      canonicalized[i] = base::ToUpperASCII(canonicalized[i]);
234    }
235  }
236
237  return canonicalized;
238}
239
240}  // namespace device
241