1e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//
2e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  Copyright (C) 2015 Google, Inc.
3e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//
4e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  Licensed under the Apache License, Version 2.0 (the "License");
5e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  you may not use this file except in compliance with the License.
6e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  You may obtain a copy of the License at:
7e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//
8e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  http://www.apache.org/licenses/LICENSE-2.0
9e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//
10e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  Unless required by applicable law or agreed to in writing, software
11e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  distributed under the License is distributed on an "AS IS" BASIS,
12e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  See the License for the specific language governing permissions and
14e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//  limitations under the License.
15e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray//
161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/bind.h>
171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/location.h>
18e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray#include <base/logging.h>
191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray#include <base/rand_util.h>
20e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
2167d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski#include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
2267d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski#include <android/bluetooth/IBluetoothLeAdvertiser.h>
23234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray#include <bluetooth/low_energy_constants.h>
24234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray
25e2eeff4f7f149c59ea8cb67392f287317f40f9bdJack He#include "constants.h"
26e2eeff4f7f149c59ea8cb67392f287317f40f9bdJack He#include "heart_rate_server.h"
27e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
28a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::binder::Status;
29a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::String8;
30a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::String16;
31a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
3267d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowskiusing android::bluetooth::IBluetoothLeAdvertiser;
33a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowskiusing android::bluetooth::BluetoothGattService;
34a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
35e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguraynamespace heart_rate {
36e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
3767d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowskiclass CLIBluetoothLeAdvertiserCallback
3867d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski    : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
39032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski public:
40911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  explicit CLIBluetoothLeAdvertiserCallback(
41911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      android::sp<android::bluetooth::IBluetooth> bt)
42032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski      : bt_(bt) {}
43032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
4467d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski  // IBluetoothLeAdvertiserCallback overrides:
4567d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski  Status OnAdvertiserRegistered(int status, int advertiser_id) {
46032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    if (status != bluetooth::BLE_STATUS_SUCCESS) {
47911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      LOG(ERROR)
48911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson          << "Failed to register BLE advertiser, will not start advertising";
49a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      return Status::ok();
50032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    }
51032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
5267d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski    LOG(INFO) << "Registered BLE advertiser with ID: " << advertiser_id;
53032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
540ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski    String16 name_param;
550ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski    bt_->GetName(&name_param);
560ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski    std::string name(String8(name_param).string());
570ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski
580ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski    /* Advertising data: 16-bit Service UUID: Heart Rate Service, Tx power*/
59911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUUIDs,
60911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                              0x0D, 0x18,
61911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                              0x02, bluetooth::kEIRTypeTxPower,
62911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                              0x00};
630ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski    data.push_back(name.length() + 1);
640ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski    data.push_back(bluetooth::kEIRTypeCompleteLocalName);
65e3051fec0629b8b10812c2afbadb414bb6cf0629Jakub Pawlowski    data.insert(data.end(), name.c_str(), name.c_str() + name.length());
660ecddf398c92324e15a53c9d410646fd7a494b96Jakub Pawlowski
67032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    base::TimeDelta timeout;
68032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
69032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    bluetooth::AdvertiseSettings settings(
70a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski        bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
71a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski        bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, true);
72032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
73032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    bluetooth::AdvertiseData adv_data(data);
74032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    bluetooth::AdvertiseData scan_rsp;
75032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
7667d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski    android::sp<IBluetoothLeAdvertiser> ble;
7767d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski    bt_->GetLeAdvertiserInterface(&ble);
78a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool start_status;
7967d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski    ble->StartMultiAdvertising(advertiser_id, adv_data, scan_rsp, settings,
80a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                               &start_status);
81a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
82032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski  }
83032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
84a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnMultiAdvertiseCallback(
85a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      int status, bool is_start,
86a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      const android::bluetooth::AdvertiseSettings& /* settings */) {
87a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    LOG(INFO) << "Advertising" << (is_start ? " started" : " stopped");
88a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
89032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski  };
90032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
91032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski private:
92a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  android::sp<android::bluetooth::IBluetooth> bt_;
9367d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
94032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski};
95032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
961c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman UgurayHeartRateServer::HeartRateServer(
97a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    android::sp<android::bluetooth::IBluetooth> bluetooth,
98032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
99032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski    bool advertise)
1001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    : simulation_started_(false),
1011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray      bluetooth_(bluetooth),
1021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray      server_if_(-1),
1031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray      hr_notification_count_(0),
1041c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray      energy_expended_(0),
105032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski      advertise_(advertise),
1061c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray      main_task_runner_(main_task_runner),
1071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray      weak_ptr_factory_(this) {
108e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  CHECK(bluetooth_.get());
109e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray}
110e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
111e0fe387561141e049bb2fc748cacb0b56af4928fArman UgurayHeartRateServer::~HeartRateServer() {
112e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  std::lock_guard<std::mutex> lock(mutex_);
113a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (!gatt_.get() || server_if_ == -1) return;
114e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
115a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) return;
116e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
1171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Manually unregister ourselves from the daemon. It's good practice to do
1181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // this, even though the daemon will automatically unregister us if this
1191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // process exits.
120e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  gatt_->UnregisterServer(server_if_);
121e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray}
122e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
123e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguraybool HeartRateServer::Run(const RunCallback& callback) {
124e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  std::lock_guard<std::mutex> lock(mutex_);
125e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
126e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  if (pending_run_cb_) {
127e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    LOG(ERROR) << "Already started";
128e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    return false;
129e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  }
130e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
1311c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
132a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bluetooth_->GetGattServerInterface(&gatt_);
133e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  if (!gatt_.get()) {
134e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
135e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    return false;
136e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  }
137e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
1381c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Register this instance as a GATT server. If this call succeeds, we will
1391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // asynchronously receive a server ID via the OnServerRegistered callback.
140a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
141a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  gatt_->RegisterServer(this, &status);
142a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (!status) {
143e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    LOG(ERROR) << "Failed to register with the server interface";
144e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    return false;
145e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  }
146e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
147e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  pending_run_cb_ = callback;
148e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
149e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  return true;
150e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray}
151e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
1521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::ScheduleNextMeasurement() {
1531c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  main_task_runner_->PostDelayedTask(
154a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      FROM_HERE, base::Bind(&HeartRateServer::SendHeartRateMeasurement,
155a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                            weak_ptr_factory_.GetWeakPtr()),
1561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray      base::TimeDelta::FromSeconds(1));
1571c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray}
1581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1591c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::SendHeartRateMeasurement() {
1601c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::lock_guard<std::mutex> lock(mutex_);
1611c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1621c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Send a notification or indication to all enabled devices.
1631c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  bool found = false;
1641c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  for (const auto& iter : device_ccc_map_) {
1651c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    uint8_t ccc_val = iter.second;
1661c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
167a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    if (!ccc_val) continue;
1681c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1691c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    found = true;
1701c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1711c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    // Don't send a notification if one is already pending for this device.
172a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    if (pending_notification_map_[iter.first]) continue;
1731c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1741c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    std::vector<uint8_t> value;
1751c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    BuildHeartRateMeasurementValue(&value);
1761c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
177a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool status;
178a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    gatt_->SendNotification(server_if_, String16(String8(iter.first.c_str())),
179a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski                            hr_measurement_handle_, false, value, &status);
180a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    if (status) pending_notification_map_[iter.first] = true;
1811c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
1821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1831c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Still enabled!
1841c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (found) {
1851c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    ScheduleNextMeasurement();
1861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    return;
1871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
1881c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1891c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // All clients disabled notifications.
1901c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  simulation_started_ = false;
1911c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1921c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // TODO(armansito): We should keep track of closed connections here so that we
1931c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // don't send notifications to uninterested clients.
1941c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray}
1951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
1961c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Ugurayvoid HeartRateServer::BuildHeartRateMeasurementValue(
1971c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    std::vector<uint8_t>* out_value) {
1981c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  CHECK(out_value);  // Assert that |out_value| is not nullptr.
1991c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
2001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Default flags field. Here is what we put in there:
2011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  //   Bit 0: 0 - 8-bit Heart Rate value
2021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  //   Bits 1 & 2: 11 - Sensor contact feature supported and contact detected.
2031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected;
2041c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
2051c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Our demo's heart rate. Pick a value between 90 and 130.
2061c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  uint8_t heart_rate = base::RandInt(90, 130);
2071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
2081c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // On every tenth beat we include the Energy Expended value.
2091c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  bool include_ee = false;
2101c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (!(hr_notification_count_ % 10)) {
2111c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    include_ee = true;
2121c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    flags |= kHREnergyExpendedPresent;
2131c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
2141c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
2151c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  hr_notification_count_++;
2161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
2171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
2181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Add all the value bytes.
2191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  out_value->push_back(flags);
2201c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  out_value->push_back(heart_rate);
2211c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (include_ee) {
2221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    out_value->push_back(energy_expended_);
2231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    out_value->push_back(energy_expended_ >> 8);
2241c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
2251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray}
2261c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
227a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnServerRegistered(int status, int server_if) {
228e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  std::lock_guard<std::mutex> lock(mutex_);
229e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
230e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  if (status != bluetooth::BLE_STATUS_SUCCESS) {
231e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    LOG(ERROR) << "Failed to register GATT server";
232e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    pending_run_cb_(false);
233a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
234e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  }
235e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
2361c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Registration succeeded. Store our ID, as we need it for GATT server
2371c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // operations.
238e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  server_if_ = server_if;
239e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
240e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
241e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
242911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  bluetooth::Service hrService(
243911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      0, true, kHRServiceUUID,
244911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      {{0,
245911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        kHRMeasurementUUID,
246911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        bluetooth::kCharacteristicPropertyNotify,
247911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        0,
248911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        {{0, kCCCDescriptorUUID, (bluetooth::kAttributePermissionRead |
249911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                  bluetooth::kAttributePermissionWrite)}}},
250911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       {0,
251911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        kBodySensorLocationUUID,
252911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        bluetooth::kCharacteristicPropertyRead,
253911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        bluetooth::kAttributePermissionRead,
254911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        {}},
255911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson       {0,
256911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        kHRControlPointUUID,
257911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        bluetooth::kCharacteristicPropertyWrite,
258911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        bluetooth::kAttributePermissionWrite,
259911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        {}}},
260911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      {});
261e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
262a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  bool op_status = true;
263e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
264911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  Status stat = gatt_->AddService(server_if_, (BluetoothGattService)hrService,
265911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                  &op_status);
266a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  if (!stat.isOk()) {
267a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski    LOG(ERROR) << "Failed to add service, status is: " /*<< stat*/;
268e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    pending_run_cb_(false);
269a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
270e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  }
271e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
272a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (!op_status) {
273a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski    LOG(ERROR) << "Failed to add service";
274e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    pending_run_cb_(false);
275a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
276e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  }
277e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
278a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  LOG(INFO) << "Initiated AddService request";
279a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
280e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray}
281e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
282a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnServiceAdded(
283a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski    int status, const android::bluetooth::BluetoothGattService& service) {
284e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  std::lock_guard<std::mutex> lock(mutex_);
285e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
286e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  if (status != bluetooth::BLE_STATUS_SUCCESS) {
287e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    LOG(ERROR) << "Failed to add Heart Rate service";
288e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray    pending_run_cb_(false);
289a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
290e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  }
291e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
292a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  hr_service_handle_ = service.handle();
293a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  hr_measurement_handle_ = service.characteristics()[0].handle();
294a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  hr_measurement_cccd_handle_ =
295a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski      service.characteristics()[0].descriptors()[0].handle();
296a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  body_sensor_loc_handle_ = service.characteristics()[1].handle();
297a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  hr_control_point_handle_ = service.characteristics()[2].handle();
2981c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
299e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  LOG(INFO) << "Heart Rate service added";
300e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray  pending_run_cb_(true);
301032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
302032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski  if (advertise_) {
30367d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski    android::sp<IBluetoothLeAdvertiser> ble;
30467d5a2523314d9757b2472c3e828dbc1015df4feJakub Pawlowski    bluetooth_->GetLeAdvertiserInterface(&ble);
305a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool status;
306911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    ble->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(bluetooth_),
307911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                            &status);
308032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski  }
309032169c056dd414596c0eb0d39fd01fca67d4242Jakub Pawlowski
310a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
311e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray}
312e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray
313a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnCharacteristicReadRequest(
314a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    const String16& device_address, int request_id, int offset,
315a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski    bool /* is_long */, int handle) {
3161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::lock_guard<std::mutex> lock(mutex_);
3171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // This is where we handle an incoming characteristic read. Only the body
3191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // sensor location characteristic is readable.
320a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  CHECK(handle == body_sensor_loc_handle_);
3211c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::vector<uint8_t> value;
3231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
3241c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (offset > 1)
3251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    error = bluetooth::GATT_ERROR_INVALID_OFFSET;
3261c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  else if (offset == 0)
3271c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    value.push_back(kHRBodyLocationFoot);
3281c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
329a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
330a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
331a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                      value, &status);
332a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
333514bf6087093375351784b287cb29c5f4603273cArman Uguray}
334514bf6087093375351784b287cb29c5f4603273cArman Uguray
335911d1ae03efec2d54c3b1b605589d790d1745488Myles WatsonStatus HeartRateServer::OnDescriptorReadRequest(const String16& device_address,
336911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                                int request_id, int offset,
337911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                                bool /* is_long */,
338911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                                int handle) {
3391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::lock_guard<std::mutex> lock(mutex_);
3401c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3411c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // This is where we handle an incoming characteristic descriptor read. There
3421c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // is only one descriptor.
343a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  if (handle != hr_measurement_cccd_handle_) {
3441c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    std::vector<uint8_t> value;
345a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool status;
3461c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    gatt_->SendResponse(server_if_, device_address, request_id,
347a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, offset,
348a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        value, &status);
349a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
3501c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
3511c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // 16-bit value encoded as little-endian.
353a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  const uint8_t value_bytes[] = {
354a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      device_ccc_map_[std::string(String8(device_address).string())], 0x00};
3551c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::vector<uint8_t> value;
3571c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
3581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (offset > 2)
3591c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    error = bluetooth::GATT_ERROR_INVALID_OFFSET;
3601c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  else
3611c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
3621c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
363a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
364a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
365a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                      value, &status);
366a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
367514bf6087093375351784b287cb29c5f4603273cArman Uguray}
368514bf6087093375351784b287cb29c5f4603273cArman Uguray
369a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnCharacteristicWriteRequest(
370a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    const String16& device_address, int request_id, int offset,
371a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool is_prepare_write, bool need_response,
372a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski    const std::vector<uint8_t>& value, int handle) {
3731c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::lock_guard<std::mutex> lock(mutex_);
3741c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3751c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::vector<uint8_t> dummy;
3761c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3771c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // This is where we handle an incoming characteristic write. The Heart Rate
3781c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // service doesn't really support prepared writes, so we just reject them to
3791c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // keep things simple.
3801c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (is_prepare_write) {
381a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool status;
3821c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    gatt_->SendResponse(server_if_, device_address, request_id,
383a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
384a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        dummy, &status);
385a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
3861c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
3871c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3881c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Heart Rate Control point is the only writable characteristic.
389a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  CHECK(handle == hr_control_point_handle_);
3901c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
3911c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Writes to the Heart Rate Control Point characteristic must contain a single
3921c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // byte with the value 0x01.
3931c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (value.size() != 1 || value[0] != 0x01) {
394a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool status;
3951c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    gatt_->SendResponse(server_if_, device_address, request_id,
396a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        bluetooth::GATT_ERROR_OUT_OF_RANGE, offset, dummy,
397a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        &status);
398a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
3991c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
4001c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
4011c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
4021c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  energy_expended_ = 0;
4031c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
404a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (!need_response) return Status::ok();
4051c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
406a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
4071c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  gatt_->SendResponse(server_if_, device_address, request_id,
408a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                      bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
409a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
4104ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray}
4114ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray
412a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnDescriptorWriteRequest(
413a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    const String16& device_address, int request_id, int offset,
414a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool is_prepare_write, bool need_response,
415a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski    const std::vector<uint8_t>& value, int handle) {
4161c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::lock_guard<std::mutex> lock(mutex_);
4171c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
4181c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::vector<uint8_t> dummy;
4191c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
4201c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // This is where we handle an incoming characteristic write. The Heart Rate
4211c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // service doesn't really support prepared writes, so we just reject them to
4221c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // keep things simple.
4231c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (is_prepare_write) {
424a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool status;
4251c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    gatt_->SendResponse(server_if_, device_address, request_id,
426a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
427a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        dummy, &status);
428a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
4291c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
4301c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
4311c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // CCC is the only descriptor we have.
432a641b6fa2a25e1b5382945d13c4fa49d36084a78Jakub Pawlowski  CHECK(handle == hr_measurement_cccd_handle_);
4331c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
4341c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // CCC must contain 2 bytes for a 16-bit value in little-endian. The only
4351c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // allowed values here are 0x0000 and 0x0001.
4361c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) {
437a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    bool status;
4381c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    gatt_->SendResponse(server_if_, device_address, request_id,
4391c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray                        bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
440a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        offset, dummy, &status);
441a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
4421c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
4431c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
444a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  device_ccc_map_[std::string(String8(device_address).string())] = value[0];
4451c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
446a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  LOG(INFO) << "Heart Rate Measurement CCC written - device: " << device_address
447a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski            << " value: " << (int)value[0];
4481c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
4491c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // Start the simulation.
4501c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  if (!simulation_started_ && value[0]) {
4511c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    simulation_started_ = true;
4521c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray    ScheduleNextMeasurement();
4531c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  }
4541c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
455a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (!need_response) return Status::ok();
4561c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray
457a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
4581c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  gatt_->SendResponse(server_if_, device_address, request_id,
459a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                      bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
460a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
4614ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray}
4624ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray
463a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnExecuteWriteRequest(const String16& device_address,
464a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                                              int request_id,
465a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                                              bool /* is_execute */) {
4661c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  // We don't support Prepared Writes so, simply return Not Supported error.
4671c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::vector<uint8_t> dummy;
468a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
4691c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  gatt_->SendResponse(server_if_, device_address, request_id,
470a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                      bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy,
471a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                      &status);
472a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
473a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
4744ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray}
4754ebcbd9ede4006500c3ead0685befe0a8e4aadc2Arman Uguray
476a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub PawlowskiStatus HeartRateServer::OnNotificationSent(const String16& device_address,
477a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                                           int status) {
4781c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  LOG(INFO) << "Notification was sent - device: " << device_address
4791c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray            << " status: " << status;
4801c162dc31bad03ee21a93e5afb9c7a572bf21ec7Arman Uguray  std::lock_guard<std::mutex> lock(mutex_);
481a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  pending_notification_map_[std::string(String8(device_address).string())] =
482a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      false;
483a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
484a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  return Status::ok();
485cd644e3c54a4321b7626b52531c59f88e24e87beArman Uguray}
486cd644e3c54a4321b7626b52531c59f88e24e87beArman Uguray
4877932727cbe07b4bc176b2d1c04f0bcf350973512Jakub PawlowskiStatus HeartRateServer::OnConnectionStateChanged(const String16& device_address,
4887932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski                                                 bool connected) {
4897932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski  LOG(INFO) << "Connection state changed - device: " << device_address
490911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            << " connected: " << (connected ? "true" : "false");
4917932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski  return Status::ok();
4927932727cbe07b4bc176b2d1c04f0bcf350973512Jakub Pawlowski}
493e0fe387561141e049bb2fc748cacb0b56af4928fArman Uguray}  // namespace heart_rate
494