main.cc revision a4bd0d2370bd469942e92e724cfc9c7c01d3da74
1f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//
2f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  Copyright (C) 2015 Google, Inc.
3f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//
4f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  Licensed under the Apache License, Version 2.0 (the "License");
5f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  you may not use this file except in compliance with the License.
6f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  You may obtain a copy of the License at:
7f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//
8f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  http://www.apache.org/licenses/LICENSE-2.0
9f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//
10f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  Unless required by applicable law or agreed to in writing, software
11f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  distributed under the License is distributed on an "AS IS" BASIS,
12f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  See the License for the specific language governing permissions and
14f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//  limitations under the License.
15f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray//
16f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
17fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray#include <iostream>
18fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray#include <string>
19fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
201377f938abf30ab3104571fb8372c657e65237d0Pavlin Radoslavov#ifdef BT_LIBCHROME_NDEBUG
211377f938abf30ab3104571fb8372c657e65237d0Pavlin Radoslavov#define NDEBUG 1
221377f938abf30ab3104571fb8372c657e65237d0Pavlin Radoslavov#endif
231377f938abf30ab3104571fb8372c657e65237d0Pavlin Radoslavov
24ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray#include <base/at_exit.h>
25ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray#include <base/command_line.h>
26f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray#include <base/logging.h>
2739a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray#include <base/macros.h>
28ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski#include <base/strings/string_number_conversions.h>
295192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray#include <base/strings/string_split.h>
305192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray#include <base/strings/string_util.h>
312e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray#include <binder/IPCThreadState.h>
32a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#include <binder/IServiceManager.h>
3339a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray#include <binder/ProcessState.h>
34f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
35234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray#include <bluetooth/adapter_state.h>
36a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#include <android/bluetooth/BnBluetoothCallback.h>
37a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#include <android/bluetooth/BnBluetoothGattClientCallback.h>
38a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#include <android/bluetooth/BnBluetoothLowEnergyCallback.h>
39a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#include <android/bluetooth/IBluetooth.h>
40a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#include <android/bluetooth/IBluetoothGattClient.h>
41a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#include <android/bluetooth/IBluetoothLowEnergy.h>
42234138e2606dd7a54fbcc540643511abc0a3598dArman Uguray#include <bluetooth/low_energy_constants.h>
43ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski#include <bluetooth/scan_filter.h>
44ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski#include <bluetooth/scan_settings.h>
4587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray#include <bluetooth/uuid.h>
46f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
47fcf2e0391950a8b140082fbe78688fa89471fbedArman Ugurayusing namespace std;
48fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
49f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Ugurayusing android::sp;
50a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::String8;
51a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::String16;
52a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::binder::Status;
53a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::OK;
54a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::getService;
55f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
56a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::bluetooth::IBluetooth;
57a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::bluetooth::IBluetoothGattClient;
58a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiusing android::bluetooth::IBluetoothLowEnergy;
59f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
602117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguraynamespace {
612117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray
62a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_OFF "\x1B[0m"
63a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_RED "\x1B[0;91m"
64a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_GREEN "\x1B[0;92m"
65a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_YELLOW "\x1B[0;93m"
66a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_BLUE "\x1B[0;94m"
67a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_MAGENTA "\x1B[0;95m"
68a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_BOLDGRAY "\x1B[1;30m"
69a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_BOLDWHITE "\x1B[1;37m"
70a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define COLOR_BOLDYELLOW "\x1B[1;93m"
71a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski#define CLEAR_LINE "\x1B[2K"
72fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
735192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray#define CHECK_ARGS_COUNT(args, op, num, msg) \
74a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (!(args.size() op num)) {               \
75a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    PrintError(msg);                         \
76a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return;                                  \
775192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  }
785192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray#define CHECK_NO_ARGS(args) \
795192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_ARGS_COUNT(args, ==, 0, "Expected no arguments")
805192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
8139a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray// TODO(armansito): Clean up this code. Right now everything is in this
8239a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray// monolithic file. We should organize this into different classes for command
8339a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray// handling, console output/printing, callback handling, etc.
8439a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray// (See http://b/23387611)
8539a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
8639a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray// Used to synchronize the printing of the command-line prompt and incoming
8739a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray// Binder callbacks.
8839a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguraystd::atomic_bool showing_prompt(false);
8939a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
902e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray// The registered IBluetoothLowEnergy client handle. If |ble_registering| is
912e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray// true then an operation to register the client is in progress.
922e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguraystd::atomic_bool ble_registering(false);
934fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguraystd::atomic_int ble_client_id(0);
944fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
954fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray// The registered IBluetoothGattClient client handle. If |gatt_registering| is
964fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray// true then an operation to register the client is in progress.
974fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguraystd::atomic_bool gatt_registering(false);
984fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguraystd::atomic_int gatt_client_id(0);
992e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
100ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski// True if we should dump the scan record bytes for incoming scan results.
101ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowskistd::atomic_bool dump_scan_record(false);
102ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
1032e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray// True if the remote process has died and we should exit.
1042e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguraystd::atomic_bool should_exit(false);
1052e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
106a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskistd::string kServiceName = "bluetooth-service";
107a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
108a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskivoid PrintPrompt() { cout << COLOR_BLUE "[FCLI] " COLOR_OFF << flush; }
10939a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
1102e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayvoid PrintError(const string& message) {
1112e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  cout << COLOR_RED << message << COLOR_OFF << endl;
1122e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray}
1132e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
114d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Ugurayvoid PrintOpStatus(const std::string& op, bool status) {
115d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  cout << COLOR_BOLDWHITE << op << " status: " COLOR_OFF
116d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray       << (status ? (COLOR_GREEN "success") : (COLOR_RED "failure"))
11764401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski       << COLOR_OFF << endl;
11864401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski}
11964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski
12064401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowskiinline void BeginAsyncOut() {
121a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (showing_prompt.load()) cout << CLEAR_LINE << "\r";
12264401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski}
12364401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski
12464401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowskiinline void EndAsyncOut() {
12564401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski  std::flush(cout);
12664401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski  if (showing_prompt.load())
127a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    PrintPrompt();
12864401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski  else
12964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    cout << endl;
130d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray}
131d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
132a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskiclass CLIBluetoothCallback : public android::bluetooth::BnBluetoothCallback {
13339a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray public:
13439a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  CLIBluetoothCallback() = default;
13539a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  ~CLIBluetoothCallback() override = default;
13639a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
1372e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  // IBluetoothCallback overrides:
138a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnBluetoothStateChange(int32_t prev_state,
139a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                                int32_t new_state) override {
14064401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
141a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    cout << COLOR_BOLDWHITE "Adapter state changed: " COLOR_OFF << COLOR_MAGENTA
142a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski         << AdapterStateToString(bluetooth::AdapterState(prev_state))
143a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski         << COLOR_OFF << COLOR_BOLDWHITE " -> " COLOR_OFF << COLOR_BOLDYELLOW
144a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski         << AdapterStateToString(bluetooth::AdapterState(new_state))
145a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski         << COLOR_OFF;
14664401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
147a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
148a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
149a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  }
15039a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
15139a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray private:
15239a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
15339a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray};
15439a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
1552e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayclass CLIBluetoothLowEnergyCallback
156a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    : public android::bluetooth::BnBluetoothLowEnergyCallback {
1572e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray public:
1582e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  CLIBluetoothLowEnergyCallback() = default;
1594fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  ~CLIBluetoothLowEnergyCallback() override = default;
1602e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
1612e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  // IBluetoothLowEnergyCallback overrides:
162a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnClientRegistered(int status, int client_id) override {
16364401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
1642e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    if (status != bluetooth::BLE_STATUS_SUCCESS) {
1652e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray      PrintError("Failed to register BLE client");
1662e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    } else {
1674fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray      ble_client_id = client_id;
1682e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray      cout << COLOR_BOLDWHITE "Registered BLE client with ID: " COLOR_OFF
16964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski           << COLOR_GREEN << client_id << COLOR_OFF;
1702e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    }
17164401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
1722e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
1732e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    ble_registering = false;
174a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
1752e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
1762e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
177a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnConnectionState(int status, int client_id, const String16& address,
178a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                           bool connected) override {
17964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
180a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    cout << COLOR_BOLDWHITE "Connection state: " << COLOR_BOLDYELLOW "["
181a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski         << address << " connected: " << (connected ? "true" : "false") << " ] "
182608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski         << COLOR_BOLDWHITE "- status: " << status
183608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski         << COLOR_BOLDWHITE " - client_id: " << client_id << COLOR_OFF;
18464401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
185a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
186455dc8f535a719af6a65a7512d90f9db878f5a58Jakub Pawlowski  }
187455dc8f535a719af6a65a7512d90f9db878f5a58Jakub Pawlowski
188a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnMtuChanged(int status, const String16& address, int mtu) override {
18964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
190a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    cout << COLOR_BOLDWHITE "MTU changed: " << COLOR_BOLDYELLOW "[" << address
191a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski         << " ] " << COLOR_BOLDWHITE " - status: " << status
192a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski         << COLOR_BOLDWHITE " - mtu: " << mtu << COLOR_OFF;
19364401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
194a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
195a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  }
196a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
197a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnScanResult(
198a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      const android::bluetooth::ScanResult& scan_result) override {
19964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
200a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    cout << COLOR_BOLDWHITE "Scan result: " << COLOR_BOLDYELLOW "["
201a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski         << scan_result.device_address() << "] "
202ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski         << COLOR_BOLDWHITE "- RSSI: " << scan_result.rssi() << COLOR_OFF;
203ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
204ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    if (dump_scan_record) {
205ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      cout << " - Record: "
206ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski           << base::HexEncode(scan_result.scan_record().data(),
207ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski                              scan_result.scan_record().size());
208ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    }
20964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
210a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
211ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
212ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
213a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnMultiAdvertiseCallback(
21452bfc6060cec652a67c8989e0548225af0008be1Arman Uguray      int status, bool is_start,
215a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      const android::bluetooth::AdvertiseSettings& /* settings */) {
21664401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
217d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    std::string op = is_start ? "start" : "stop";
218d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
219d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintOpStatus("Advertising " + op, status == bluetooth::BLE_STATUS_SUCCESS);
22064401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
221a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
22252bfc6060cec652a67c8989e0548225af0008be1Arman Uguray  }
22352bfc6060cec652a67c8989e0548225af0008be1Arman Uguray
2242e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray private:
2252e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
2262e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray};
2275192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
2284fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Ugurayclass CLIGattClientCallback
229a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    : public android::bluetooth::BnBluetoothGattClientCallback {
2304fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray public:
2314fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  CLIGattClientCallback() = default;
2324fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  ~CLIGattClientCallback() override = default;
2334fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
2344fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  // IBluetoothGattClientCallback overrides:
235a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  Status OnClientRegistered(int status, int client_id) override {
23664401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
2374fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    if (status != bluetooth::BLE_STATUS_SUCCESS) {
2384fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray      PrintError("Failed to register GATT client");
2394fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    } else {
2404fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray      gatt_client_id = client_id;
2414fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray      cout << COLOR_BOLDWHITE "Registered GATT client with ID: " COLOR_OFF
24264401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski           << COLOR_GREEN << client_id << COLOR_OFF;
2434fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    }
24464401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
2454fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
2464fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    gatt_registering = false;
247a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    return Status::ok();
2484fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
2494fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
2504fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray private:
2514fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  DISALLOW_COPY_AND_ASSIGN(CLIGattClientCallback);
2524fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray};
2534fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
254a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowskivoid PrintCommandStatus(bool status) { PrintOpStatus("Command", status); }
255fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
2565192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid PrintFieldAndValue(const string& field, const string& value) {
2575192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  cout << COLOR_BOLDWHITE << field << ": " << COLOR_BOLDYELLOW << value
2585192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray       << COLOR_OFF << endl;
2595192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
2605192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
2615192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid PrintFieldAndBoolValue(const string& field, bool value) {
2625192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  PrintFieldAndValue(field, (value ? "true" : "false"));
2635192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
2645192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
2655192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleDisable(IBluetooth* bt_iface, const vector<string>& args) {
2665192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
267a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
268a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->Disable(&status);
269a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintCommandStatus(status);
270fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray}
271fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
2725192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
2735192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
274a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
275a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->Enable(&status);
276a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintCommandStatus(status);
277fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray}
278fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
2795192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
2805192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
281a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
282a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  int32_t st;
283a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetState(&st);
284a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>(st);
2855192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state));
286fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray}
287fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
2885192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) {
2895192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
290a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool enabled;
291a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->IsEnabled(&enabled);
2925192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  PrintFieldAndBoolValue("Adapter enabled", enabled);
293fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray}
294fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
2955192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) {
2965192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
297a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 address;
298a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetAddress(&address);
299a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("Adapter address", std::string(String8(address).string()));
3005192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3015192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3025192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
3035192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_ARGS_COUNT(args, >=, 1, "No name was given");
3045192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3055192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  std::string name;
306a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  for (const auto& arg : args) name += arg + " ";
3075192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3085192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
3095192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
310a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
311a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->SetName(String16(String8(name.c_str())), &status);
312a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintCommandStatus(status);
3135192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3145192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3155192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
3165192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
317a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 name;
318a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetName(&name);
319a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("Adapter name", std::string(String8(name).string()));
3205192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3215192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3225192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) {
3235192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
3245192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3255192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl;
3265192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
327a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 address;
328a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetAddress(&address);
329a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("\tAddress", std::string(String8(address).string()));
330a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
331a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  int adapter_state;
332a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetState(&adapter_state);
333a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("\tState",
334a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                     bluetooth::AdapterStateToString(
335a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                         static_cast<bluetooth::AdapterState>(adapter_state)));
336a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
337a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 name;
338a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetName(&name);
339a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("\tName", std::string(String8(name).string()));
340a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
341a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool multi_adv;
342a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
343a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndBoolValue("\tMulti-Adv. supported", multi_adv);
34410b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray}
34510b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray
34610b54c4b7f1a863a27eca4158f256062ec9c3770Arman Ugurayvoid HandleSupportsMultiAdv(IBluetooth* bt_iface, const vector<string>& args) {
34710b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray  CHECK_NO_ARGS(args);
34810b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray
349a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool multi_adv;
350a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
351a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndBoolValue("Multi-advertisement support", multi_adv);
3525192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3535192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3542e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayvoid HandleRegisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
3552e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  CHECK_NO_ARGS(args);
3562e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3572e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (ble_registering.load()) {
3582e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("In progress");
3592e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3602e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3612e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3624fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (ble_client_id.load()) {
3632e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Already registered");
3642e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3652e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3662e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
367a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
368a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
3692e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (!ble_iface.get()) {
3702e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
3712e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3722e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3732e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
374a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
375a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->RegisterClient(new CLIBluetoothLowEnergyCallback(), &status);
376ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  ble_registering = status;
377ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  PrintCommandStatus(status);
3782e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray}
3792e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3802e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayvoid HandleUnregisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
3812e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  CHECK_NO_ARGS(args);
3822e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3834fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!ble_client_id.load()) {
3842e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Not registered");
3852e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3862e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3872e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
388a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
389a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
3902e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (!ble_iface.get()) {
3912e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
3922e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3932e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3942e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3954fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  ble_iface->UnregisterClient(ble_client_id.load());
3964fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  ble_client_id = 0;
3972e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  PrintCommandStatus(true);
3982e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray}
3992e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
4002e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayvoid HandleUnregisterAllBLE(IBluetooth* bt_iface, const vector<string>& args) {
4012e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  CHECK_NO_ARGS(args);
4022e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
403a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
404a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
4052e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (!ble_iface.get()) {
4062e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
4072e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
4082e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
4092e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
4102e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  ble_iface->UnregisterAll();
4112e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  PrintCommandStatus(true);
4122e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray}
4132e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
4144fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Ugurayvoid HandleRegisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
4154fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  CHECK_NO_ARGS(args);
4164fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4174fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (gatt_registering.load()) {
4184fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("In progress");
4194fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4204fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4214fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4224fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (gatt_client_id.load()) {
4234fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Already registered");
4244fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4254fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4264fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
427a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothGattClient> gatt_iface;
428a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetGattClientInterface(&gatt_iface);
4294fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!gatt_iface.get()) {
4304fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
4314fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4324fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4334fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
434a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
435a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  gatt_iface->RegisterClient(new CLIGattClientCallback(), &status);
4364fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  gatt_registering = status;
4374fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  PrintCommandStatus(status);
4384fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray}
4394fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4404fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Ugurayvoid HandleUnregisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
4414fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  CHECK_NO_ARGS(args);
4424fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4434fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!gatt_client_id.load()) {
4444fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Not registered");
4454fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4464fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4474fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
448a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothGattClient> gatt_iface;
449a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetGattClientInterface(&gatt_iface);
4504fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!gatt_iface.get()) {
4514fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
4524fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4534fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4544fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4554fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  gatt_iface->UnregisterClient(gatt_client_id.load());
4564fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  gatt_client_id = 0;
4574fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  PrintCommandStatus(true);
4584fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray}
4594fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
460d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Ugurayvoid HandleStartAdv(IBluetooth* bt_iface, const vector<string>& args) {
461d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool include_name = false;
462d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool include_tx_power = false;
463d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool connectable = false;
464d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool set_manufacturer_data = false;
46587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  bool set_uuid = false;
46687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  bluetooth::UUID uuid;
467d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
46887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  for (auto iter = args.begin(); iter != args.end(); ++iter) {
46987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    const std::string& arg = *iter;
470d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    if (arg == "-n")
471d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      include_name = true;
472d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    else if (arg == "-t")
473d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      include_tx_power = true;
474d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    else if (arg == "-c")
475d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      connectable = true;
476d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    else if (arg == "-m")
477d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      set_manufacturer_data = true;
47887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else if (arg == "-u") {
47987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      // This flag has a single argument.
48087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      ++iter;
48187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      if (iter == args.end()) {
48287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        PrintError("Expected a UUID after -u");
48387222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        return;
48487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      }
48587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
48687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      std::string uuid_str = *iter;
48787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      uuid = bluetooth::UUID(uuid_str);
48887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      if (!uuid.is_valid()) {
48987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        PrintError("Invalid UUID: " + uuid_str);
49087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        return;
49187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      }
49287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
49387222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      set_uuid = true;
494a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    } else if (arg == "-h") {
495ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      static const char kUsage[] =
496d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "Usage: start-adv [flags]\n"
497d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\n"
498ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "Flags:\n"
499d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-n\tInclude device name\n"
500d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-t\tInclude TX power\n"
501d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-c\tSend connectable adv. packets (default is non-connectable)\n"
502d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-m\tInclude random manufacturer data\n"
503d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-h\tShow this help message\n";
504d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      cout << kUsage << endl;
505d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      return;
506a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    } else {
507d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      PrintError("Unrecognized option: " + arg);
508d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      return;
509d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    }
510d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
511d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
5124fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!ble_client_id.load()) {
513d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("BLE not registered");
514d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
515d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
516d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
517a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
518a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
519d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  if (!ble_iface.get()) {
520d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
521d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
522d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
523d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
524d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  std::vector<uint8_t> data;
525d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  if (set_manufacturer_data) {
526a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    data = {{0x07, bluetooth::kEIRTypeManufacturerSpecificData, 0xe0, 0x00, 'T',
527a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski             'e', 's', 't'}};
528d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
529d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
53087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  if (set_uuid) {
53187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    // Determine the type and length bytes.
53287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    int uuid_size = uuid.GetShortestRepresentationSize();
53387222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    uint8_t type;
53487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    if (uuid_size == bluetooth::UUID::kNumBytes128)
53587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      type = bluetooth::kEIRTypeComplete128BitUUIDs;
53687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else if (uuid_size == bluetooth::UUID::kNumBytes32)
53787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      type = bluetooth::kEIRTypeComplete32BitUUIDs;
53887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else if (uuid_size == bluetooth::UUID::kNumBytes16)
53987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      type = bluetooth::kEIRTypeComplete16BitUUIDs;
54087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else
54187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      NOTREACHED() << "Unexpected size: " << uuid_size;
54287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
54387222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    data.push_back(uuid_size + 1);
54487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    data.push_back(type);
54587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
54687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    auto uuid_bytes = uuid.GetFullLittleEndian();
54787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    int index = (uuid_size == 16) ? 0 : 12;
54887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    data.insert(data.end(), uuid_bytes.data() + index,
54987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray                uuid_bytes.data() + index + uuid_size);
55087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  }
55187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
552d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  base::TimeDelta timeout;
553d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
554d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bluetooth::AdvertiseSettings settings(
555a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
556a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, connectable);
557d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
558d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bluetooth::AdvertiseData adv_data(data);
559d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  adv_data.set_include_device_name(include_name);
560d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  adv_data.set_include_tx_power_level(include_tx_power);
561d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
562d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bluetooth::AdvertiseData scan_rsp;
563d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
564a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
565a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StartMultiAdvertising(ble_client_id.load(), adv_data, scan_rsp,
566a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                                   settings, &status);
567ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  PrintCommandStatus(status);
568d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray}
569d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
570d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Ugurayvoid HandleStopAdv(IBluetooth* bt_iface, const vector<string>& args) {
5714fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!ble_client_id.load()) {
572d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("BLE not registered");
573d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
574d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
575d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
576a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
577a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
578d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  if (!ble_iface.get()) {
579d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
580d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
581d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
582d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
583a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
584a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StopMultiAdvertising(ble_client_id.load(), &status);
585ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  PrintCommandStatus(status);
586d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray}
587d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
588608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowskivoid HandleConnect(IBluetooth* bt_iface, const vector<string>& args) {
589608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  string address;
590608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
591608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (args.size() != 1) {
592608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Expected MAC address as only argument");
593608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
594608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
595608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
596608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  address = args[0];
597608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
598608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_client_id.load()) {
599608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("BLE not registered");
600608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
601608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
602608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
603a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
604a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
605608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_iface.get()) {
606608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
607608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
608608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
609608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
610a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
611a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->Connect(ble_client_id.load(),
612a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                     String16(address.c_str(), address.length()),
613a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                     false /*  is_direct */, &status);
614608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
615608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  PrintCommandStatus(status);
616608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski}
617608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
618608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowskivoid HandleDisconnect(IBluetooth* bt_iface, const vector<string>& args) {
619608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  string address;
620608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
621608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (args.size() != 1) {
622608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Expected MAC address as only argument");
623608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
624608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
625608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
626608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  address = args[0];
627608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
628608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_client_id.load()) {
629608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("BLE not registered");
630608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
631608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
632608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
633a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
634a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
635608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_iface.get()) {
636608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
637608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
638608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
639608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
640a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
641a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->Disconnect(ble_client_id.load(),
642a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        String16(address.c_str(), address.length()), &status);
643608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  PrintCommandStatus(status);
644608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski}
645608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
646756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowskivoid HandleSetMtu(IBluetooth* bt_iface, const vector<string>& args) {
647756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  string address;
648756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  int mtu;
649756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
650756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (args.size() != 2) {
651756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("Usage: set-mtu [address] [mtu]");
652756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
653756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
654756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
655756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  address = args[0];
656756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  mtu = std::stoi(args[1]);
657756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
658756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (mtu < 23) {
659756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("MTU must be 23 or larger");
660756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
661756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
662756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
663756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (!ble_client_id.load()) {
664756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("BLE not registered");
665756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
666756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
667756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
668a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
669a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
670756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (!ble_iface.get()) {
671756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
672756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
673756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
674756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
675a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
676a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->SetMtu(ble_client_id.load(),
677a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                    String16(address.c_str(), address.length()), mtu, &status);
678756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  PrintCommandStatus(status);
679756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski}
680756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
681ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowskivoid HandleStartLeScan(IBluetooth* bt_iface, const vector<string>& args) {
682ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_client_id.load()) {
683ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("BLE not registered");
684ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
685ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
686ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
687ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  for (auto arg : args) {
688ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    if (arg == "-d") {
689ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      dump_scan_record = true;
690ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    } else if (arg == "-h") {
691ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      static const char kUsage[] =
692ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "Usage: start-le-scan [flags]\n"
693ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "\n"
694ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "Flags:\n"
695ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "\t-d\tDump scan record\n"
696ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "\t-h\tShow this help message\n";
697ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      cout << kUsage << endl;
698ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      return;
699ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    }
700ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
701ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
702a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
703a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
704ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_iface.get()) {
705ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
706ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
707ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
708ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
709ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  bluetooth::ScanSettings settings;
710a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  std::vector<android::bluetooth::ScanFilter> filters;
711ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
712a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
713a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StartScan(ble_client_id.load(), settings, filters, &status);
714ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  PrintCommandStatus(status);
715ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski}
716ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
717ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowskivoid HandleStopLeScan(IBluetooth* bt_iface, const vector<string>& args) {
718ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_client_id.load()) {
719ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("BLE not registered");
720ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
721ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
722ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
723a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
724a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
725ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_iface.get()) {
726ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
727ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
728ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
729ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
730a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
731a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StopScan(ble_client_id.load(), &status);
732ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  PrintCommandStatus(status);
733ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski}
734ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
7355192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleHelp(IBluetooth* bt_iface, const vector<string>& args);
7362117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray
737fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguraystruct {
738fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray  string command;
7395192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  void (*func)(IBluetooth*, const vector<string>& args);
7402117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  string help;
741fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray} kCommandMap[] = {
742a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"help", HandleHelp, "\t\t\tDisplay this message"},
743a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"disable", HandleDisable, "\t\t\tDisable Bluetooth"},
744a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"enable", HandleEnable, "\t\t\tEnable Bluetooth"},
745a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"get-state", HandleGetState, "\t\tGet the current adapter state"},
746a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled"},
747a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"get-local-address", HandleGetLocalAddress,
748a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\tGet the local adapter address"},
749a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"set-local-name", HandleSetLocalName, "\t\tSet the local adapter name"},
750a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"get-local-name", HandleGetLocalName, "\t\tGet the local adapter name"},
751a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties"},
752a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"supports-multi-adv", HandleSupportsMultiAdv,
753a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\tWhether multi-advertisement is currently supported"},
754a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"register-ble", HandleRegisterBLE,
755a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tRegister with the Bluetooth Low Energy interface"},
756a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"unregister-ble", HandleUnregisterBLE,
757a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tUnregister from the Bluetooth Low Energy interface"},
758a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"unregister-all-ble", HandleUnregisterAllBLE,
759a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\tUnregister all clients from the Bluetooth Low Energy interface"},
760a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"register-gatt", HandleRegisterGATT,
761a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tRegister with the Bluetooth GATT Client interface"},
762a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"unregister-gatt", HandleUnregisterGATT,
763a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tUnregister from the Bluetooth GATT Client interface"},
764a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"connect-le", HandleConnect, "\t\tConnect to LE device (-h for options)"},
765a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"disconnect-le", HandleDisconnect,
766a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tDisconnect LE device (-h for options)"},
767a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"set-mtu", HandleSetMtu, "\t\tSet MTU (-h for options)"},
768a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"start-adv", HandleStartAdv, "\t\tStart advertising (-h for options)"},
769a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"stop-adv", HandleStopAdv, "\t\tStop advertising"},
770a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"start-le-scan", HandleStartLeScan,
771a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tStart LE device scan (-h for options)"},
772a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"stop-le-scan", HandleStopLeScan, "\t\tStop LE device scan"},
773a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {},
774fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray};
775f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
7765192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) {
7772117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  cout << endl;
7782117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  for (int i = 0; kCommandMap[i].func; i++)
7792117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray    cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl;
7802117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  cout << endl;
7812117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray}
7822117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray
7835d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssenconst char kExecuteLong[] = "exec";
7845d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssenconst char kExecuteShort[] = "e";
7855d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
7865d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssenbool ExecuteCommand(sp<IBluetooth> bt_iface, std::string &command) {
7875d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  vector<string> args =
7885d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      base::SplitString(command, " ", base::TRIM_WHITESPACE,
7895d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen                        base::SPLIT_WANT_ALL);
7905d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
7915d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  if (args.empty())
7925d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    return true;
7935d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
7945d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  // The first argument is the command while the remaining are what we pass to
7955d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  // the handler functions.
7965d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  command = args[0];
7975d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  args.erase(args.begin());
7985d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
7995d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  for (int i = 0; kCommandMap[i].func; i++) {
8005d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    if (command == kCommandMap[i].command) {
8015d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      kCommandMap[i].func(bt_iface.get(), args);
8025d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      return true;
8035d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    }
8045d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  }
8055d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8065d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  cout << "Unrecognized command: " << command << endl;
8075d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  return false;
8085d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen}
8095d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8102117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray}  // namespace
8112117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray
8122e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayclass BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
8132e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray public:
8142e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  BluetoothDeathRecipient() = default;
8152e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  ~BluetoothDeathRecipient() override = default;
8162e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8172e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  // android::IBinder::DeathRecipient override:
8182e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  void binderDied(const android::wp<android::IBinder>& /* who */) override {
81964401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
8202e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    cout << COLOR_BOLDWHITE "The Bluetooth daemon has died" COLOR_OFF << endl;
82164401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    cout << "\nPress 'ENTER' to exit.";
82264401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
8232e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8242e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    android::IPCThreadState::self()->stopProcess();
8252e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    should_exit = true;
8262e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
8272e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8282e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray private:
8292e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  DISALLOW_COPY_AND_ASSIGN(BluetoothDeathRecipient);
8302e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray};
8312e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8325d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
833ae43de627b9c91e54215d439149c0e01599249c0Arman Ugurayint main(int argc, char* argv[]) {
834ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  base::AtExitManager exit_manager;
835ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  base::CommandLine::Init(argc, argv);
836ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  logging::LoggingSettings log_settings;
837ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray
838ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  if (!logging::InitLogging(log_settings)) {
839ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray    LOG(ERROR) << "Failed to set up logging";
840ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray    return EXIT_FAILURE;
841ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  }
842ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray
843a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetooth> bt_iface;
844a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  status_t status = getService(String16(kServiceName.c_str()), &bt_iface);
845a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (status != OK) {
846a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    LOG(ERROR) << "Failed to get service binder: '" << kServiceName
847a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski               << "' status=" << status;
848f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray    return EXIT_FAILURE;
849f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray  }
850f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
8512e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  sp<BluetoothDeathRecipient> dr(new BluetoothDeathRecipient());
8522e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (android::IInterface::asBinder(bt_iface.get())->linkToDeath(dr) !=
8532e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray      android::NO_ERROR) {
8542e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
8552e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return EXIT_FAILURE;
8562e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
8572e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
85839a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // Initialize the Binder process thread pool. We have to set this up,
85939a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // otherwise, incoming callbacks from IBluetoothCallback will block the main
86039a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // thread (in other words, we have to do this as we are a "Binder server").
86139a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  android::ProcessState::self()->startThreadPool();
86239a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
86339a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // Register Adapter state-change callback
86439a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
86539a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  bt_iface->RegisterCallback(callback);
86639a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
867a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n"
868a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski       << COLOR_OFF << endl
8692117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray       << "Type \"help\" to see possible commands.\n"
870fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray       << endl;
871fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
8725d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  string command;
8735d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8745d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  // Add commands from the command line, if they exist.
8755d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  auto command_line = base::CommandLine::ForCurrentProcess();
8765d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  if (command_line->HasSwitch(kExecuteLong)) {
8775d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    command += command_line->GetSwitchValueASCII(kExecuteLong);
8785d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  }
8795d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8805d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  if (command_line->HasSwitch(kExecuteShort)) {
8815d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    if (!command.empty())
8825d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      command += " ; ";
8835d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    command += command_line->GetSwitchValueASCII(kExecuteShort);
8845d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  }
8855d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
886fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray  while (true) {
8875d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    vector<string> commands = base::SplitString(command, ";",
8885d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen                                                base::TRIM_WHITESPACE,
8895d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen                                                base::SPLIT_WANT_ALL);
8905d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    for (string command : commands) {
8915d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      if (!ExecuteCommand(bt_iface, command))
8925d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen        break;
8935d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    }
8945d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8955d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    commands.clear();
8965192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
89739a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray    PrintPrompt();
89839a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
89939a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray    showing_prompt = true;
90091c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    auto& istream = getline(cin, command);
90139a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray    showing_prompt = false;
902fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
90391c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    if (istream.eof() || should_exit.load()) {
90491c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray      cout << "\nExiting" << endl;
9052e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray      return EXIT_SUCCESS;
90691c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    }
90791c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray
90891c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    if (!istream.good()) {
90991c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray      LOG(ERROR) << "An error occured while reading input";
91091c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray      return EXIT_FAILURE;
91191c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    }
912fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray  }
913f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
914f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray  return EXIT_SUCCESS;
915f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray}
916