15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "device/bluetooth/bluetooth_device.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/strings/string_util.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "device/bluetooth/bluetooth_gatt_service.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/device_bluetooth_strings.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace device {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)BluetoothDevice::BluetoothDevice() {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BluetoothDevice::~BluetoothDevice() {
21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  STLDeleteValues(&gatt_services_);
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 BluetoothDevice::GetName() const {
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string name = GetDeviceName();
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!name.empty()) {
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::UTF8ToUTF16(name);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetAddressWithLocalizedDeviceTypeName();
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 BluetoothDevice::GetAddressWithLocalizedDeviceTypeName() const {
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 address_utf16 = base::UTF8ToUTF16(GetAddress());
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BluetoothDevice::DeviceType device_type = GetDeviceType();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (device_type) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_COMPUTER:
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_COMPUTER,
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_PHONE:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_PHONE,
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_MODEM:
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MODEM,
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_AUDIO:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_AUDIO,
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_CAR_AUDIO:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_CAR_AUDIO,
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_VIDEO:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_VIDEO,
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_JOYSTICK:
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_JOYSTICK,
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_GAMEPAD:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_GAMEPAD,
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_KEYBOARD:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_KEYBOARD,
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_MOUSE:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MOUSE,
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_TABLET:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_TABLET,
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DEVICE_KEYBOARD_MOUSE_COMBO:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringFUTF16(
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          IDS_BLUETOOTH_DEVICE_KEYBOARD_MOUSE_COMBO, address_utf16);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_UNKNOWN,
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        address_utf16);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BluetoothDevice::DeviceType BluetoothDevice::GetDeviceType() const {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  uint32 bluetooth_class = GetBluetoothClass();
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch ((bluetooth_class & 0x1f00) >> 8) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 0x01:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Computer major device class.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return DEVICE_COMPUTER;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 0x02:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Phone major device class.
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      switch ((bluetooth_class & 0xfc) >> 2) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x01:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x02:
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x03:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Cellular, cordless and smart phones.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return DEVICE_PHONE;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x04:
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x05:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Modems: wired or voice gateway and common ISDN access.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return DEVICE_MODEM;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 0x04:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Audio major device class.
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      switch ((bluetooth_class & 0xfc) >> 2) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x08:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Car audio.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return DEVICE_CAR_AUDIO;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x0b:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x0c:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x0d:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x0e:
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x0f:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x010:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Video devices.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return DEVICE_VIDEO;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return DEVICE_AUDIO;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 0x05:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Peripheral major device class.
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      switch ((bluetooth_class & 0xc0) >> 6) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x00:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // "Not a keyboard or pointing device."
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          switch ((bluetooth_class & 0x01e) >> 2) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case 0x01:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // Joystick.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              return DEVICE_JOYSTICK;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case 0x02:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // Gamepad.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              return DEVICE_GAMEPAD;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              return DEVICE_PERIPHERAL;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x01:
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Keyboard.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return DEVICE_KEYBOARD;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x02:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Pointing device.
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          switch ((bluetooth_class & 0x01e) >> 2) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case 0x05:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // Digitizer tablet.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              return DEVICE_TABLET;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // Mouse.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              return DEVICE_MOUSE;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0x03:
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Combo device.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return DEVICE_KEYBOARD_MOUSE_COMBO;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DEVICE_UNKNOWN;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool BluetoothDevice::IsPairable() const {
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeviceType type = GetDeviceType();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Get the vendor part of the address: "00:11:22" for "00:11:22:33:44:55"
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string vendor = GetAddress().substr(0, 8);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Verbatim "Bluetooth Mouse", model 96674
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (type == DEVICE_MOUSE && vendor == "00:12:A1")
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Microsoft "Microsoft Bluetooth Notebook Mouse 5000", model X807028-001
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (type == DEVICE_MOUSE && vendor == "7C:ED:8D")
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Sony PlayStation Dualshock3
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (IsTrustable())
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO: Move this database into a config file.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool BluetoothDevice::IsTrustable() const {
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Sony PlayStation Dualshock3
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if ((GetVendorID() == 0x054c && GetProductID() == 0x0268 &&
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       GetDeviceName() == "PLAYSTATION(R)3 Controller"))
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return true;
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return false;
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
188c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstd::vector<BluetoothGattService*>
189c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    BluetoothDevice::GetGattServices() const {
190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<BluetoothGattService*> services;
191c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (GattServiceMap::const_iterator iter = gatt_services_.begin();
192c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       iter != gatt_services_.end(); ++iter)
193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    services.push_back(iter->second);
194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return services;
195c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
196c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothGattService* BluetoothDevice::GetGattService(
198c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& identifier) const {
199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GattServiceMap::const_iterator iter = gatt_services_.find(identifier);
200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (iter != gatt_services_.end())
201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return iter->second;
202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return NULL;
203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
204c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)std::string BluetoothDevice::CanonicalizeAddress(const std::string& address) {
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string canonicalized = address;
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (address.size() == 12) {
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Might be an address in the format "1A2B3C4D5E6F". Add separators.
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (size_t i = 2; i < canonicalized.size(); i += 3) {
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      canonicalized.insert(i, ":");
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Verify that the length matches the canonical format "1A:2B:3C:4D:5E:6F".
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const size_t kCanonicalAddressLength = 17;
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (canonicalized.size() != kCanonicalAddressLength)
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return std::string();
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const char separator = canonicalized[2];
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (size_t i = 0; i < canonicalized.size(); ++i) {
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool is_separator = (i + 1) % 3 == 0;
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (is_separator) {
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // All separators in the input |address| should be consistent.
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (canonicalized[i] != separator)
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return std::string();
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      canonicalized[i] = ':';
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (!IsHexDigit(canonicalized[i]))
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return std::string();
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      canonicalized[i] = base::ToUpperASCII(canonicalized[i]);
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return canonicalized;
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace device
241