main.cc revision 7b266be449e4f915c419199c2312eb31f70e63bc
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) {
2737b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker  bool is_restricted_mode = false;
2747b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker
2757b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker  for (auto iter : args) {
2767b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker    const std::string& arg = iter;
2777b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker    if (arg == "-h") {
2787b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker      static const char kUsage[] =
2797b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker          "Usage: start-adv [flags]\n"
2807b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker          "\n"
2817b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker          "Flags:\n"
2827b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker          "\t--restricted|-r\tStart in restricted mode\n";
2837b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker      cout << kUsage << endl;
2847b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker      return;
2857b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker    } else if (arg == "--restricted" || arg == "-r") {
2867b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker      is_restricted_mode = true;
2877b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker    }
2887b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker  }
2897b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker
290a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
2917b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker  bt_iface->Enable(is_restricted_mode, &status);
292a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintCommandStatus(status);
293fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray}
294fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
2955192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
2965192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
297a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
298a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  int32_t st;
299a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetState(&st);
300a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>(st);
3015192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state));
302fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray}
303fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
3045192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) {
3055192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
306a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool enabled;
307a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->IsEnabled(&enabled);
3085192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  PrintFieldAndBoolValue("Adapter enabled", enabled);
309fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray}
310fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
3115192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) {
3125192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
313a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 address;
314a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetAddress(&address);
315a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("Adapter address", std::string(String8(address).string()));
3165192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3175192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3185192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
3195192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_ARGS_COUNT(args, >=, 1, "No name was given");
3205192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3215192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  std::string name;
322a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  for (const auto& arg : args) name += arg + " ";
3235192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3245192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
3255192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
326a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
327a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->SetName(String16(String8(name.c_str())), &status);
328a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintCommandStatus(status);
3295192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3305192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3315192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
3325192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
333a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 name;
334a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetName(&name);
335a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("Adapter name", std::string(String8(name).string()));
3365192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3375192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3385192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) {
3395192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  CHECK_NO_ARGS(args);
3405192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3415192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl;
3425192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
343a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 address;
344a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetAddress(&address);
345a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("\tAddress", std::string(String8(address).string()));
346a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
347a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  int adapter_state;
348a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetState(&adapter_state);
349a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("\tState",
350a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                     bluetooth::AdapterStateToString(
351a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                         static_cast<bluetooth::AdapterState>(adapter_state)));
352a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
353a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  String16 name;
354a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetName(&name);
355a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndValue("\tName", std::string(String8(name).string()));
356a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski
357a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool multi_adv;
358a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
359a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndBoolValue("\tMulti-Adv. supported", multi_adv);
36010b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray}
36110b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray
36210b54c4b7f1a863a27eca4158f256062ec9c3770Arman Ugurayvoid HandleSupportsMultiAdv(IBluetooth* bt_iface, const vector<string>& args) {
36310b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray  CHECK_NO_ARGS(args);
36410b54c4b7f1a863a27eca4158f256062ec9c3770Arman Uguray
365a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool multi_adv;
366a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
367a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  PrintFieldAndBoolValue("Multi-advertisement support", multi_adv);
3685192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray}
3695192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
3702e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayvoid HandleRegisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
3712e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  CHECK_NO_ARGS(args);
3722e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3732e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (ble_registering.load()) {
3742e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("In progress");
3752e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3762e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3772e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3784fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (ble_client_id.load()) {
3792e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Already registered");
3802e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3812e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3822e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
383a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
384a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
3852e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (!ble_iface.get()) {
3862e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
3872e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
3882e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
3892e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
390a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
391a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->RegisterClient(new CLIBluetoothLowEnergyCallback(), &status);
392ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  ble_registering = status;
393ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  PrintCommandStatus(status);
3942e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray}
3952e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3962e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayvoid HandleUnregisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
3972e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  CHECK_NO_ARGS(args);
3982e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
3994fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!ble_client_id.load()) {
4002e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Not registered");
4012e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
4022e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
4032e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
404a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
405a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
4062e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (!ble_iface.get()) {
4072e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
4082e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
4092e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
4102e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
4114fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  ble_iface->UnregisterClient(ble_client_id.load());
4124fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  ble_client_id = 0;
4132e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  PrintCommandStatus(true);
4142e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray}
4152e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
4162e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayvoid HandleUnregisterAllBLE(IBluetooth* bt_iface, const vector<string>& args) {
4172e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  CHECK_NO_ARGS(args);
4182e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
419a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
420a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
4212e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (!ble_iface.get()) {
4222e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
4232e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return;
4242e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
4252e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
4262e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  ble_iface->UnregisterAll();
4272e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  PrintCommandStatus(true);
4282e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray}
4292e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
4304fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Ugurayvoid HandleRegisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
4314fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  CHECK_NO_ARGS(args);
4324fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4334fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (gatt_registering.load()) {
4344fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("In progress");
4354fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4364fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4374fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4384fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (gatt_client_id.load()) {
4394fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Already registered");
4404fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4414fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4424fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
443a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothGattClient> gatt_iface;
444a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetGattClientInterface(&gatt_iface);
4454fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!gatt_iface.get()) {
4464fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
4474fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4484fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4494fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
450a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
451a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  gatt_iface->RegisterClient(new CLIGattClientCallback(), &status);
4524fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  gatt_registering = status;
4534fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  PrintCommandStatus(status);
4544fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray}
4554fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4564fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Ugurayvoid HandleUnregisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
4574fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  CHECK_NO_ARGS(args);
4584fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4594fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!gatt_client_id.load()) {
4604fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Not registered");
4614fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4624fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4634fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
464a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothGattClient> gatt_iface;
465a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetGattClientInterface(&gatt_iface);
4664fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!gatt_iface.get()) {
4674fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
4684fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray    return;
4694fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  }
4704fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
4714fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  gatt_iface->UnregisterClient(gatt_client_id.load());
4724fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  gatt_client_id = 0;
4734fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  PrintCommandStatus(true);
4744fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray}
4754fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray
476d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Ugurayvoid HandleStartAdv(IBluetooth* bt_iface, const vector<string>& args) {
477d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool include_name = false;
478d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool include_tx_power = false;
479d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool connectable = false;
480d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bool set_manufacturer_data = false;
48187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  bool set_uuid = false;
48287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  bluetooth::UUID uuid;
483d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
48487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  for (auto iter = args.begin(); iter != args.end(); ++iter) {
48587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    const std::string& arg = *iter;
486d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    if (arg == "-n")
487d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      include_name = true;
488d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    else if (arg == "-t")
489d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      include_tx_power = true;
490d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    else if (arg == "-c")
491d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      connectable = true;
492d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    else if (arg == "-m")
493d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      set_manufacturer_data = true;
49487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else if (arg == "-u") {
49587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      // This flag has a single argument.
49687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      ++iter;
49787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      if (iter == args.end()) {
49887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        PrintError("Expected a UUID after -u");
49987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        return;
50087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      }
50187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
50287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      std::string uuid_str = *iter;
50387222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      uuid = bluetooth::UUID(uuid_str);
50487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      if (!uuid.is_valid()) {
50587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        PrintError("Invalid UUID: " + uuid_str);
50687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray        return;
50787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      }
50887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
50987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      set_uuid = true;
510a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    } else if (arg == "-h") {
511ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      static const char kUsage[] =
512d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "Usage: start-adv [flags]\n"
513d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\n"
514ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "Flags:\n"
515d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-n\tInclude device name\n"
516d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-t\tInclude TX power\n"
517d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-c\tSend connectable adv. packets (default is non-connectable)\n"
518d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-m\tInclude random manufacturer data\n"
519d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray          "\t-h\tShow this help message\n";
520d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      cout << kUsage << endl;
521d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      return;
522a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    } else {
523d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      PrintError("Unrecognized option: " + arg);
524d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray      return;
525d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    }
526d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
527d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
5284fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!ble_client_id.load()) {
529d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("BLE not registered");
530d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
531d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
532d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
533a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
534a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
535d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  if (!ble_iface.get()) {
536d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
537d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
538d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
539d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
540d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  std::vector<uint8_t> data;
541d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  if (set_manufacturer_data) {
542a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    data = {{0x07, bluetooth::kEIRTypeManufacturerSpecificData, 0xe0, 0x00, 'T',
543a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski             'e', 's', 't'}};
544d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
545d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
54687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  if (set_uuid) {
54787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    // Determine the type and length bytes.
54887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    int uuid_size = uuid.GetShortestRepresentationSize();
54987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    uint8_t type;
55087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    if (uuid_size == bluetooth::UUID::kNumBytes128)
55187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      type = bluetooth::kEIRTypeComplete128BitUUIDs;
55287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else if (uuid_size == bluetooth::UUID::kNumBytes32)
55387222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      type = bluetooth::kEIRTypeComplete32BitUUIDs;
55487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else if (uuid_size == bluetooth::UUID::kNumBytes16)
55587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      type = bluetooth::kEIRTypeComplete16BitUUIDs;
55687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    else
55787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray      NOTREACHED() << "Unexpected size: " << uuid_size;
55887222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
55987222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    data.push_back(uuid_size + 1);
56087222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    data.push_back(type);
56187222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
56287222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    auto uuid_bytes = uuid.GetFullLittleEndian();
56387222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    int index = (uuid_size == 16) ? 0 : 12;
56487222e0e826216c69f6a9a5bfe77689561067474Arman Uguray    data.insert(data.end(), uuid_bytes.data() + index,
56587222e0e826216c69f6a9a5bfe77689561067474Arman Uguray                uuid_bytes.data() + index + uuid_size);
56687222e0e826216c69f6a9a5bfe77689561067474Arman Uguray  }
56787222e0e826216c69f6a9a5bfe77689561067474Arman Uguray
568d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  base::TimeDelta timeout;
569d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
570d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bluetooth::AdvertiseSettings settings(
571a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
572a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski      bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, connectable);
573d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
574d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bluetooth::AdvertiseData adv_data(data);
575d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  adv_data.set_include_device_name(include_name);
576d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  adv_data.set_include_tx_power_level(include_tx_power);
577d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
578d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  bluetooth::AdvertiseData scan_rsp;
579d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
580a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
581a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StartMultiAdvertising(ble_client_id.load(), adv_data, scan_rsp,
582a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                                   settings, &status);
583ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  PrintCommandStatus(status);
584d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray}
585d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
586d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Ugurayvoid HandleStopAdv(IBluetooth* bt_iface, const vector<string>& args) {
5874fbbf6047f182b9dfbf11d5d8da7281845fce99eArman Uguray  if (!ble_client_id.load()) {
588d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("BLE not registered");
589d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
590d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
591d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
592a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
593a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
594d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  if (!ble_iface.get()) {
595d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
596d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray    return;
597d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray  }
598d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
599a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
600a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StopMultiAdvertising(ble_client_id.load(), &status);
601ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  PrintCommandStatus(status);
602d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray}
603d19bc0457a9b6519acd6a79c3ac7de653894f5ecArman Uguray
604608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowskivoid HandleConnect(IBluetooth* bt_iface, const vector<string>& args) {
605608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  string address;
606608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
607608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (args.size() != 1) {
608608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Expected MAC address as only argument");
609608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
610608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
611608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
612608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  address = args[0];
613608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
614608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_client_id.load()) {
615608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("BLE not registered");
616608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
617608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
618608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
619a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
620a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
621608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_iface.get()) {
622608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
623608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
624608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
625608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
626a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
627a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->Connect(ble_client_id.load(),
628a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                     String16(address.c_str(), address.length()),
629a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                     false /*  is_direct */, &status);
630608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
631608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  PrintCommandStatus(status);
632608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski}
633608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
634608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowskivoid HandleDisconnect(IBluetooth* bt_iface, const vector<string>& args) {
635608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  string address;
636608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
637608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (args.size() != 1) {
638608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Expected MAC address as only argument");
639608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
640608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
641608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
642608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  address = args[0];
643608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
644608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_client_id.load()) {
645608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("BLE not registered");
646608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
647608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
648608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
649a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
650a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
651608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  if (!ble_iface.get()) {
652608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
653608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski    return;
654608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  }
655608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
656a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
657a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->Disconnect(ble_client_id.load(),
658a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                        String16(address.c_str(), address.length()), &status);
659608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski  PrintCommandStatus(status);
660608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski}
661608762d5769b948387c8d76e7f1d5a60db1850aeJakub Pawlowski
662756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowskivoid HandleSetMtu(IBluetooth* bt_iface, const vector<string>& args) {
663756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  string address;
664756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  int mtu;
665756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
666756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (args.size() != 2) {
667756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("Usage: set-mtu [address] [mtu]");
668756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
669756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
670756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
671756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  address = args[0];
672756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  mtu = std::stoi(args[1]);
673756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
674756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (mtu < 23) {
675756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("MTU must be 23 or larger");
676756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
677756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
678756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
679756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (!ble_client_id.load()) {
680756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("BLE not registered");
681756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
682756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
683756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
684a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
685a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
686756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  if (!ble_iface.get()) {
687756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
688756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski    return;
689756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  }
690756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
691a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
692a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->SetMtu(ble_client_id.load(),
693a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski                    String16(address.c_str(), address.length()), mtu, &status);
694756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski  PrintCommandStatus(status);
695756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski}
696756cc4bdedca24e4ba157902a3d0b411cfa109beJakub Pawlowski
697ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowskivoid HandleStartLeScan(IBluetooth* bt_iface, const vector<string>& args) {
698ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_client_id.load()) {
699ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("BLE not registered");
700ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
701ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
702ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
703ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  for (auto arg : args) {
704ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    if (arg == "-d") {
705ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      dump_scan_record = true;
706ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    } else if (arg == "-h") {
707ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      static const char kUsage[] =
708ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "Usage: start-le-scan [flags]\n"
709ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "\n"
710ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "Flags:\n"
711ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "\t-d\tDump scan record\n"
712ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski          "\t-h\tShow this help message\n";
713ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      cout << kUsage << endl;
714ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski      return;
715ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    }
716ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
717ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
718a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
719a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
720ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_iface.get()) {
721ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
722ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
723ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
724ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
725ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  bluetooth::ScanSettings settings;
726a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  std::vector<android::bluetooth::ScanFilter> filters;
727ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
728a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
729a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StartScan(ble_client_id.load(), settings, filters, &status);
730ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  PrintCommandStatus(status);
731ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski}
732ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
733ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowskivoid HandleStopLeScan(IBluetooth* bt_iface, const vector<string>& args) {
734ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_client_id.load()) {
735ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("BLE not registered");
736ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
737ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
738ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
739a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetoothLowEnergy> ble_iface;
740a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bt_iface->GetLowEnergyInterface(&ble_iface);
741ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  if (!ble_iface.get()) {
742ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
743ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski    return;
744ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  }
745ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
746a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  bool status;
747a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  ble_iface->StopScan(ble_client_id.load(), &status);
748ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski  PrintCommandStatus(status);
749ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski}
750ba197a21d810b0ef814ed9c23dd3b290613751c7Jakub Pawlowski
7515192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleHelp(IBluetooth* bt_iface, const vector<string>& args);
7522117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray
753fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguraystruct {
754fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray  string command;
7555192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray  void (*func)(IBluetooth*, const vector<string>& args);
7562117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  string help;
757fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray} kCommandMap[] = {
758a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"help", HandleHelp, "\t\t\tDisplay this message"},
759a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"disable", HandleDisable, "\t\t\tDisable Bluetooth"},
7607b266be449e4f915c419199c2312eb31f70e63bcAjay Panicker    {"enable", HandleEnable, "\t\t\tEnable Bluetooth (-h for options)"},
761a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"get-state", HandleGetState, "\t\tGet the current adapter state"},
762a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled"},
763a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"get-local-address", HandleGetLocalAddress,
764a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\tGet the local adapter address"},
765a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"set-local-name", HandleSetLocalName, "\t\tSet the local adapter name"},
766a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"get-local-name", HandleGetLocalName, "\t\tGet the local adapter name"},
767a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties"},
768a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"supports-multi-adv", HandleSupportsMultiAdv,
769a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\tWhether multi-advertisement is currently supported"},
770a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"register-ble", HandleRegisterBLE,
771a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tRegister with the Bluetooth Low Energy interface"},
772a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"unregister-ble", HandleUnregisterBLE,
773a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tUnregister from the Bluetooth Low Energy interface"},
774a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"unregister-all-ble", HandleUnregisterAllBLE,
775a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\tUnregister all clients from the Bluetooth Low Energy interface"},
776a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"register-gatt", HandleRegisterGATT,
777a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tRegister with the Bluetooth GATT Client interface"},
778a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"unregister-gatt", HandleUnregisterGATT,
779a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tUnregister from the Bluetooth GATT Client interface"},
780a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"connect-le", HandleConnect, "\t\tConnect to LE device (-h for options)"},
781a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"disconnect-le", HandleDisconnect,
782a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tDisconnect LE device (-h for options)"},
783a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"set-mtu", HandleSetMtu, "\t\tSet MTU (-h for options)"},
784a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"start-adv", HandleStartAdv, "\t\tStart advertising (-h for options)"},
785a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"stop-adv", HandleStopAdv, "\t\tStop advertising"},
786a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"start-le-scan", HandleStartLeScan,
787a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski     "\t\tStart LE device scan (-h for options)"},
788a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {"stop-le-scan", HandleStopLeScan, "\t\tStop LE device scan"},
789a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    {},
790fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray};
791f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
7925192309af14408c3f170f15c1282ae5c1eb5abffArman Ugurayvoid HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) {
7932117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  cout << endl;
7942117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  for (int i = 0; kCommandMap[i].func; i++)
7952117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray    cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl;
7962117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray  cout << endl;
7972117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray}
7982117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray
7995d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssenconst char kExecuteLong[] = "exec";
8005d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssenconst char kExecuteShort[] = "e";
8015d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8025d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssenbool ExecuteCommand(sp<IBluetooth> bt_iface, std::string &command) {
8035d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  vector<string> args =
8045d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      base::SplitString(command, " ", base::TRIM_WHITESPACE,
8055d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen                        base::SPLIT_WANT_ALL);
8065d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8075d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  if (args.empty())
8085d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    return true;
8095d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8105d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  // The first argument is the command while the remaining are what we pass to
8115d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  // the handler functions.
8125d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  command = args[0];
8135d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  args.erase(args.begin());
8145d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8155d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  for (int i = 0; kCommandMap[i].func; i++) {
8165d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    if (command == kCommandMap[i].command) {
8175d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      kCommandMap[i].func(bt_iface.get(), args);
8185d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      return true;
8195d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    }
8205d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  }
8215d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8225d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  cout << "Unrecognized command: " << command << endl;
8235d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  return false;
8245d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen}
8255d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8262117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray}  // namespace
8272117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray
8282e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Ugurayclass BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
8292e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray public:
8302e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  BluetoothDeathRecipient() = default;
8312e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  ~BluetoothDeathRecipient() override = default;
8322e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8332e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  // android::IBinder::DeathRecipient override:
8342e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  void binderDied(const android::wp<android::IBinder>& /* who */) override {
83564401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    BeginAsyncOut();
8362e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    cout << COLOR_BOLDWHITE "The Bluetooth daemon has died" COLOR_OFF << endl;
83764401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    cout << "\nPress 'ENTER' to exit.";
83864401bf539bdef652ddcfc25138ad5e353aea1c3Jakub Pawlowski    EndAsyncOut();
8392e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8402e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    android::IPCThreadState::self()->stopProcess();
8412e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    should_exit = true;
8422e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
8432e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8442e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray private:
8452e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  DISALLOW_COPY_AND_ASSIGN(BluetoothDeathRecipient);
8462e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray};
8472e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
8485d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
849ae43de627b9c91e54215d439149c0e01599249c0Arman Ugurayint main(int argc, char* argv[]) {
850ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  base::AtExitManager exit_manager;
851ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  base::CommandLine::Init(argc, argv);
852ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  logging::LoggingSettings log_settings;
853ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray
854ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  if (!logging::InitLogging(log_settings)) {
855ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray    LOG(ERROR) << "Failed to set up logging";
856ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray    return EXIT_FAILURE;
857ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray  }
858ae43de627b9c91e54215d439149c0e01599249c0Arman Uguray
859a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  sp<IBluetooth> bt_iface;
860a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  status_t status = getService(String16(kServiceName.c_str()), &bt_iface);
861a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  if (status != OK) {
862a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski    LOG(ERROR) << "Failed to get service binder: '" << kServiceName
863a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski               << "' status=" << status;
864f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray    return EXIT_FAILURE;
865f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray  }
866f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
8672e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  sp<BluetoothDeathRecipient> dr(new BluetoothDeathRecipient());
8682e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  if (android::IInterface::asBinder(bt_iface.get())->linkToDeath(dr) !=
8692e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray      android::NO_ERROR) {
8702e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
8712e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray    return EXIT_FAILURE;
8722e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray  }
8732e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray
87439a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // Initialize the Binder process thread pool. We have to set this up,
87539a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // otherwise, incoming callbacks from IBluetoothCallback will block the main
87639a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // thread (in other words, we have to do this as we are a "Binder server").
87739a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  android::ProcessState::self()->startThreadPool();
87839a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
87939a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  // Register Adapter state-change callback
88039a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
88139a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray  bt_iface->RegisterCallback(callback);
88239a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
883a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski  cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n"
884a4bd0d2370bd469942e92e724cfc9c7c01d3da74Jakub Pawlowski       << COLOR_OFF << endl
8852117e520c9f5b105ade7e92c4ab4928ea905f176Arman Uguray       << "Type \"help\" to see possible commands.\n"
886fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray       << endl;
887fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
8885d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  string command;
8895d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8905d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  // Add commands from the command line, if they exist.
8915d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  auto command_line = base::CommandLine::ForCurrentProcess();
8925d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  if (command_line->HasSwitch(kExecuteLong)) {
8935d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    command += command_line->GetSwitchValueASCII(kExecuteLong);
8945d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  }
8955d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
8965d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  if (command_line->HasSwitch(kExecuteShort)) {
8975d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    if (!command.empty())
8985d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      command += " ; ";
8995d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    command += command_line->GetSwitchValueASCII(kExecuteShort);
9005d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen  }
9015d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
902fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray  while (true) {
9035d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    vector<string> commands = base::SplitString(command, ";",
9045d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen                                                base::TRIM_WHITESPACE,
9055d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen                                                base::SPLIT_WANT_ALL);
9065d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    for (string command : commands) {
9075d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen      if (!ExecuteCommand(bt_iface, command))
9085d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen        break;
9095d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    }
9105d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen
9115d80cb938d7fb3312870a047749cc839ba5bafcaMarie Janssen    commands.clear();
9125192309af14408c3f170f15c1282ae5c1eb5abffArman Uguray
91339a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray    PrintPrompt();
91439a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray
91539a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray    showing_prompt = true;
91691c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    auto& istream = getline(cin, command);
91739a66bed960d96eca900e7e002e0d7bef0e0e151Arman Uguray    showing_prompt = false;
918fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray
91991c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    if (istream.eof() || should_exit.load()) {
92091c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray      cout << "\nExiting" << endl;
9212e4341488064be7e8f4d575c8de0a1670ddc81a0Arman Uguray      return EXIT_SUCCESS;
92291c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    }
92391c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray
92491c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    if (!istream.good()) {
92591c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray      LOG(ERROR) << "An error occured while reading input";
92691c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray      return EXIT_FAILURE;
92791c59c9febbf4a49664b8a06620d4a4882605131Arman Uguray    }
928fcf2e0391950a8b140082fbe78688fa89471fbedArman Uguray  }
929f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray
930f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray  return EXIT_SUCCESS;
931f52095257e36b887d7ddfd1f00871b9311dbfa1bArman Uguray}
932