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.Arrays; 20 import java.util.UUID; 21 import java.util.List; 22 23 import android.app.Service; 24 import android.bluetooth.BluetoothAdapter; 25 import android.bluetooth.BluetoothDevice; 26 import android.bluetooth.BluetoothGatt; 27 import android.bluetooth.BluetoothGattCallback; 28 import android.bluetooth.BluetoothGattCharacteristic; 29 import android.bluetooth.BluetoothGattDescriptor; 30 import android.bluetooth.BluetoothGattService; 31 import android.bluetooth.BluetoothManager; 32 import android.bluetooth.BluetoothProfile; 33 import android.bluetooth.le.BluetoothLeScanner; 34 import android.bluetooth.le.ScanCallback; 35 import android.bluetooth.le.ScanFilter; 36 import android.bluetooth.le.ScanResult; 37 import android.bluetooth.le.ScanSettings; 38 import android.content.Context; 39 import android.content.Intent; 40 import android.os.Handler; 41 import android.os.IBinder; 42 import android.os.ParcelUuid; 43 import android.util.Log; 44 import android.widget.Toast; 45 46 public class BleClientService extends Service { 47 48 public static final boolean DEBUG = true; 49 public static final String TAG = "BleClientService"; 50 51 public static final int COMMAND_CONNECT = 0; 52 public static final int COMMAND_DISCONNECT = 1; 53 public static final int COMMAND_DISCOVER_SERVICE = 2; 54 public static final int COMMAND_READ_RSSI = 3; 55 public static final int COMMAND_WRITE_CHARACTERISTIC = 4; 56 public static final int COMMAND_READ_CHARACTERISTIC = 5; 57 public static final int COMMAND_WRITE_DESCRIPTOR = 6; 58 public static final int COMMAND_READ_DESCRIPTOR = 7; 59 public static final int COMMAND_SET_NOTIFICATION = 8; 60 public static final int COMMAND_BEGIN_WRITE = 9; 61 public static final int COMMAND_EXECUTE_WRITE = 10; 62 public static final int COMMAND_ABORT_RELIABLE = 11; 63 public static final int COMMAND_SCAN_START = 12; 64 public static final int COMMAND_SCAN_STOP = 13; 65 66 public static final String BLE_BLUETOOTH_CONNECTED = 67 "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_CONNECTED"; 68 public static final String BLE_BLUETOOTH_DISCONNECTED = 69 "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISCONNECTED"; 70 public static final String BLE_SERVICES_DISCOVERED = 71 "com.android.cts.verifier.bluetooth.BLE_SERVICES_DISCOVERED"; 72 public static final String BLE_CHARACTERISTIC_READ = 73 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ"; 74 public static final String BLE_CHARACTERISTIC_WRITE = 75 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE"; 76 public static final String BLE_CHARACTERISTIC_CHANGED = 77 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_CHANGED"; 78 public static final String BLE_DESCRIPTOR_READ = 79 "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ"; 80 public static final String BLE_DESCRIPTOR_WRITE = 81 "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE"; 82 public static final String BLE_RELIABLE_WRITE_COMPLETED = 83 "com.android.cts.verifier.bluetooth.BLE_RELIABLE_WRITE_COMPLETED"; 84 public static final String BLE_READ_REMOTE_RSSI = 85 "com.android.cts.verifier.bluetooth.BLE_READ_REMOTE_RSSI"; 86 87 public static final String EXTRA_COMMAND = 88 "com.android.cts.verifier.bluetooth.EXTRA_COMMAND"; 89 public static final String EXTRA_WRITE_VALUE = 90 "com.android.cts.verifier.bluetooth.EXTRA_WRITE_VALUE"; 91 public static final String EXTRA_BOOL = 92 "com.android.cts.verifier.bluetooth.EXTRA_BOOL"; 93 public static final String EXTRA_CHARACTERISTIC_VALUE = 94 "com.android.cts.verifier.bluetooth.EXTRA_CHARACTERISTIC_VALUE"; 95 public static final String EXTRA_DESCRIPTOR_VALUE = 96 "com.android.cts.verifier.bluetooth.EXTRA_DESCRIPTOR_VALUE"; 97 public static final String EXTRA_RSSI_VALUE = 98 "com.android.cts.verifier.bluetooth.EXTRA_RSSI_VALUE"; 99 public static final String EXTRA_ERROR_MESSAGE = 100 "com.android.cts.verifier.bluetooth.EXTRA_ERROR_MESSAGE"; 101 102 private static final UUID SERVICE_UUID = 103 UUID.fromString("00009999-0000-1000-8000-00805f9b34fb"); 104 private static final UUID CHARACTERISTIC_UUID = 105 UUID.fromString("00009998-0000-1000-8000-00805f9b34fb"); 106 private static final UUID UPDATE_CHARACTERISTIC_UUID = 107 UUID.fromString("00009997-0000-1000-8000-00805f9b34fb"); 108 private static final UUID DESCRIPTOR_UUID = 109 UUID.fromString("00009996-0000-1000-8000-00805f9b34fb"); 110 111 private static final String WRITE_VALUE = "TEST"; 112 113 private BluetoothManager mBluetoothManager; 114 private BluetoothAdapter mBluetoothAdapter; 115 private BluetoothDevice mDevice; 116 private BluetoothGatt mBluetoothGatt; 117 private BluetoothLeScanner mScanner; 118 private Handler mHandler; 119 private Context mContext; 120 121 @Override onCreate()122 public void onCreate() { 123 super.onCreate(); 124 125 mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 126 mBluetoothAdapter = mBluetoothManager.getAdapter(); 127 mScanner = mBluetoothAdapter.getBluetoothLeScanner(); 128 mHandler = new Handler(); 129 mContext = this; 130 startScan(); 131 } 132 133 @Override onStartCommand(Intent intent, int flags, int startId)134 public int onStartCommand(Intent intent, int flags, int startId) { 135 return START_NOT_STICKY; 136 } 137 138 @Override onBind(Intent intent)139 public IBinder onBind(Intent intent) { 140 return null; 141 } 142 143 @Override onDestroy()144 public void onDestroy() { 145 super.onDestroy(); 146 mBluetoothGatt.disconnect(); 147 mBluetoothGatt.close(); 148 mBluetoothGatt = null; 149 stopScan(); 150 } 151 writeCharacteristic(String writeValue)152 private void writeCharacteristic(String writeValue) { 153 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 154 if (characteristic == null) return; 155 characteristic.setValue(writeValue); 156 mBluetoothGatt.writeCharacteristic(characteristic); 157 } 158 readCharacteristic()159 private void readCharacteristic() { 160 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 161 if (characteristic != null) mBluetoothGatt.readCharacteristic(characteristic); 162 } 163 writeDescriptor(String writeValue)164 private void writeDescriptor(String writeValue) { 165 BluetoothGattDescriptor descriptor = getDescriptor(); 166 if (descriptor == null) return; 167 descriptor.setValue(writeValue.getBytes()); 168 mBluetoothGatt.writeDescriptor(descriptor); 169 } 170 readDescriptor()171 private void readDescriptor() { 172 BluetoothGattDescriptor descriptor = getDescriptor(); 173 if (descriptor != null) mBluetoothGatt.readDescriptor(descriptor); 174 } 175 setNotification(boolean enable)176 private void setNotification(boolean enable) { 177 BluetoothGattCharacteristic characteristic = getCharacteristic(UPDATE_CHARACTERISTIC_UUID); 178 if (characteristic != null) 179 mBluetoothGatt.setCharacteristicNotification(characteristic, enable); 180 } 181 notifyError(String message)182 private void notifyError(String message) { 183 showMessage(message); 184 } 185 notifyConnected()186 private void notifyConnected() { 187 showMessage("BLE connected"); 188 Intent intent = new Intent(BLE_BLUETOOTH_CONNECTED); 189 sendBroadcast(intent); 190 } 191 notifyDisconnected()192 private void notifyDisconnected() { 193 showMessage("BLE disconnected"); 194 Intent intent = new Intent(BLE_BLUETOOTH_DISCONNECTED); 195 sendBroadcast(intent); 196 } 197 notifyServicesDiscovered()198 private void notifyServicesDiscovered() { 199 showMessage("Service discovered"); 200 Intent intent = new Intent(BLE_SERVICES_DISCOVERED); 201 sendBroadcast(intent); 202 } 203 notifyCharacteristicRead(String value)204 private void notifyCharacteristicRead(String value) { 205 showMessage("Characteristic read: " + value); 206 Intent intent = new Intent(BLE_CHARACTERISTIC_READ); 207 intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value); 208 sendBroadcast(intent); 209 } 210 notifyCharacteristicWrite(String value)211 private void notifyCharacteristicWrite(String value) { 212 showMessage("Characteristic write: " + value); 213 Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE); 214 sendBroadcast(intent); 215 } 216 notifyCharacteristicChanged(String value)217 private void notifyCharacteristicChanged(String value) { 218 showMessage("Characteristic changed: " + value); 219 Intent intent = new Intent(BLE_CHARACTERISTIC_CHANGED); 220 intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value); 221 sendBroadcast(intent); 222 } 223 notifyDescriptorRead(String value)224 private void notifyDescriptorRead(String value) { 225 showMessage("Descriptor read: " + value); 226 Intent intent = new Intent(BLE_DESCRIPTOR_READ); 227 intent.putExtra(EXTRA_DESCRIPTOR_VALUE, value); 228 sendBroadcast(intent); 229 } 230 notifyDescriptorWrite(String value)231 private void notifyDescriptorWrite(String value) { 232 showMessage("Descriptor write: " + value); 233 Intent intent = new Intent(BLE_DESCRIPTOR_WRITE); 234 sendBroadcast(intent); 235 } 236 notifyReliableWriteCompleted()237 private void notifyReliableWriteCompleted() { 238 showMessage("Reliable write compelte"); 239 Intent intent = new Intent(BLE_RELIABLE_WRITE_COMPLETED); 240 sendBroadcast(intent); 241 } 242 notifyReadRemoteRssi(int rssi)243 private void notifyReadRemoteRssi(int rssi) { 244 showMessage("Remote rssi read: " + rssi); 245 Intent intent = new Intent(BLE_READ_REMOTE_RSSI); 246 intent.putExtra(EXTRA_RSSI_VALUE, rssi); 247 sendBroadcast(intent); 248 } 249 getService()250 private BluetoothGattService getService() { 251 if (mBluetoothGatt == null) return null; 252 253 BluetoothGattService service = mBluetoothGatt.getService(SERVICE_UUID); 254 if (service == null) { 255 showMessage("Service not found"); 256 return null; 257 } 258 return service; 259 } 260 getCharacteristic(UUID uuid)261 private BluetoothGattCharacteristic getCharacteristic(UUID uuid) { 262 BluetoothGattService service = getService(); 263 if (service == null) return null; 264 265 BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid); 266 if (characteristic == null) { 267 showMessage("Characteristic not found"); 268 return null; 269 } 270 return characteristic; 271 } 272 getDescriptor()273 private BluetoothGattDescriptor getDescriptor() { 274 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 275 if (characteristic == null) return null; 276 277 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID); 278 if (descriptor == null) { 279 showMessage("Descriptor not found"); 280 return null; 281 } 282 return descriptor; 283 } 284 showMessage(final String msg)285 private void showMessage(final String msg) { 286 mHandler.post(new Runnable() { 287 public void run() { 288 Toast.makeText(BleClientService.this, msg, Toast.LENGTH_SHORT).show(); 289 } 290 }); 291 } 292 sleep(int millis)293 private void sleep(int millis) { 294 try { 295 Thread.sleep(millis); 296 } catch (InterruptedException e) { 297 Log.e(TAG, "Error in thread sleep", e); 298 } 299 } 300 reliableWrite()301 private void reliableWrite() { 302 mBluetoothGatt.beginReliableWrite(); 303 sleep(1000); 304 writeCharacteristic(WRITE_VALUE); 305 sleep(1000); 306 if (!mBluetoothGatt.executeReliableWrite()) { 307 Log.w(TAG, "reliable write failed"); 308 } 309 sleep(1000); 310 mBluetoothGatt.abortReliableWrite(); 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) { 319 notifyConnected(); 320 stopScan(); 321 sleep(1000); 322 mBluetoothGatt.discoverServices(); 323 } else if (status == BluetoothProfile.STATE_DISCONNECTED) { 324 notifyDisconnected(); 325 } 326 } else { 327 showMessage("Failed to connect"); 328 } 329 } 330 331 @Override 332 public void onServicesDiscovered(BluetoothGatt gatt, int status) { 333 if (DEBUG) Log.d(TAG, "onServiceDiscovered"); 334 if ((status == BluetoothGatt.GATT_SUCCESS) && 335 (mBluetoothGatt.getService(SERVICE_UUID) != null)) { 336 notifyServicesDiscovered(); 337 sleep(1000); 338 writeCharacteristic(WRITE_VALUE); 339 } 340 } 341 342 @Override 343 public void onCharacteristicWrite(BluetoothGatt gatt, 344 BluetoothGattCharacteristic characteristic, int status) { 345 String value = characteristic.getStringValue(0); 346 if (DEBUG) Log.d(TAG, "onCharacteristicWrite: characteristic.val=" 347 + value + " status=" + status); 348 BluetoothGattCharacteristic mCharacteristic = getCharacteristic(CHARACTERISTIC_UUID); 349 if ((status == BluetoothGatt.GATT_SUCCESS) && 350 (value.equals(mCharacteristic.getStringValue(0)))) { 351 notifyCharacteristicWrite(value); 352 sleep(1000); 353 readCharacteristic(); 354 } else { 355 notifyError("Failed to write characteristic: " + value); 356 } 357 } 358 359 @Override 360 public void onCharacteristicRead(BluetoothGatt gatt, 361 BluetoothGattCharacteristic characteristic, int status) { 362 if (DEBUG) Log.d(TAG, "onCharacteristicRead"); 363 if ((status == BluetoothGatt.GATT_SUCCESS) && 364 (characteristic.getUuid().equals(CHARACTERISTIC_UUID))) { 365 notifyCharacteristicRead(characteristic.getStringValue(0)); 366 sleep(1000); 367 writeDescriptor(WRITE_VALUE); 368 } else { 369 notifyError("Failed to read characteristic"); 370 } 371 } 372 373 @Override 374 public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 375 int status) { 376 if (DEBUG) Log.d(TAG, "onDescriptorWrite"); 377 if ((status == BluetoothGatt.GATT_SUCCESS) && 378 (descriptor.getUuid().equals(DESCRIPTOR_UUID))) { 379 notifyDescriptorWrite(new String(descriptor.getValue())); 380 sleep(1000); 381 readDescriptor(); 382 } else { 383 notifyError("Failed to write descriptor"); 384 } 385 } 386 387 @Override 388 public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 389 int status) { 390 if (DEBUG) Log.d(TAG, "onDescriptorRead"); 391 if ((status == BluetoothGatt.GATT_SUCCESS) && 392 (descriptor.getUuid() != null) && 393 (descriptor.getUuid().equals(DESCRIPTOR_UUID))) { 394 notifyDescriptorRead(new String(descriptor.getValue())); 395 sleep(1000); 396 setNotification(true); 397 } else { 398 notifyError("Failed to read descriptor"); 399 } 400 } 401 402 @Override 403 public void onCharacteristicChanged(BluetoothGatt gatt, 404 BluetoothGattCharacteristic characteristic) { 405 if (DEBUG) Log.d(TAG, "onCharacteristicChanged"); 406 if ((characteristic.getUuid() != null) && 407 (characteristic.getUuid().equals(UPDATE_CHARACTERISTIC_UUID))) { 408 notifyCharacteristicChanged(characteristic.getStringValue(0)); 409 setNotification(false); 410 sleep(1000); 411 mBluetoothGatt.readRemoteRssi(); 412 } 413 } 414 415 @Override 416 public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { 417 if (DEBUG) Log.d(TAG, "onReliableWriteComplete: " + status); 418 if (status == BluetoothGatt.GATT_SUCCESS) { 419 notifyReliableWriteCompleted(); 420 } else { 421 notifyError("Failed to complete reliable write: " + status); 422 } 423 sleep(1000); 424 mBluetoothGatt.disconnect(); 425 } 426 427 @Override 428 public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 429 if (DEBUG) Log.d(TAG, "onReadRemoteRssi"); 430 if (status == BluetoothGatt.GATT_SUCCESS) { 431 notifyReadRemoteRssi(rssi); 432 } else { 433 notifyError("Failed to read remote rssi"); 434 } 435 sleep(1000); 436 reliableWrite(); 437 } 438 }; 439 440 private final ScanCallback mScanCallback = new ScanCallback() { 441 @Override 442 public void onScanResult(int callbackType, ScanResult result) { 443 if (mBluetoothGatt == null) { 444 mBluetoothGatt = result.getDevice().connectGatt(mContext, false, mGattCallbacks); 445 } 446 } 447 }; 448 startScan()449 private void startScan() { 450 if (DEBUG) Log.d(TAG, "startScan"); 451 List<ScanFilter> filter = Arrays.asList(new ScanFilter.Builder().setServiceUuid( 452 new ParcelUuid(BleServerService.ADV_SERVICE_UUID)).build()); 453 ScanSettings setting = new ScanSettings.Builder() 454 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); 455 mScanner.startScan(filter, setting, mScanCallback); 456 } 457 stopScan()458 private void stopScan() { 459 if (DEBUG) Log.d(TAG, "stopScan"); 460 mScanner.stopScan(mScanCallback); 461 } 462 } 463