1 /* 2 * Copyright (C) 2013 The Android Open Source Project 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 package com.android.cts.verifier.bluetooth; 18 19 import java.util.UUID; 20 import java.util.List; 21 22 import android.app.Service; 23 import android.bluetooth.BluetoothAdapter; 24 import android.bluetooth.BluetoothDevice; 25 import android.bluetooth.BluetoothGatt; 26 import android.bluetooth.BluetoothGattCallback; 27 import android.bluetooth.BluetoothGattCharacteristic; 28 import android.bluetooth.BluetoothGattDescriptor; 29 import android.bluetooth.BluetoothGattService; 30 import android.bluetooth.BluetoothManager; 31 import android.bluetooth.BluetoothProfile; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.util.Log; 37 import android.widget.Toast; 38 39 public class BleClientService extends Service { 40 41 public static final boolean DEBUG = true; 42 public static final String TAG = "BleClientService"; 43 44 public static final int COMMAND_CONNECT = 0; 45 public static final int COMMAND_DISCONNECT = 1; 46 public static final int COMMAND_DISCOVER_SERVICE = 2; 47 public static final int COMMAND_READ_RSSI = 3; 48 public static final int COMMAND_WRITE_CHARACTERISTIC = 4; 49 public static final int COMMAND_READ_CHARACTERISTIC = 5; 50 public static final int COMMAND_WRITE_DESCRIPTOR = 6; 51 public static final int COMMAND_READ_DESCRIPTOR = 7; 52 public static final int COMMAND_SET_NOTIFICATION = 8; 53 public static final int COMMAND_BEGIN_WRITE = 9; 54 public static final int COMMAND_EXECUTE_WRITE = 10; 55 public static final int COMMAND_ABORT_RELIABLE = 11; 56 57 public static final String BLE_BLUETOOTH_CONNECTED = 58 "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_CONNECTED"; 59 public static final String BLE_BLUETOOTH_DISCONNECTED = 60 "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISCONNECTED"; 61 public static final String BLE_SERVICES_DISCOVERED = 62 "com.android.cts.verifier.bluetooth.BLE_SERVICES_DISCOVERED"; 63 public static final String BLE_CHARACTERISTIC_READ = 64 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ"; 65 public static final String BLE_CHARACTERISTIC_WRITE = 66 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE"; 67 public static final String BLE_CHARACTERISTIC_CHANGED = 68 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_CHANGED"; 69 public static final String BLE_DESCRIPTOR_READ = 70 "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ"; 71 public static final String BLE_DESCRIPTOR_WRITE = 72 "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE"; 73 public static final String BLE_RELIABLE_WRITE_COMPLETED = 74 "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_COMPLETED"; 75 public static final String BLE_READ_REMOTE_RSSI = 76 "com.android.cts.verifier.bluetooth.BLE_READ_REMOTE_RSSI"; 77 78 public static final String EXTRA_COMMAND = 79 "com.android.cts.verifier.bluetooth.EXTRA_COMMAND"; 80 public static final String EXTRA_WRITE_VALUE = 81 "com.android.cts.verifier.bluetooth.EXTRA_WRITE_VALUE"; 82 public static final String EXTRA_BOOL = 83 "com.android.cts.verifier.bluetooth.EXTRA_BOOL"; 84 public static final String EXTRA_CHARACTERISTIC_VALUE = 85 "com.android.cts.verifier.bluetooth.EXTRA_CHARACTERISTIC_VALUE"; 86 public static final String EXTRA_DESCRIPTOR_VALUE = 87 "com.android.cts.verifier.bluetooth.EXTRA_DESCRIPTOR_VALUE"; 88 public static final String EXTRA_RSSI_VALUE = 89 "com.android.cts.verifier.bluetooth.EXTRA_RSSI_VALUE"; 90 91 private static final UUID SERVICE_UUID = 92 UUID.fromString("00009999-0000-1000-8000-00805f9b34fb"); 93 private static final UUID CHARACTERISTIC_UUID = 94 UUID.fromString("00009998-0000-1000-8000-00805f9b34fb"); 95 private static final UUID UPDATE_CHARACTERISTIC_UUID = 96 UUID.fromString("00009997-0000-1000-8000-00805f9b34fb"); 97 private static final UUID DESCRIPTOR_UUID = 98 UUID.fromString("00009996-0000-1000-8000-00805f9b34fb"); 99 100 private BluetoothManager mBluetoothManager; 101 private BluetoothAdapter mBluetoothAdapter; 102 private BluetoothDevice mDevice; 103 private BluetoothGatt mBluetoothGatt; 104 private Handler mHandler; 105 106 @Override onCreate()107 public void onCreate() { 108 super.onCreate(); 109 110 mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 111 mBluetoothAdapter = mBluetoothManager.getAdapter(); 112 mHandler = new Handler(); 113 } 114 115 @Override onStartCommand(Intent intent, int flags, int startId)116 public int onStartCommand(Intent intent, int flags, int startId) { 117 if (intent != null) handleIntent(intent); 118 return START_NOT_STICKY; 119 } 120 121 @Override onBind(Intent intent)122 public IBinder onBind(Intent intent) { 123 return null; 124 } 125 126 @Override onDestroy()127 public void onDestroy() { 128 super.onDestroy(); 129 mBluetoothGatt.disconnect(); 130 mBluetoothGatt.close(); 131 } 132 handleIntent(Intent intent)133 private void handleIntent(Intent intent) { 134 int command = intent.getIntExtra(EXTRA_COMMAND, -1); 135 String address = intent.getStringExtra(BluetoothDevice.EXTRA_DEVICE); // sometimes null 136 String writeValue = intent.getStringExtra(EXTRA_WRITE_VALUE); // sometimes null 137 boolean enable = intent.getBooleanExtra(EXTRA_BOOL, false); 138 BluetoothGattService service; 139 BluetoothGattCharacteristic characteristic; 140 BluetoothGattDescriptor descriptor; 141 142 switch (command) { 143 case COMMAND_CONNECT: 144 mDevice = mBluetoothAdapter.getRemoteDevice(address); 145 mBluetoothGatt = mDevice.connectGatt(this, false, mGattCallbacks); 146 break; 147 case COMMAND_DISCONNECT: 148 if (mBluetoothGatt != null) mBluetoothGatt.disconnect(); 149 break; 150 case COMMAND_DISCOVER_SERVICE: 151 if (mBluetoothGatt != null) mBluetoothGatt.discoverServices(); 152 break; 153 case COMMAND_READ_RSSI: 154 if (mBluetoothGatt != null) mBluetoothGatt.readRemoteRssi(); 155 break; 156 case COMMAND_WRITE_CHARACTERISTIC: 157 writeCharacteristic(writeValue); 158 break; 159 case COMMAND_READ_CHARACTERISTIC: 160 readCharacteristic(); 161 break; 162 case COMMAND_WRITE_DESCRIPTOR: 163 writeDescriptor(writeValue); 164 break; 165 case COMMAND_READ_DESCRIPTOR: 166 readDescriptor(); 167 break; 168 case COMMAND_SET_NOTIFICATION: 169 setNotification(enable); 170 break; 171 case COMMAND_BEGIN_WRITE: 172 if (mBluetoothGatt != null) mBluetoothGatt.beginReliableWrite(); 173 break; 174 case COMMAND_EXECUTE_WRITE: 175 if (mBluetoothGatt != null) mBluetoothGatt.executeReliableWrite(); 176 break; 177 case COMMAND_ABORT_RELIABLE: 178 if (mBluetoothGatt != null) mBluetoothGatt.abortReliableWrite(mDevice); 179 break; 180 default: 181 showMessage("Unrecognized command: " + command); 182 break; 183 } 184 } 185 writeCharacteristic(String writeValue)186 private void writeCharacteristic(String writeValue) { 187 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 188 if (characteristic == null) return; 189 characteristic.setValue(writeValue); 190 mBluetoothGatt.writeCharacteristic(characteristic); 191 } 192 readCharacteristic()193 private void readCharacteristic() { 194 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 195 if (characteristic != null) mBluetoothGatt.readCharacteristic(characteristic); 196 } 197 writeDescriptor(String writeValue)198 private void writeDescriptor(String writeValue) { 199 BluetoothGattDescriptor descriptor = getDescriptor(); 200 if (descriptor == null) return; 201 descriptor.setValue(writeValue.getBytes()); 202 mBluetoothGatt.writeDescriptor(descriptor); 203 } 204 readDescriptor()205 private void readDescriptor() { 206 BluetoothGattDescriptor descriptor = getDescriptor(); 207 if (descriptor != null) mBluetoothGatt.readDescriptor(descriptor); 208 } 209 setNotification(boolean enable)210 private void setNotification(boolean enable) { 211 BluetoothGattCharacteristic characteristic = getCharacteristic(UPDATE_CHARACTERISTIC_UUID); 212 if (characteristic != null) 213 mBluetoothGatt.setCharacteristicNotification(characteristic, enable); 214 } 215 notifyConnected()216 private void notifyConnected() { 217 Intent intent = new Intent(BLE_BLUETOOTH_CONNECTED); 218 sendBroadcast(intent); 219 } 220 notifyDisconnected()221 private void notifyDisconnected() { 222 Intent intent = new Intent(BLE_BLUETOOTH_DISCONNECTED); 223 sendBroadcast(intent); 224 } 225 notifyServicesDiscovered()226 private void notifyServicesDiscovered() { 227 Intent intent = new Intent(BLE_SERVICES_DISCOVERED); 228 sendBroadcast(intent); 229 } 230 notifyCharacteristicRead(String value)231 private void notifyCharacteristicRead(String value) { 232 Intent intent = new Intent(BLE_CHARACTERISTIC_READ); 233 intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value); 234 sendBroadcast(intent); 235 } 236 notifyCharacteristicWrite()237 private void notifyCharacteristicWrite() { 238 Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE); 239 sendBroadcast(intent); 240 } 241 notifyCharacteristicChanged(String value)242 private void notifyCharacteristicChanged(String value) { 243 Intent intent = new Intent(BLE_CHARACTERISTIC_CHANGED); 244 intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value); 245 sendBroadcast(intent); 246 } 247 notifyDescriptorRead(String value)248 private void notifyDescriptorRead(String value) { 249 Intent intent = new Intent(BLE_DESCRIPTOR_READ); 250 intent.putExtra(EXTRA_DESCRIPTOR_VALUE, value); 251 sendBroadcast(intent); 252 } 253 notifyDescriptorWrite()254 private void notifyDescriptorWrite() { 255 Intent intent = new Intent(BLE_DESCRIPTOR_WRITE); 256 sendBroadcast(intent); 257 } 258 notifyReliableWriteCompleted()259 private void notifyReliableWriteCompleted() { 260 Intent intent = new Intent(BLE_RELIABLE_WRITE_COMPLETED); 261 sendBroadcast(intent); 262 } 263 notifyReadRemoteRssi(int rssi)264 private void notifyReadRemoteRssi(int rssi) { 265 Intent intent = new Intent(BLE_READ_REMOTE_RSSI); 266 intent.putExtra(EXTRA_RSSI_VALUE, rssi); 267 sendBroadcast(intent); 268 } 269 getService()270 private BluetoothGattService getService() { 271 if (mBluetoothGatt == null) return null; 272 273 BluetoothGattService service = mBluetoothGatt.getService(SERVICE_UUID); 274 if (service == null) { 275 showMessage("Service not found"); 276 return null; 277 } 278 return service; 279 } 280 getCharacteristic(UUID uuid)281 private BluetoothGattCharacteristic getCharacteristic(UUID uuid) { 282 BluetoothGattService service = getService(); 283 if (service == null) return null; 284 285 BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid); 286 if (characteristic == null) { 287 showMessage("Characteristic not found"); 288 return null; 289 } 290 return characteristic; 291 } 292 getDescriptor()293 private BluetoothGattDescriptor getDescriptor() { 294 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 295 if (characteristic == null) return null; 296 297 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID); 298 if (descriptor == null) { 299 showMessage("Descriptor not found"); 300 return null; 301 } 302 return descriptor; 303 } 304 showMessage(final String msg)305 private void showMessage(final String msg) { 306 mHandler.post(new Runnable() { 307 public void run() { 308 Toast.makeText(BleClientService.this, msg, Toast.LENGTH_SHORT).show(); 309 } 310 }); 311 } 312 313 private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() { 314 @Override 315 public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 316 if (DEBUG) Log.d(TAG, "onConnectionStateChange"); 317 if (status == BluetoothGatt.GATT_SUCCESS) { 318 if (newState == BluetoothProfile.STATE_CONNECTED) notifyConnected(); 319 else if (status == BluetoothProfile.STATE_DISCONNECTED) { 320 notifyDisconnected(); 321 showMessage("Bluetooth LE disconnected"); 322 } 323 } 324 } 325 326 @Override 327 public void onServicesDiscovered(BluetoothGatt gatt, int status) { 328 if ((status == BluetoothGatt.GATT_SUCCESS) && 329 (mBluetoothGatt.getService(SERVICE_UUID) != null)) { 330 notifyServicesDiscovered(); 331 } 332 } 333 334 @Override 335 public void onCharacteristicRead(BluetoothGatt gatt, 336 BluetoothGattCharacteristic characteristic, int status) { 337 if ((status == BluetoothGatt.GATT_SUCCESS) && 338 (characteristic.getUuid().equals(CHARACTERISTIC_UUID))) { 339 notifyCharacteristicRead(characteristic.getStringValue(0)); 340 } 341 } 342 343 @Override 344 public void onCharacteristicWrite(BluetoothGatt gatt, 345 BluetoothGattCharacteristic characteristic, int status) { 346 if (DEBUG) Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + characteristic.getStringValue(0) 347 + " status=" + status); 348 BluetoothGattCharacteristic mCharacteristic = getCharacteristic(CHARACTERISTIC_UUID); 349 if ((status == BluetoothGatt.GATT_SUCCESS) && 350 (characteristic.getStringValue(0).equals(mCharacteristic.getStringValue(0)))) { 351 notifyCharacteristicWrite(); 352 } 353 } 354 355 @Override 356 public void onCharacteristicChanged(BluetoothGatt gatt, 357 BluetoothGattCharacteristic characteristic) { 358 if (characteristic.getUuid().equals(UPDATE_CHARACTERISTIC_UUID)) 359 notifyCharacteristicChanged(characteristic.getStringValue(0)); 360 } 361 362 @Override 363 public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 364 int status) { 365 if ((status == BluetoothGatt.GATT_SUCCESS) && 366 (descriptor.getUuid().equals(DESCRIPTOR_UUID))) { 367 notifyDescriptorRead(new String(descriptor.getValue())); 368 } 369 } 370 371 @Override 372 public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 373 int status) { 374 if ((status == BluetoothGatt.GATT_SUCCESS) && 375 (descriptor.getUuid().equals(DESCRIPTOR_UUID))) { 376 notifyDescriptorWrite(); 377 } 378 } 379 380 @Override 381 public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { 382 if (status == BluetoothGatt.GATT_SUCCESS) notifyReliableWriteCompleted(); 383 } 384 385 @Override 386 public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 387 if (status == BluetoothGatt.GATT_SUCCESS) notifyReadRemoteRssi(rssi); 388 } 389 }; 390 }