1 /* 2 * Copyright 2018 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 android.app.Service; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothDevice; 22 import android.bluetooth.BluetoothGatt; 23 import android.bluetooth.BluetoothGattCharacteristic; 24 import android.bluetooth.BluetoothGattDescriptor; 25 import android.bluetooth.BluetoothGattServer; 26 import android.bluetooth.BluetoothGattServerCallback; 27 import android.bluetooth.BluetoothGattService; 28 import android.bluetooth.BluetoothManager; 29 import android.bluetooth.BluetoothProfile; 30 import android.bluetooth.BluetoothServerSocket; 31 import android.bluetooth.BluetoothSocket; 32 import android.bluetooth.le.AdvertiseCallback; 33 import android.bluetooth.le.AdvertiseData; 34 import android.bluetooth.le.AdvertiseSettings; 35 import android.bluetooth.le.BluetoothLeAdvertiser; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.os.Build; 39 import android.os.Handler; 40 import android.os.IBinder; 41 import android.os.Message; 42 import android.os.ParcelUuid; 43 import android.util.Log; 44 import android.widget.Toast; 45 46 import com.android.cts.verifier.R; 47 48 import java.io.IOException; 49 50 import java.util.ArrayList; 51 import java.util.Arrays; 52 import java.util.HashMap; 53 import java.util.LinkedHashMap; 54 import java.util.List; 55 import java.util.Set; 56 import java.util.Timer; 57 import java.util.UUID; 58 59 public class BleCocServerService extends Service { 60 61 public static final boolean DEBUG = true; 62 public static final String TAG = "BleCocServerService"; 63 64 public static final int COMMAND_ADD_SERVICE = 0; 65 public static final int COMMAND_WRITE_CHARACTERISTIC = 1; 66 public static final int COMMAND_WRITE_DESCRIPTOR = 2; 67 68 public static final int TEST_DATA_EXCHANGE_BUFSIZE = 8 * 1024; 69 70 public static final String BLE_BLUETOOTH_MISMATCH_SECURE = 71 "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_SECURE"; 72 public static final String BLE_BLUETOOTH_MISMATCH_INSECURE = 73 "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_MISMATCH_INSECURE"; 74 public static final String BLE_BLUETOOTH_DISABLED = 75 "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISABLED"; 76 77 public static final String BLE_ACTION_COC_SERVER_INSECURE = 78 "com.android.cts.verifier.bluetooth.BLE_ACTION_COC_SERVER_INSECURE"; 79 public static final String BLE_ACTION_COC_SERVER_SECURE = 80 "com.android.cts.verifier.bluetooth.BLE_ACTION_COC_SERVER_SECURE"; 81 82 public static final String BLE_ACTION_SERVER_SECURE = 83 "com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_SECURE"; 84 public static final String BLE_ACTION_SERVER_NON_SECURE = 85 "com.android.cts.verifier.bluetooth.BLE_ACTION_SERVER_NON_SECURE"; 86 87 public static final String BLE_LE_CONNECTED = 88 "com.android.cts.verifier.bluetooth.BLE_LE_CONNECTED"; 89 public static final String BLE_COC_LISTENER_CREATED = 90 "com.android.cts.verifier.bluetooth.BLE_COC_LISTENER_CREATED"; 91 public static final String BLE_PSM_READ = 92 "com.android.cts.verifier.bluetooth.BLE_PSM_READ"; 93 public static final String BLE_COC_CONNECTED = 94 "com.android.cts.verifier.bluetooth.BLE_COC_CONNECTED"; 95 public static final String BLE_CONNECTION_TYPE_CHECKED = 96 "com.android.cts.verifier.bluetooth.BLE_CONNECTION_TYPE_CHECKED"; 97 public static final String BLE_DATA_8BYTES_READ = 98 "com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_READ"; 99 public static final String BLE_DATA_LARGEBUF_READ = 100 "com.android.cts.verifier.bluetooth.BLE_DATA_LARGEBUF_READ"; 101 public static final String BLE_DATA_8BYTES_SENT = 102 "com.android.cts.verifier.bluetooth.BLE_DATA_8BYTES_SENT"; 103 public static final String BLE_LE_DISCONNECTED = 104 "com.android.cts.verifier.bluetooth.BLE_LE_DISCONNECTED"; 105 public static final String BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES = 106 "com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES"; 107 public static final String BLE_COC_SERVER_ACTION_EXCHANGE_DATA = 108 "com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_EXCHANGE_DATA"; 109 public static final String BLE_COC_SERVER_ACTION_DISCONNECT = 110 "com.android.cts.verifier.bluetooth.BLE_COC_SERVER_ACTION_DISCONNECT"; 111 112 public static final String BLE_SERVER_DISCONNECTED = 113 "com.android.cts.verifier.bluetooth.BLE_SERVER_DISCONNECTED"; 114 public static final String BLE_OPEN_FAIL = 115 "com.android.cts.verifier.bluetooth.BLE_OPEN_FAIL"; 116 public static final String BLE_ADVERTISE_UNSUPPORTED = 117 "com.android.cts.verifier.bluetooth.BLE_ADVERTISE_UNSUPPORTED"; 118 public static final String BLE_ADD_SERVICE_FAIL = 119 "com.android.cts.verifier.bluetooth.BLE_ADD_SERVICE_FAIL"; 120 121 private static final UUID SERVICE_UUID = 122 UUID.fromString("00009999-0000-1000-8000-00805f9b34fb"); 123 private static final UUID CHARACTERISTIC_UUID = 124 UUID.fromString("00009998-0000-1000-8000-00805f9b34fb"); 125 private static final UUID CHARACTERISTIC_RESULT_UUID = 126 UUID.fromString("00009974-0000-1000-8000-00805f9b34fb"); 127 private static final UUID UPDATE_CHARACTERISTIC_UUID = 128 UUID.fromString("00009997-0000-1000-8000-00805f9b34fb"); 129 private static final UUID DESCRIPTOR_UUID = 130 UUID.fromString("00009996-0000-1000-8000-00805f9b34fb"); 131 public static final UUID ADV_COC_SERVICE_UUID= 132 UUID.fromString("00003334-0000-1000-8000-00805f9b34fb"); 133 134 private static final UUID SERVICE_UUID_ADDITIONAL = 135 UUID.fromString("00009995-0000-1000-8000-00805f9b34fb"); 136 private static final UUID SERVICE_UUID_INCLUDED = 137 UUID.fromString("00009994-0000-1000-8000-00805f9b34fb"); 138 139 // Variable for registration permission of Descriptor 140 private static final UUID DESCRIPTOR_NO_READ_UUID = 141 UUID.fromString("00009973-0000-1000-8000-00805f9b34fb"); 142 private static final UUID DESCRIPTOR_NO_WRITE_UUID = 143 UUID.fromString("00009972-0000-1000-8000-00805f9b34fb"); 144 private static final UUID DESCRIPTOR_NEED_ENCRYPTED_READ_UUID = 145 UUID.fromString("00009969-0000-1000-8000-00805f9b34fb"); 146 private static final UUID DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID = 147 UUID.fromString("00009968-0000-1000-8000-00805f9b34fb"); 148 149 private static final int CONN_INTERVAL = 150; // connection interval 150ms 150 151 private static final int EXECUTION_DELAY = 1500; 152 153 // Delay of notification when secure test failed to start. 154 private static final long NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE = 5 * 1000; 155 156 public static final String WRITE_VALUE = "SERVER_TEST"; 157 private static final String NOTIFY_VALUE = "NOTIFY_TEST"; 158 private static final String INDICATE_VALUE = "INDICATE_TEST"; 159 public static final String READ_NO_PERMISSION = "READ_NO_CHAR"; 160 public static final String WRITE_NO_PERMISSION = "WRITE_NO_CHAR"; 161 public static final String DESCRIPTOR_READ_NO_PERMISSION = "READ_NO_DESC"; 162 public static final String DESCRIPTOR_WRITE_NO_PERMISSION = "WRITE_NO_DESC"; 163 164 private BluetoothManager mBluetoothManager; 165 private BluetoothGattServer mGattServer; 166 private BluetoothGattService mService; 167 private BluetoothDevice mDevice; 168 private Handler mHandler; 169 private BluetoothLeAdvertiser mAdvertiser; 170 private boolean mSecure; 171 private int mMtuSize = -1; 172 173 private BluetoothServerSocket mServerSocket; 174 private int mPsm = -1; 175 private BluetoothGattCharacteristic mLePsmCharacteristic; 176 BluetoothChatService mChatService; 177 178 private int mNextReadExpectedLen = -1; 179 private String mNextReadCompletionIntent; 180 private int mTotalReadLen = 0; 181 private byte mNextReadByte; 182 private int mNextWriteExpectedLen = -1; 183 private String mNextWriteCompletionIntent = null; 184 185 // Handler for communicating task with peer. 186 private TestTaskQueue mTaskQueue; 187 188 // current test category 189 private String mCurrentAction; 190 191 // Task to notify failure of starting secure test. 192 // Secure test calls BluetoothDevice#createBond() when devices were not paired. 193 // createBond() causes onConnectionStateChange() twice, and it works as strange sequence. 194 // At the first onConnectionStateChange(), target device is not paired (bond state is 195 // BluetoothDevice.BOND_NONE). 196 // At the second onConnectionStateChange(), target devices is paired (bond state is 197 // BluetoothDevice.BOND_BONDED). 198 // CTS Verifier will perform lazy check of bond state. Verifier checks bond state 199 // after NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE from the first onConnectionStateChange(). 200 private Runnable mNotificationTaskOfSecureTestStartFailure; 201 202 @Override onCreate()203 public void onCreate() { 204 super.onCreate(); 205 206 mTaskQueue = new TestTaskQueue(getClass().getName() + "_taskHandlerThread"); 207 208 mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 209 mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser(); 210 mGattServer = mBluetoothManager.openGattServer(this, mCallbacks); 211 212 mService = createService(); 213 214 mDevice = null; 215 216 mHandler = new Handler(); 217 if (!mBluetoothManager.getAdapter().isEnabled()) { 218 notifyBluetoothDisabled(); 219 } else if (mGattServer == null) { 220 notifyOpenFail(); 221 } else if (mAdvertiser == null) { 222 notifyAdvertiseUnsupported(); 223 } else { 224 // start adding services 225 mSecure = false; 226 if (!mGattServer.addService(mService)) { 227 notifyAddServiceFail(); 228 } 229 } 230 } 231 notifyBluetoothDisabled()232 private void notifyBluetoothDisabled() { 233 Intent intent = new Intent(BLE_BLUETOOTH_DISABLED); 234 sendBroadcast(intent); 235 } 236 notifyMismatchSecure()237 private void notifyMismatchSecure() { 238 Intent intent = new Intent(BLE_BLUETOOTH_MISMATCH_SECURE); 239 sendBroadcast(intent); 240 } 241 242 @Override onStartCommand(Intent intent, int flags, int startId)243 public int onStartCommand(Intent intent, int flags, int startId) { 244 String action = intent.getAction(); 245 if (action != null) { 246 if (DEBUG) { 247 Log.d(TAG, "onStartCommand: action=" + action); 248 } 249 mTaskQueue.addTask(new Runnable() { 250 @Override 251 public void run() { 252 onTestFinish(intent.getAction()); 253 } 254 }, EXECUTION_DELAY); 255 } 256 return START_NOT_STICKY; 257 } 258 startServerTest(boolean secure)259 private void startServerTest(boolean secure) { 260 mSecure = secure; 261 262 if (mBluetoothManager.getAdapter().isEnabled() && (mChatService == null)) { 263 createChatService(); 264 } 265 266 if (mBluetoothManager.getAdapter().isEnabled() && (mAdvertiser != null)) { 267 startAdvertise(); 268 } 269 } 270 sendMessage(byte[] buf)271 private void sendMessage(byte[] buf) { 272 mChatService.write(buf); 273 } 274 sendData8bytes()275 private void sendData8bytes() { 276 if (DEBUG) Log.d(TAG, "sendData8bytes"); 277 278 final byte[] buf = new byte[]{1,2,3,4,5,6,7,8}; 279 mNextWriteExpectedLen = 8; 280 mNextWriteCompletionIntent = BLE_DATA_8BYTES_SENT; 281 sendMessage(buf); 282 } 283 sendDataLargeBuf()284 private void sendDataLargeBuf() { 285 final int len = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE; 286 if (DEBUG) Log.d(TAG, "sendDataLargeBuf of size=" + len); 287 288 byte[] buf = new byte[len]; 289 for (int i = 0; i < len; i++) { 290 buf[i] = (byte)(i + 1); 291 } 292 mNextWriteExpectedLen = len; 293 mNextWriteCompletionIntent = null; 294 sendMessage(buf); 295 } 296 onTestFinish(String action)297 private void onTestFinish(String action) { 298 mCurrentAction = action; 299 if (mCurrentAction != null) { 300 switch (mCurrentAction) { 301 case BLE_ACTION_COC_SERVER_INSECURE: 302 startServerTest(false); 303 break; 304 case BLE_ACTION_COC_SERVER_SECURE: 305 startServerTest(true); 306 break; 307 case BLE_COC_SERVER_ACTION_SEND_DATA_8BYTES: 308 sendData8bytes(); 309 break; 310 case BLE_COC_SERVER_ACTION_EXCHANGE_DATA: 311 sendDataLargeBuf(); 312 break; 313 case BLE_COC_SERVER_ACTION_DISCONNECT: 314 if (mChatService != null) { 315 mChatService.stop(); 316 } 317 notifyDisconnected(); 318 break; 319 default: 320 Log.e(TAG, "Error: Unhandled or invalid action=" + mCurrentAction); 321 } 322 } 323 } 324 325 @Override onBind(Intent intent)326 public IBinder onBind(Intent intent) { 327 return null; 328 } 329 330 @Override onDestroy()331 public void onDestroy() { 332 super.onDestroy(); 333 334 if (mChatService != null) { 335 mChatService.stop(); 336 } 337 338 cancelNotificationTaskOfSecureTestStartFailure(); 339 stopAdvertise(); 340 341 mTaskQueue.quit(); 342 343 if (mGattServer == null) { 344 return; 345 } 346 if (mDevice != null) { 347 mGattServer.cancelConnection(mDevice); 348 } 349 mGattServer.clearServices(); 350 mGattServer.close(); 351 } 352 notifyOpenFail()353 private void notifyOpenFail() { 354 if (DEBUG) { 355 Log.d(TAG, "notifyOpenFail"); 356 } 357 Intent intent = new Intent(BLE_OPEN_FAIL); 358 sendBroadcast(intent); 359 } 360 notifyAddServiceFail()361 private void notifyAddServiceFail() { 362 if (DEBUG) { 363 Log.d(TAG, "notifyAddServiceFail"); 364 } 365 Intent intent = new Intent(BLE_ADD_SERVICE_FAIL); 366 sendBroadcast(intent); 367 } 368 notifyAdvertiseUnsupported()369 private void notifyAdvertiseUnsupported() { 370 if (DEBUG) { 371 Log.d(TAG, "notifyAdvertiseUnsupported"); 372 } 373 Intent intent = new Intent(BLE_ADVERTISE_UNSUPPORTED); 374 sendBroadcast(intent); 375 } 376 notifyConnected()377 private void notifyConnected() { 378 if (DEBUG) { 379 Log.d(TAG, "notifyConnected"); 380 } 381 Intent intent = new Intent(BLE_LE_CONNECTED); 382 sendBroadcast(intent); 383 } 384 notifyDisconnected()385 private void notifyDisconnected() { 386 if (DEBUG) { 387 Log.d(TAG, "notifyDisconnected"); 388 } 389 Intent intent = new Intent(BLE_SERVER_DISCONNECTED); 390 sendBroadcast(intent); 391 } 392 createService()393 private BluetoothGattService createService() { 394 BluetoothGattService service = 395 new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); 396 BluetoothGattCharacteristic characteristic = 397 new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11); 398 characteristic.setValue(WRITE_VALUE.getBytes()); 399 400 BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11); 401 descriptor.setValue(WRITE_VALUE.getBytes()); 402 characteristic.addDescriptor(descriptor); 403 404 BluetoothGattDescriptor descriptor_permission = 405 new BluetoothGattDescriptor(DESCRIPTOR_NO_READ_UUID, 0x10); 406 characteristic.addDescriptor(descriptor_permission); 407 408 descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_WRITE_UUID, 0x01); 409 characteristic.addDescriptor(descriptor_permission); 410 411 service.addCharacteristic(characteristic); 412 413 // Registered the characteristic of PSM Value 414 mLePsmCharacteristic = 415 new BluetoothGattCharacteristic(BleCocClientService.LE_PSM_CHARACTERISTIC_UUID, 416 BluetoothGattCharacteristic.PROPERTY_READ, 417 BluetoothGattCharacteristic.PERMISSION_READ); 418 service.addCharacteristic(mLePsmCharacteristic); 419 420 return service; 421 } 422 showMessage(final String msg)423 private void showMessage(final String msg) { 424 mHandler.post(new Runnable() { 425 public void run() { 426 Toast.makeText(BleCocServerService.this, msg, Toast.LENGTH_SHORT).show(); 427 } 428 }); 429 } 430 cancelNotificationTaskOfSecureTestStartFailure()431 private synchronized void cancelNotificationTaskOfSecureTestStartFailure() { 432 if (mNotificationTaskOfSecureTestStartFailure != null) { 433 mHandler.removeCallbacks(mNotificationTaskOfSecureTestStartFailure); 434 mNotificationTaskOfSecureTestStartFailure = null; 435 } 436 } 437 438 private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() { 439 @Override 440 public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { 441 if (DEBUG) { 442 Log.d(TAG, "onConnectionStateChange: newState=" + newState); 443 } 444 445 if (status == BluetoothGatt.GATT_SUCCESS) { 446 if (newState == BluetoothProfile.STATE_CONNECTED) { 447 mDevice = device; 448 boolean bonded = false; 449 Set<BluetoothDevice> pairedDevices = 450 mBluetoothManager.getAdapter().getBondedDevices(); 451 if (pairedDevices.size() > 0) { 452 for (BluetoothDevice target : pairedDevices) { 453 if (target.getAddress().equals(device.getAddress())) { 454 bonded = true; 455 break; 456 } 457 } 458 } 459 460 if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE) || 461 !bonded)) { 462 // not pairing and execute Secure Test 463 Log.e(TAG, "BluetoothGattServerCallback.onConnectionStateChange: " 464 + "Not paired but execute secure test"); 465 cancelNotificationTaskOfSecureTestStartFailure(); 466 } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE) 467 || bonded)) { 468 // already pairing and execute Insecure Test 469 Log.e(TAG, "BluetoothGattServerCallback.onConnectionStateChange: " 470 + "Paired but execute insecure test"); 471 } else { 472 cancelNotificationTaskOfSecureTestStartFailure(); 473 } 474 notifyConnected(); 475 } else if (status == BluetoothProfile.STATE_DISCONNECTED) { 476 notifyDisconnected(); 477 mDevice = null; 478 } 479 } 480 } 481 482 @Override 483 public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, 484 BluetoothGattCharacteristic characteristic) { 485 if (mGattServer == null) { 486 if (DEBUG) { 487 Log.d(TAG, "GattServer is null, return"); 488 } 489 return; 490 } 491 if (DEBUG) { 492 Log.d(TAG, "onCharacteristicReadRequest()"); 493 } 494 495 boolean finished = false; 496 byte[] value = null; 497 if (mMtuSize > 0) { 498 byte[] buf = characteristic.getValue(); 499 if (buf != null) { 500 int len = Math.min((buf.length - offset), mMtuSize); 501 if (len > 0) { 502 value = Arrays.copyOfRange(buf, offset, (offset + len)); 503 } 504 finished = ((offset + len) >= buf.length); 505 if (finished) { 506 Log.d(TAG, "sent whole data: " + (new String(characteristic.getValue()))); 507 } 508 } 509 } else { 510 value = characteristic.getValue(); 511 finished = true; 512 } 513 514 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); 515 516 UUID uid = characteristic.getUuid(); 517 if (uid.equals(BleCocClientService.LE_PSM_CHARACTERISTIC_UUID)) { 518 Log.d(TAG, "onCharacteristicReadRequest: reading PSM"); 519 } 520 } 521 522 }; 523 leCheckConnectionType()524 private void leCheckConnectionType() { 525 if (mChatService == null) { 526 Log.e(TAG, "leCheckConnectionType: no LE Coc connection"); 527 return; 528 } 529 int type = mChatService.getSocketConnectionType(); 530 if (type != BluetoothSocket.TYPE_L2CAP) { 531 Log.e(TAG, "leCheckConnectionType: invalid connection type=" + type); 532 return; 533 } 534 showMessage("LE CoC Connection Type Checked"); 535 Intent intent = new Intent(BLE_CONNECTION_TYPE_CHECKED); 536 sendBroadcast(intent); 537 } 538 readData8bytes()539 private void readData8bytes() { 540 mNextReadExpectedLen = 8; 541 mTotalReadLen = 0; 542 mNextReadCompletionIntent = BLE_DATA_8BYTES_READ; 543 mNextReadByte = 1; 544 } 545 readDataLargeBuf()546 private void readDataLargeBuf() { 547 mNextReadExpectedLen = BleCocServerService.TEST_DATA_EXCHANGE_BUFSIZE; 548 mTotalReadLen = 0; 549 mNextReadCompletionIntent = BLE_DATA_LARGEBUF_READ; 550 mNextReadByte = 1; 551 } 552 processChatStateChange(int newState)553 private void processChatStateChange(int newState) { 554 Intent intent; 555 if (DEBUG) { 556 Log.d(TAG, "processChatStateChange: newState=" + newState); 557 } 558 switch (newState) { 559 case BluetoothChatService.STATE_LISTEN: 560 intent = new Intent(BLE_COC_LISTENER_CREATED); 561 sendBroadcast(intent); 562 break; 563 case BluetoothChatService.STATE_CONNECTED: 564 intent = new Intent(BLE_COC_CONNECTED); 565 sendBroadcast(intent); 566 567 // Check the connection type 568 leCheckConnectionType(); 569 570 // Prepare the next data read 571 readData8bytes(); 572 break; 573 } 574 } 575 checkReadBufContent(byte[] buf, int len)576 private boolean checkReadBufContent(byte[] buf, int len) { 577 // Check that the content is correct 578 for (int i = 0; i < len; i++) { 579 if (buf[i] != mNextReadByte) { 580 Log.e(TAG, "handleMessageRead: Error: wrong byte content. buf[" 581 + i + "]=" + buf[i] + " not equal to " + mNextReadByte); 582 return false; 583 } 584 mNextReadByte++; 585 } 586 return true; 587 } 588 handleMessageRead(Message msg)589 private void handleMessageRead(Message msg) { 590 byte[] buf = (byte[])msg.obj; 591 int len = msg.arg1; 592 if (len <= 0) { 593 return; 594 } 595 mTotalReadLen += len; 596 if (DEBUG) { 597 Log.d(TAG, "handleMessageRead: receive buffer of length=" + len + ", mTotalReadLen=" 598 + mTotalReadLen + ", mNextReadExpectedLen=" + mNextReadExpectedLen); 599 } 600 601 if (mNextReadExpectedLen == mTotalReadLen) { 602 if (!checkReadBufContent(buf, len)) { 603 mNextReadExpectedLen = -1; 604 return; 605 } 606 showMessage("Read " + len + " bytes"); 607 if (DEBUG) { 608 Log.d(TAG, "handleMessageRead: broadcast intent " + mNextReadCompletionIntent); 609 } 610 Intent intent = new Intent(mNextReadCompletionIntent); 611 sendBroadcast(intent); 612 mTotalReadLen = 0; 613 if (mNextReadCompletionIntent.equals(BLE_DATA_8BYTES_READ)) { 614 // Keeps the logic same as in the client code, to make sure that the expectation is 615 // set before we receive the next bunch of data. 616 readDataLargeBuf(); 617 } else { 618 mNextReadExpectedLen = -1; 619 mNextReadCompletionIntent = null; 620 } 621 } else if (mNextReadExpectedLen > mTotalReadLen) { 622 if (!checkReadBufContent(buf, len)) { 623 mNextReadExpectedLen = -1; 624 return; 625 } 626 } else if (mNextReadExpectedLen < mTotalReadLen) { 627 Log.e(TAG, "handleMessageRead: Unexpected receive buffer of length=" + len 628 + ", expected len=" + mNextReadExpectedLen); 629 } 630 } 631 handleMessageWrite(Message msg)632 private void handleMessageWrite(Message msg) { 633 byte[] buffer = (byte[]) msg.obj; 634 int len = buffer.length; 635 showMessage("LE CoC Server wrote " + len + " bytes" + ", mNextWriteExpectedLen=" 636 + mNextWriteExpectedLen); 637 if (len == mNextWriteExpectedLen) { 638 if (mNextWriteCompletionIntent != null) { 639 Intent intent = new Intent(mNextWriteCompletionIntent); 640 sendBroadcast(intent); 641 } 642 } else { 643 Log.d(TAG, "handleMessageWrite: unrecognized length=" + len); 644 } 645 mNextWriteCompletionIntent = null; 646 mNextWriteExpectedLen = -1; 647 } 648 649 private class ChatHandler extends Handler { 650 @Override handleMessage(Message msg)651 public void handleMessage(Message msg) { 652 super.handleMessage(msg); 653 if (DEBUG) { 654 Log.d(TAG, "ChatHandler.handleMessage: msg=" + msg); 655 } 656 switch (msg.what) { 657 case BluetoothChatService.MESSAGE_STATE_CHANGE: 658 processChatStateChange(msg.arg1); 659 break; 660 case BluetoothChatService.MESSAGE_READ: 661 handleMessageRead(msg); 662 break; 663 case BluetoothChatService.MESSAGE_WRITE: 664 handleMessageWrite(msg); 665 break; 666 } 667 } 668 } 669 670 /* Start the Chat Service to create the Bluetooth Server Socket for LE CoC */ createChatService()671 private void createChatService() { 672 673 mChatService = new BluetoothChatService(this, new ChatHandler(), true); 674 mChatService.start(mSecure); 675 mPsm = mChatService.getPsm(mSecure); 676 if (DEBUG) { 677 Log.d(TAG, "createChatService: assigned PSM=" + mPsm); 678 } 679 if (mPsm > 0x00ff) { 680 Log.e(TAG, "createChatService: Invalid PSM=" + mPsm); 681 } 682 // Notify that the PSM is read 683 Intent intent = new Intent(BLE_PSM_READ); 684 sendBroadcast(intent); 685 686 // Set the PSM value in the PSM characteristics in the GATT Server. 687 mLePsmCharacteristic.setValue(mPsm, BluetoothGattCharacteristic.FORMAT_UINT8, 0); 688 } 689 startAdvertise()690 private void startAdvertise() { 691 if (DEBUG) { 692 Log.d(TAG, "startAdvertise"); 693 } 694 AdvertiseData data = new AdvertiseData.Builder() 695 .addServiceData(new ParcelUuid(ADV_COC_SERVICE_UUID), new byte[]{1,2,3}) 696 .addServiceUuid(new ParcelUuid(ADV_COC_SERVICE_UUID)) 697 .build(); 698 AdvertiseSettings setting = new AdvertiseSettings.Builder() 699 .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) 700 .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) 701 .setConnectable(true) 702 .build(); 703 mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback); 704 } 705 stopAdvertise()706 private void stopAdvertise() { 707 if (DEBUG) { 708 Log.d(TAG, "stopAdvertise"); 709 } 710 if (mAdvertiser != null) { 711 mAdvertiser.stopAdvertising(mAdvertiseCallback); 712 } 713 } 714 715 private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){ 716 @Override 717 public void onStartFailure(int errorCode) { 718 // Implementation for API Test. 719 super.onStartFailure(errorCode); 720 if (DEBUG) { 721 Log.d(TAG, "onStartFailure"); 722 } 723 724 if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) { 725 notifyAdvertiseUnsupported(); 726 } else { 727 notifyOpenFail(); 728 } 729 } 730 731 @Override 732 public void onStartSuccess(AdvertiseSettings settingsInEffect) { 733 // Implementation for API Test. 734 super.onStartSuccess(settingsInEffect); 735 if (DEBUG) { 736 Log.d(TAG, "onStartSuccess"); 737 } 738 } 739 }; 740 dumpService(BluetoothGattService service, int level)741 /*protected*/ static void dumpService(BluetoothGattService service, int level) { 742 String indent = ""; 743 for (int i = 0; i < level; ++i) { 744 indent += " "; 745 } 746 747 Log.d(TAG, indent + "[service]"); 748 Log.d(TAG, indent + "UUID: " + service.getUuid()); 749 Log.d(TAG, indent + " [characteristics]"); 750 for (BluetoothGattCharacteristic ch : service.getCharacteristics()) { 751 Log.d(TAG, indent + " UUID: " + ch.getUuid()); 752 Log.d(TAG, indent + " properties: " 753 + String.format("0x%02X", ch.getProperties())); 754 Log.d(TAG, indent + " permissions: " 755 + String.format("0x%02X", ch.getPermissions())); 756 Log.d(TAG, indent + " [descriptors]"); 757 for (BluetoothGattDescriptor d : ch.getDescriptors()) { 758 Log.d(TAG, indent + " UUID: " + d.getUuid()); 759 Log.d(TAG, indent + " permissions: " 760 + String.format("0x%02X", d.getPermissions())); 761 } 762 } 763 764 if (service.getIncludedServices() != null) { 765 Log.d(TAG, indent + " [included services]"); 766 for (BluetoothGattService s : service.getIncludedServices()) { 767 dumpService(s, level + 1); 768 } 769 } 770 } 771 } 772 773