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 17package com.android.cts.verifier.bluetooth; 18 19import java.util.Date; 20import java.util.List; 21import java.util.Timer; 22import java.util.TimerTask; 23import java.util.UUID; 24 25import android.app.Service; 26import android.bluetooth.BluetoothAdapter; 27import android.bluetooth.BluetoothDevice; 28import android.bluetooth.BluetoothGatt; 29import android.bluetooth.BluetoothGattCharacteristic; 30import android.bluetooth.BluetoothGattDescriptor; 31import android.bluetooth.BluetoothGattServer; 32import android.bluetooth.BluetoothGattServerCallback; 33import android.bluetooth.BluetoothGattService; 34import android.bluetooth.BluetoothManager; 35import android.bluetooth.BluetoothProfile; 36import android.bluetooth.le.AdvertiseCallback; 37import android.bluetooth.le.AdvertiseData; 38import android.bluetooth.le.AdvertiseSettings; 39import android.bluetooth.le.BluetoothLeAdvertiser; 40import android.content.Context; 41import android.content.Intent; 42import android.os.Handler; 43import android.os.IBinder; 44import android.os.ParcelUuid; 45import android.util.Log; 46import android.widget.Toast; 47 48public class BleServerService extends Service { 49 50 public static final boolean DEBUG = true; 51 public static final String TAG = "BleServerService"; 52 53 public static final int COMMAND_ADD_SERVICE = 0; 54 public static final int COMMAND_WRITE_CHARACTERISTIC = 1; 55 public static final int COMMAND_WRITE_DESCRIPTOR = 2; 56 57 public static final String BLE_SERVER_CONNECTED = 58 "com.android.cts.verifier.bluetooth.BLE_SERVER_CONNECTED"; 59 public static final String BLE_SERVER_DISCONNECTED = 60 "com.android.cts.verifier.bluetooth.BLE_SERVER_DISCONNECTED"; 61 public static final String BLE_SERVICE_ADDED = 62 "com.android.cts.verifier.bluetooth.BLE_SERVICE_ADDED"; 63 public static final String BLE_CHARACTERISTIC_READ_REQUEST = 64 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST"; 65 public static final String BLE_CHARACTERISTIC_WRITE_REQUEST = 66 "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST"; 67 public static final String BLE_DESCRIPTOR_READ_REQUEST = 68 "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_READ_REQUEST"; 69 public static final String BLE_DESCRIPTOR_WRITE_REQUEST = 70 "com.android.cts.verifier.bluetooth.BLE_DESCRIPTOR_WRITE_REQUEST"; 71 public static final String BLE_EXECUTE_WRITE = 72 "com.android.cts.verifier.bluetooth.BLE_EXECUTE_WRITE"; 73 public static final String BLE_OPEN_FAIL = 74 "com.android.cts.verifier.bluetooth.BLE_OPEN_FAIL"; 75 76 private static final UUID SERVICE_UUID = 77 UUID.fromString("00009999-0000-1000-8000-00805f9b34fb"); 78 private static final UUID CHARACTERISTIC_UUID = 79 UUID.fromString("00009998-0000-1000-8000-00805f9b34fb"); 80 private static final UUID UPDATE_CHARACTERISTIC_UUID = 81 UUID.fromString("00009997-0000-1000-8000-00805f9b34fb"); 82 private static final UUID DESCRIPTOR_UUID = 83 UUID.fromString("00009996-0000-1000-8000-00805f9b34fb"); 84 public static final UUID ADV_SERVICE_UUID= 85 UUID.fromString("00003333-0000-1000-8000-00805f9b34fb"); 86 87 private BluetoothManager mBluetoothManager; 88 private BluetoothGattServer mGattServer; 89 private BluetoothGattService mService; 90 private BluetoothDevice mDevice; 91 private Timer mNotificationTimer; 92 private Handler mHandler; 93 private String mReliableWriteValue; 94 private BluetoothLeAdvertiser mAdvertiser; 95 96 @Override 97 public void onCreate() { 98 super.onCreate(); 99 100 mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 101 mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser(); 102 mGattServer = mBluetoothManager.openGattServer(this, mCallbacks); 103 mService = createService(); 104 if (mGattServer != null) { 105 mGattServer.addService(mService); 106 } 107 mDevice = null; 108 mReliableWriteValue = null; 109 110 mHandler = new Handler(); 111 if (mGattServer == null) { 112 notifyOpenFail(); 113 } 114 } 115 116 @Override 117 public int onStartCommand(Intent intent, int flags, int startId) { 118 startAdvertise(); 119 return START_NOT_STICKY; 120 } 121 122 @Override 123 public IBinder onBind(Intent intent) { 124 return null; 125 } 126 127 @Override 128 public void onDestroy() { 129 super.onDestroy(); 130 stopAdvertise(); 131 if (mGattServer == null) { 132 return; 133 } 134 if (mDevice != null) mGattServer.cancelConnection(mDevice); 135 mGattServer.close(); 136 } 137 138 private void writeCharacteristic(String writeValue) { 139 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 140 if (characteristic != null) return; 141 characteristic.setValue(writeValue); 142 } 143 144 private void writeDescriptor(String writeValue) { 145 BluetoothGattDescriptor descriptor = getDescriptor(); 146 if (descriptor == null) return; 147 descriptor.setValue(writeValue.getBytes()); 148 } 149 150 private void notifyOpenFail() { 151 if (DEBUG) Log.d(TAG, "notifyOpenFail"); 152 Intent intent = new Intent(BLE_OPEN_FAIL); 153 sendBroadcast(intent); 154 } 155 156 private void notifyConnected() { 157 if (DEBUG) Log.d(TAG, "notifyConnected"); 158 Intent intent = new Intent(BLE_SERVER_CONNECTED); 159 sendBroadcast(intent); 160 } 161 162 private void notifyDisconnected() { 163 if (DEBUG) Log.d(TAG, "notifyDisconnected"); 164 Intent intent = new Intent(BLE_SERVER_DISCONNECTED); 165 sendBroadcast(intent); 166 } 167 168 private void notifyServiceAdded() { 169 if (DEBUG) Log.d(TAG, "notifyServiceAdded"); 170 Intent intent = new Intent(BLE_SERVICE_ADDED); 171 sendBroadcast(intent); 172 } 173 174 private void notifyCharacteristicReadRequest() { 175 if (DEBUG) Log.d(TAG, "notifyCharacteristicReadRequest"); 176 Intent intent = new Intent(BLE_CHARACTERISTIC_READ_REQUEST); 177 sendBroadcast(intent); 178 } 179 180 private void notifyCharacteristicWriteRequest() { 181 if (DEBUG) Log.d(TAG, "notifyCharacteristicWriteRequest"); 182 Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE_REQUEST); 183 sendBroadcast(intent); 184 } 185 186 private void notifyDescriptorReadRequest() { 187 if (DEBUG) Log.d(TAG, "notifyDescriptorReadRequest"); 188 Intent intent = new Intent(BLE_DESCRIPTOR_READ_REQUEST); 189 sendBroadcast(intent); 190 } 191 192 private void notifyDescriptorWriteRequest() { 193 if (DEBUG) Log.d(TAG, "notifyDescriptorWriteRequest"); 194 Intent intent = new Intent(BLE_DESCRIPTOR_WRITE_REQUEST); 195 sendBroadcast(intent); 196 } 197 198 private void notifyExecuteWrite() { 199 if (DEBUG) Log.d(TAG, "notifyExecuteWrite"); 200 Intent intent = new Intent(BLE_EXECUTE_WRITE); 201 sendBroadcast(intent); 202 } 203 204 private BluetoothGattCharacteristic getCharacteristic(UUID uuid) { 205 BluetoothGattCharacteristic characteristic = 206 mService.getCharacteristic(uuid); 207 if (characteristic == null) { 208 showMessage("Characteristic not found"); 209 return null; 210 } 211 return characteristic; 212 } 213 214 private BluetoothGattDescriptor getDescriptor() { 215 BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID); 216 if (characteristic == null) return null; 217 218 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(DESCRIPTOR_UUID); 219 if (descriptor == null) { 220 showMessage("Descriptor not found"); 221 return null; 222 } 223 return descriptor; 224 } 225 226 private BluetoothGattService createService() { 227 BluetoothGattService service = 228 new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); 229 BluetoothGattCharacteristic characteristic = 230 new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11); 231 BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11); 232 characteristic.addDescriptor(descriptor); 233 service.addCharacteristic(characteristic); 234 235 BluetoothGattCharacteristic notiCharacteristic = 236 new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID, 0x10, 0x00); 237 service.addCharacteristic(notiCharacteristic); 238 239 return service; 240 } 241 242 private void beginNotification() { 243 TimerTask task = new TimerTask() { 244 @Override 245 public void run() { 246 if (mGattServer == null) { 247 if (DEBUG) Log.d(TAG, "GattServer is null, return"); 248 return; 249 } 250 BluetoothGattCharacteristic characteristic = 251 mService.getCharacteristic(UPDATE_CHARACTERISTIC_UUID); 252 if (characteristic == null) return; 253 254 String date = (new Date()).toString(); 255 characteristic.setValue(date); 256 mGattServer.notifyCharacteristicChanged(mDevice, characteristic, false); 257 } 258 }; 259 mNotificationTimer = new Timer(); 260 mNotificationTimer.schedule(task, 0, 1000); 261 } 262 263 private void stopNotification() { 264 if (mNotificationTimer == null) return; 265 mNotificationTimer.cancel(); 266 mNotificationTimer = null; 267 } 268 269 private void showMessage(final String msg) { 270 mHandler.post(new Runnable() { 271 public void run() { 272 Toast.makeText(BleServerService.this, msg, Toast.LENGTH_SHORT).show(); 273 } 274 }); 275 } 276 277 private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() { 278 @Override 279 public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { 280 if (DEBUG) Log.d(TAG, "onConnectionStateChange: newState=" + newState); 281 if (status == BluetoothGatt.GATT_SUCCESS) { 282 if (newState == BluetoothProfile.STATE_CONNECTED) { 283 mDevice = device; 284 notifyConnected(); 285 beginNotification(); 286 } else if (status == BluetoothProfile.STATE_DISCONNECTED) { 287 stopNotification(); 288 notifyDisconnected(); 289 mDevice = null; 290 } 291 } 292 } 293 294 @Override 295 public void onServiceAdded(int status, BluetoothGattService service) { 296 if (DEBUG) Log.d(TAG, "onServiceAdded()"); 297 if (status == BluetoothGatt.GATT_SUCCESS) notifyServiceAdded(); 298 } 299 300 @Override 301 public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, 302 int offset, BluetoothGattCharacteristic characteristic) { 303 if (mGattServer == null) { 304 if (DEBUG) Log.d(TAG, "GattServer is null, return"); 305 return; 306 } 307 if (DEBUG) Log.d(TAG, "onCharacteristicReadRequest()"); 308 309 notifyCharacteristicReadRequest(); 310 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, 311 characteristic.getValue()); 312 } 313 314 @Override 315 public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, 316 BluetoothGattCharacteristic characteristic, 317 boolean preparedWrite, boolean responseNeeded, 318 int offset, byte[] value) { 319 if (mGattServer == null) { 320 if (DEBUG) Log.d(TAG, "GattServer is null, return"); 321 return; 322 } 323 if (DEBUG) Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite); 324 325 notifyCharacteristicWriteRequest(); 326 if (preparedWrite) mReliableWriteValue = new String(value); 327 else characteristic.setValue(value); 328 329 if (responseNeeded) 330 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null); 331 } 332 333 @Override 334 public void onDescriptorReadRequest(BluetoothDevice device, int requestId, 335 int offset, BluetoothGattDescriptor descriptor) { 336 if (mGattServer == null) { 337 if (DEBUG) Log.d(TAG, "GattServer is null, return"); 338 return; 339 } 340 if (DEBUG) Log.d(TAG, "onDescriptorReadRequest(): (descriptor == getDescriptor())=" 341 + (descriptor == getDescriptor())); 342 343 notifyDescriptorReadRequest(); 344 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, 345 descriptor.getValue()); 346 } 347 348 @Override 349 public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, 350 BluetoothGattDescriptor descriptor, 351 boolean preparedWrite, boolean responseNeeded, 352 int offset, byte[] value) { 353 if (mGattServer == null) { 354 if (DEBUG) Log.d(TAG, "GattServer is null, return"); 355 return; 356 } 357 if (DEBUG) Log.d(TAG, "onDescriptorWriteRequest(): (descriptor == getDescriptor())=" 358 + (descriptor == getDescriptor())); 359 360 notifyDescriptorWriteRequest(); 361 descriptor.setValue(value); 362 if (responseNeeded) 363 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null); 364 } 365 366 @Override 367 public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) { 368 if (mGattServer == null) { 369 if (DEBUG) Log.d(TAG, "GattServer is null, return"); 370 return; 371 } 372 if (DEBUG) Log.d(TAG, "onExecuteWrite"); 373 if (execute) { 374 notifyExecuteWrite(); 375 getCharacteristic(CHARACTERISTIC_UUID).setValue(mReliableWriteValue); 376 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null); 377 } 378 } 379 }; 380 381 private void startAdvertise() { 382 if (DEBUG) Log.d(TAG, "startAdvertise"); 383 AdvertiseData data = new AdvertiseData.Builder() 384 .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1,2,3}) 385 .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID)) 386 .build(); 387 AdvertiseSettings setting = new AdvertiseSettings.Builder() 388 .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) 389 .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) 390 .setConnectable(true) 391 .build(); 392 mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback); 393 } 394 395 private void stopAdvertise() { 396 if (DEBUG) Log.d(TAG, "stopAdvertise"); 397 mAdvertiser.stopAdvertising(mAdvertiseCallback); 398 } 399 400 private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){}; 401} 402 403