main.cc revision 10b54c4b7f1a863a27eca4158f256062ec9c3770
1// 2// Copyright (C) 2015 Google, Inc. 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at: 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include <iostream> 18#include <string> 19 20#include <base/logging.h> 21#include <base/macros.h> 22#include <base/strings/string_split.h> 23#include <base/strings/string_util.h> 24#include <binder/ProcessState.h> 25 26#include "service/adapter_state.h" 27#include "service/ipc/binder/IBluetooth.h" 28#include "service/ipc/binder/IBluetoothCallback.h" 29 30using namespace std; 31 32using android::sp; 33 34using ipc::binder::IBluetooth; 35 36namespace { 37 38#define COLOR_OFF "\x1B[0m" 39#define COLOR_RED "\x1B[0;91m" 40#define COLOR_GREEN "\x1B[0;92m" 41#define COLOR_YELLOW "\x1B[0;93m" 42#define COLOR_BLUE "\x1B[0;94m" 43#define COLOR_MAGENTA "\x1B[0;95m" 44#define COLOR_BOLDGRAY "\x1B[1;30m" 45#define COLOR_BOLDWHITE "\x1B[1;37m" 46#define COLOR_BOLDYELLOW "\x1B[1;93m" 47 48const char kCommandDisable[] = "disable"; 49const char kCommandEnable[] = "enable"; 50const char kCommandGetState[] = "get-state"; 51const char kCommandIsEnabled[] = "is-enabled"; 52 53#define CHECK_ARGS_COUNT(args, op, num, msg) \ 54 if (!(args.size() op num)) { \ 55 PrintError(msg); \ 56 return; \ 57 } 58#define CHECK_NO_ARGS(args) \ 59 CHECK_ARGS_COUNT(args, ==, 0, "Expected no arguments") 60 61// TODO(armansito): Clean up this code. Right now everything is in this 62// monolithic file. We should organize this into different classes for command 63// handling, console output/printing, callback handling, etc. 64// (See http://b/23387611) 65 66// Used to synchronize the printing of the command-line prompt and incoming 67// Binder callbacks. 68std::atomic_bool showing_prompt(false); 69 70void PrintPrompt() { 71 cout << COLOR_BLUE "[FCLI] " COLOR_OFF << flush; 72} 73 74class CLIBluetoothCallback : public ipc::binder::BnBluetoothCallback { 75 public: 76 CLIBluetoothCallback() = default; 77 ~CLIBluetoothCallback() override = default; 78 79 // IBluetoothCallback override: 80 void OnBluetoothStateChange( 81 bluetooth::AdapterState prev_state, 82 bluetooth::AdapterState new_state) override { 83 if (showing_prompt.load()) 84 cout << endl; 85 cout << COLOR_BOLDWHITE "Adapter state changed: " COLOR_OFF 86 << COLOR_MAGENTA << AdapterStateToString(prev_state) << COLOR_OFF 87 << COLOR_BOLDWHITE " -> " COLOR_OFF 88 << COLOR_BOLDYELLOW << AdapterStateToString(new_state) << COLOR_OFF 89 << endl << endl; 90 if (showing_prompt.load()) 91 PrintPrompt(); 92 } 93 94 private: 95 DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback); 96}; 97 98void PrintError(const string& message) { 99 cout << COLOR_RED << message << COLOR_OFF << endl; 100} 101 102void PrintCommandStatus(bool status) { 103 cout << COLOR_BOLDWHITE "Command status: " COLOR_OFF 104 << (status ? (COLOR_GREEN "success") : (COLOR_RED "failure")) 105 << COLOR_OFF << endl << endl; 106} 107 108void PrintFieldAndValue(const string& field, const string& value) { 109 cout << COLOR_BOLDWHITE << field << ": " << COLOR_BOLDYELLOW << value 110 << COLOR_OFF << endl; 111} 112 113void PrintFieldAndBoolValue(const string& field, bool value) { 114 PrintFieldAndValue(field, (value ? "true" : "false")); 115} 116 117void HandleDisable(IBluetooth* bt_iface, const vector<string>& args) { 118 CHECK_NO_ARGS(args); 119 PrintCommandStatus(bt_iface->Disable()); 120} 121 122void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) { 123 CHECK_NO_ARGS(args); 124 PrintCommandStatus(bt_iface->Enable()); 125} 126 127void HandleGetState(IBluetooth* bt_iface, const vector<string>& args) { 128 CHECK_NO_ARGS(args); 129 bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>( 130 bt_iface->GetState()); 131 PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state)); 132} 133 134void HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) { 135 CHECK_NO_ARGS(args); 136 bool enabled = bt_iface->IsEnabled(); 137 PrintFieldAndBoolValue("Adapter enabled", enabled); 138} 139 140void HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) { 141 CHECK_NO_ARGS(args); 142 string address = bt_iface->GetAddress(); 143 PrintFieldAndValue("Adapter address", address); 144} 145 146void HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) { 147 CHECK_ARGS_COUNT(args, >=, 1, "No name was given"); 148 149 std::string name; 150 for (const auto& arg : args) 151 name += arg + " "; 152 153 base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name); 154 155 PrintCommandStatus(bt_iface->SetName(name)); 156} 157 158void HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) { 159 CHECK_NO_ARGS(args); 160 string name = bt_iface->GetName(); 161 PrintFieldAndValue("Adapter name", name); 162} 163 164void HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) { 165 CHECK_NO_ARGS(args); 166 167 cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl; 168 169 PrintFieldAndValue("\tAddress", bt_iface->GetAddress()); 170 PrintFieldAndValue("\tState", bluetooth::AdapterStateToString( 171 static_cast<bluetooth::AdapterState>(bt_iface->GetState()))); 172 PrintFieldAndValue("\tName", bt_iface->GetName()); 173 PrintFieldAndBoolValue("\tMulti-Adv. supported", 174 bt_iface->IsMultiAdvertisementSupported()); 175} 176 177void HandleSupportsMultiAdv(IBluetooth* bt_iface, const vector<string>& args) { 178 CHECK_NO_ARGS(args); 179 180 bool status = bt_iface->IsMultiAdvertisementSupported(); 181 PrintFieldAndBoolValue("Multi-advertisement support", status); 182} 183 184void HandleHelp(IBluetooth* bt_iface, const vector<string>& args); 185 186struct { 187 string command; 188 void (*func)(IBluetooth*, const vector<string>& args); 189 string help; 190} kCommandMap[] = { 191 { "help", HandleHelp, "\t\t\tDisplay this message" }, 192 { "disable", HandleDisable, "\t\t\tDisable Bluetooth" }, 193 { "enable", HandleEnable, "\t\t\tEnable Bluetooth" }, 194 { "get-state", HandleGetState, "\t\tGet the current adapter state" }, 195 { "is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled" }, 196 { "get-local-address", HandleGetLocalAddress, 197 "\tGet the local adapter address" }, 198 { "set-local-name", HandleSetLocalName, "\t\tSet the local adapter name" }, 199 { "get-local-name", HandleGetLocalName, "\t\tGet the local adapter name" }, 200 { "adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties" }, 201 { "supports-multi-adv", HandleSupportsMultiAdv, 202 "\tWhether multi-advertisement is currently supported" }, 203 {}, 204}; 205 206void HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) { 207 cout << endl; 208 for (int i = 0; kCommandMap[i].func; i++) 209 cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl; 210 cout << endl; 211} 212 213} // namespace 214 215int main() { 216 sp<IBluetooth> bt_iface = IBluetooth::getClientInterface(); 217 if (!bt_iface.get()) { 218 LOG(ERROR) << "Failed to obtain handle on IBluetooth"; 219 return EXIT_FAILURE; 220 } 221 222 // Initialize the Binder process thread pool. We have to set this up, 223 // otherwise, incoming callbacks from IBluetoothCallback will block the main 224 // thread (in other words, we have to do this as we are a "Binder server"). 225 android::ProcessState::self()->startThreadPool(); 226 227 // Register Adapter state-change callback 228 sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback(); 229 bt_iface->RegisterCallback(callback); 230 231 cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n" << COLOR_OFF 232 << endl 233 << "Type \"help\" to see possible commands.\n" 234 << endl; 235 236 while (true) { 237 string command; 238 239 PrintPrompt(); 240 241 showing_prompt = true; 242 getline(cin, command); 243 showing_prompt = false; 244 245 vector<string> args; 246 base::SplitString(command, ' ', &args); 247 248 if (args.empty()) 249 continue; 250 251 // The first argument is the command while the remaning are what we pass to 252 // the handler functions. 253 command = args[0]; 254 args.erase(args.begin()); 255 256 bool command_handled = false; 257 for (int i = 0; kCommandMap[i].func && !command_handled; i++) { 258 if (command == kCommandMap[i].command) { 259 kCommandMap[i].func(bt_iface.get(), args); 260 command_handled = true; 261 } 262 } 263 264 if (!command_handled) 265 cout << "Unrecognized command: " << command << endl; 266 } 267 268 return EXIT_SUCCESS; 269} 270