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 package android.bluetooth; 17 18 import java.util.ArrayList; 19 import java.util.List; 20 import java.util.UUID; 21 22 /** 23 * Represents a Bluetooth GATT Characteristic 24 * 25 * <p>A GATT characteristic is a basic data element used to construct a GATT service, 26 * {@link BluetoothGattService}. The characteristic contains a value as well as 27 * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}. 28 */ 29 public class BluetoothGattCharacteristic { 30 31 /** 32 * Characteristic proprty: Characteristic is broadcastable. 33 */ 34 public static final int PROPERTY_BROADCAST = 0x01; 35 36 /** 37 * Characteristic property: Characteristic is readable. 38 */ 39 public static final int PROPERTY_READ = 0x02; 40 41 /** 42 * Characteristic property: Characteristic can be written without response. 43 */ 44 public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04; 45 46 /** 47 * Characteristic property: Characteristic can be written. 48 */ 49 public static final int PROPERTY_WRITE = 0x08; 50 51 /** 52 * Characteristic property: Characteristic supports notification 53 */ 54 public static final int PROPERTY_NOTIFY = 0x10; 55 56 /** 57 * Characteristic property: Characteristic supports indication 58 */ 59 public static final int PROPERTY_INDICATE = 0x20; 60 61 /** 62 * Characteristic property: Characteristic supports write with signature 63 */ 64 public static final int PROPERTY_SIGNED_WRITE = 0x40; 65 66 /** 67 * Characteristic property: Characteristic has extended properties 68 */ 69 public static final int PROPERTY_EXTENDED_PROPS = 0x80; 70 71 /** 72 * Characteristic read permission 73 */ 74 public static final int PERMISSION_READ = 0x01; 75 76 /** 77 * Characteristic permission: Allow encrypted read operations 78 */ 79 public static final int PERMISSION_READ_ENCRYPTED = 0x02; 80 81 /** 82 * Characteristic permission: Allow reading with man-in-the-middle protection 83 */ 84 public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04; 85 86 /** 87 * Characteristic write permission 88 */ 89 public static final int PERMISSION_WRITE = 0x10; 90 91 /** 92 * Characteristic permission: Allow encrypted writes 93 */ 94 public static final int PERMISSION_WRITE_ENCRYPTED = 0x20; 95 96 /** 97 * Characteristic permission: Allow encrypted writes with man-in-the-middle 98 * protection 99 */ 100 public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40; 101 102 /** 103 * Characteristic permission: Allow signed write operations 104 */ 105 public static final int PERMISSION_WRITE_SIGNED = 0x80; 106 107 /** 108 * Characteristic permission: Allow signed write operations with 109 * man-in-the-middle protection 110 */ 111 public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100; 112 113 /** 114 * Write characteristic, requesting acknoledgement by the remote device 115 */ 116 public static final int WRITE_TYPE_DEFAULT = 0x02; 117 118 /** 119 * Wrtite characteristic without requiring a response by the remote device 120 */ 121 public static final int WRITE_TYPE_NO_RESPONSE = 0x01; 122 123 /** 124 * Write characteristic including authentication signature 125 */ 126 public static final int WRITE_TYPE_SIGNED = 0x04; 127 128 /** 129 * Characteristic value format type uint8 130 */ 131 public static final int FORMAT_UINT8 = 0x11; 132 133 /** 134 * Characteristic value format type uint16 135 */ 136 public static final int FORMAT_UINT16 = 0x12; 137 138 /** 139 * Characteristic value format type uint32 140 */ 141 public static final int FORMAT_UINT32 = 0x14; 142 143 /** 144 * Characteristic value format type sint8 145 */ 146 public static final int FORMAT_SINT8 = 0x21; 147 148 /** 149 * Characteristic value format type sint16 150 */ 151 public static final int FORMAT_SINT16 = 0x22; 152 153 /** 154 * Characteristic value format type sint32 155 */ 156 public static final int FORMAT_SINT32 = 0x24; 157 158 /** 159 * Characteristic value format type sfloat (16-bit float) 160 */ 161 public static final int FORMAT_SFLOAT = 0x32; 162 163 /** 164 * Characteristic value format type float (32-bit float) 165 */ 166 public static final int FORMAT_FLOAT = 0x34; 167 168 169 /** 170 * The UUID of this characteristic. 171 * @hide 172 */ 173 protected UUID mUuid; 174 175 /** 176 * Instance ID for this characteristic. 177 * @hide 178 */ 179 protected int mInstance; 180 181 /** 182 * Characteristic properties. 183 * @hide 184 */ 185 protected int mProperties; 186 187 /** 188 * Characteristic permissions. 189 * @hide 190 */ 191 protected int mPermissions; 192 193 /** 194 * Key size (default = 16). 195 * @hide 196 */ 197 protected int mKeySize = 16; 198 199 /** 200 * Write type for this characteristic. 201 * See WRITE_TYPE_* constants. 202 * @hide 203 */ 204 protected int mWriteType; 205 206 /** 207 * Back-reference to the service this characteristic belongs to. 208 * @hide 209 */ 210 protected BluetoothGattService mService; 211 212 /** 213 * The cached value of this characteristic. 214 * @hide 215 */ 216 protected byte[] mValue; 217 218 /** 219 * List of descriptors included in this characteristic. 220 */ 221 protected List<BluetoothGattDescriptor> mDescriptors; 222 223 /** 224 * Create a new BluetoothGattCharacteristic. 225 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 226 * 227 * @param uuid The UUID for this characteristic 228 * @param properties Properties of this characteristic 229 * @param permissions Permissions for this characteristic 230 */ BluetoothGattCharacteristic(UUID uuid, int properties, int permissions)231 public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) { 232 initCharacteristic(null, uuid, 0, properties, permissions); 233 } 234 235 /** 236 * Create a new BluetoothGattCharacteristic 237 * @hide 238 */ BluetoothGattCharacteristic(BluetoothGattService service, UUID uuid, int instanceId, int properties, int permissions)239 /*package*/ BluetoothGattCharacteristic(BluetoothGattService service, 240 UUID uuid, int instanceId, 241 int properties, int permissions) { 242 initCharacteristic(service, uuid, instanceId, properties, permissions); 243 } 244 initCharacteristic(BluetoothGattService service, UUID uuid, int instanceId, int properties, int permissions)245 private void initCharacteristic(BluetoothGattService service, 246 UUID uuid, int instanceId, 247 int properties, int permissions) { 248 mUuid = uuid; 249 mInstance = instanceId; 250 mProperties = properties; 251 mPermissions = permissions; 252 mService = service; 253 mValue = null; 254 mDescriptors = new ArrayList<BluetoothGattDescriptor>(); 255 256 if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) { 257 mWriteType = WRITE_TYPE_NO_RESPONSE; 258 } else { 259 mWriteType = WRITE_TYPE_DEFAULT; 260 } 261 } 262 263 /** 264 * Returns the deisred key size. 265 * @hide 266 */ getKeySize()267 /*package*/ int getKeySize() { 268 return mKeySize; 269 } 270 271 /** 272 * Adds a descriptor to this characteristic. 273 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 274 * 275 * @param descriptor Descriptor to be added to this characteristic. 276 * @return true, if the descriptor was added to the characteristic 277 */ addDescriptor(BluetoothGattDescriptor descriptor)278 public boolean addDescriptor(BluetoothGattDescriptor descriptor) { 279 mDescriptors.add(descriptor); 280 descriptor.setCharacteristic(this); 281 return true; 282 } 283 284 /** 285 * Get a descriptor by UUID and isntance id. 286 * @hide 287 */ getDescriptor(UUID uuid, int instanceId)288 /*package*/ BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) { 289 for(BluetoothGattDescriptor descriptor : mDescriptors) { 290 if (descriptor.getUuid().equals(uuid) 291 && descriptor.getInstanceId() == instanceId) { 292 return descriptor; 293 } 294 } 295 return null; 296 } 297 298 /** 299 * Returns the service this characteristic belongs to. 300 * @return The asscociated service 301 */ getService()302 public BluetoothGattService getService() { 303 return mService; 304 } 305 306 /** 307 * Sets the service associated with this device. 308 * @hide 309 */ setService(BluetoothGattService service)310 /*package*/ void setService(BluetoothGattService service) { 311 mService = service; 312 } 313 314 /** 315 * Returns the UUID of this characteristic 316 * 317 * @return UUID of this characteristic 318 */ getUuid()319 public UUID getUuid() { 320 return mUuid; 321 } 322 323 /** 324 * Returns the instance ID for this characteristic. 325 * 326 * <p>If a remote device offers multiple characteristics with the same UUID, 327 * the instance ID is used to distuinguish between characteristics. 328 * 329 * @return Instance ID of this characteristic 330 */ getInstanceId()331 public int getInstanceId() { 332 return mInstance; 333 } 334 335 /** 336 * Returns the properties of this characteristic. 337 * 338 * <p>The properties contain a bit mask of property flags indicating 339 * the features of this characteristic. 340 * 341 * @return Properties of this characteristic 342 */ getProperties()343 public int getProperties() { 344 return mProperties; 345 } 346 347 /** 348 * Returns the permissions for this characteristic. 349 * 350 * @return Permissions of this characteristic 351 */ getPermissions()352 public int getPermissions() { 353 return mPermissions; 354 } 355 356 /** 357 * Gets the write type for this characteristic. 358 * 359 * @return Write type for this characteristic 360 */ getWriteType()361 public int getWriteType() { 362 return mWriteType; 363 } 364 365 /** 366 * Set the write type for this characteristic 367 * 368 * <p>Setting the write type of a characteristic determines how the 369 * {@link BluetoothGatt#writeCharacteristic} function write this 370 * characteristic. 371 * 372 * @param writeType The write type to for this characteristic. Can be one 373 * of: 374 * {@link #WRITE_TYPE_DEFAULT}, 375 * {@link #WRITE_TYPE_NO_RESPONSE} or 376 * {@link #WRITE_TYPE_SIGNED}. 377 */ setWriteType(int writeType)378 public void setWriteType(int writeType) { 379 mWriteType = writeType; 380 } 381 382 /** 383 * Set the desired key size. 384 * @hide 385 */ setKeySize(int keySize)386 public void setKeySize(int keySize) { 387 mKeySize = keySize; 388 } 389 390 /** 391 * Returns a list of descriptors for this characteristic. 392 * 393 * @return Descriptors for this characteristic 394 */ getDescriptors()395 public List<BluetoothGattDescriptor> getDescriptors() { 396 return mDescriptors; 397 } 398 399 /** 400 * Returns a descriptor with a given UUID out of the list of 401 * descriptors for this characteristic. 402 * 403 * @return GATT descriptor object or null if no descriptor with the 404 * given UUID was found. 405 */ getDescriptor(UUID uuid)406 public BluetoothGattDescriptor getDescriptor(UUID uuid) { 407 for(BluetoothGattDescriptor descriptor : mDescriptors) { 408 if (descriptor.getUuid().equals(uuid)) { 409 return descriptor; 410 } 411 } 412 return null; 413 } 414 415 /** 416 * Get the stored value for this characteristic. 417 * 418 * <p>This function returns the stored value for this characteristic as 419 * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached 420 * value of the characteristic is updated as a result of a read characteristic 421 * operation or if a characteristic update notification has been received. 422 * 423 * @return Cached value of the characteristic 424 */ getValue()425 public byte[] getValue() { 426 return mValue; 427 } 428 429 /** 430 * Return the stored value of this characteristic. 431 * 432 * <p>The formatType parameter determines how the characteristic value 433 * is to be interpreted. For example, settting formatType to 434 * {@link #FORMAT_UINT16} specifies that the first two bytes of the 435 * characteristic value at the given offset are interpreted to generate the 436 * return value. 437 * 438 * @param formatType The format type used to interpret the characteristic 439 * value. 440 * @param offset Offset at which the integer value can be found. 441 * @return Cached value of the characteristic or null of offset exceeds 442 * value size. 443 */ getIntValue(int formatType, int offset)444 public Integer getIntValue(int formatType, int offset) { 445 if ((offset + getTypeLen(formatType)) > mValue.length) return null; 446 447 switch (formatType) { 448 case FORMAT_UINT8: 449 return unsignedByteToInt(mValue[offset]); 450 451 case FORMAT_UINT16: 452 return unsignedBytesToInt(mValue[offset], mValue[offset+1]); 453 454 case FORMAT_UINT32: 455 return unsignedBytesToInt(mValue[offset], mValue[offset+1], 456 mValue[offset+2], mValue[offset+3]); 457 case FORMAT_SINT8: 458 return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8); 459 460 case FORMAT_SINT16: 461 return unsignedToSigned(unsignedBytesToInt(mValue[offset], 462 mValue[offset+1]), 16); 463 464 case FORMAT_SINT32: 465 return unsignedToSigned(unsignedBytesToInt(mValue[offset], 466 mValue[offset+1], mValue[offset+2], mValue[offset+3]), 32); 467 } 468 469 return null; 470 } 471 472 /** 473 * Return the stored value of this characteristic. 474 * <p>See {@link #getValue} for details. 475 * 476 * @param formatType The format type used to interpret the characteristic 477 * value. 478 * @param offset Offset at which the float value can be found. 479 * @return Cached value of the characteristic at a given offset or null 480 * if the requested offset exceeds the value size. 481 */ getFloatValue(int formatType, int offset)482 public Float getFloatValue(int formatType, int offset) { 483 if ((offset + getTypeLen(formatType)) > mValue.length) return null; 484 485 switch (formatType) { 486 case FORMAT_SFLOAT: 487 return bytesToFloat(mValue[offset], mValue[offset+1]); 488 489 case FORMAT_FLOAT: 490 return bytesToFloat(mValue[offset], mValue[offset+1], 491 mValue[offset+2], mValue[offset+3]); 492 } 493 494 return null; 495 } 496 497 /** 498 * Return the stored value of this characteristic. 499 * <p>See {@link #getValue} for details. 500 * 501 * @param offset Offset at which the string value can be found. 502 * @return Cached value of the characteristic 503 */ getStringValue(int offset)504 public String getStringValue(int offset) { 505 if (mValue == null || offset > mValue.length) return null; 506 byte[] strBytes = new byte[mValue.length - offset]; 507 for (int i=0; i != (mValue.length-offset); ++i) strBytes[i] = mValue[offset+i]; 508 return new String(strBytes); 509 } 510 511 /** 512 * Updates the locally stored value of this characteristic. 513 * 514 * <p>This function modifies the locally stored cached value of this 515 * characteristic. To send the value to the remote device, call 516 * {@link BluetoothGatt#writeCharacteristic} to send the value to the 517 * remote device. 518 * 519 * @param value New value for this characteristic 520 * @return true if the locally stored value has been set, false if the 521 * requested value could not be stored locally. 522 */ setValue(byte[] value)523 public boolean setValue(byte[] value) { 524 mValue = value; 525 return true; 526 } 527 528 /** 529 * Set the locally stored value of this characteristic. 530 * <p>See {@link #setValue(byte[])} for details. 531 * 532 * @param value New value for this characteristic 533 * @param formatType Integer format type used to transform the value parameter 534 * @param offset Offset at which the value should be placed 535 * @return true if the locally stored value has been set 536 */ setValue(int value, int formatType, int offset)537 public boolean setValue(int value, int formatType, int offset) { 538 int len = offset + getTypeLen(formatType); 539 if (mValue == null) mValue = new byte[len]; 540 if (len > mValue.length) return false; 541 542 switch (formatType) { 543 case FORMAT_SINT8: 544 value = intToSignedBits(value, 8); 545 // Fall-through intended 546 case FORMAT_UINT8: 547 mValue[offset] = (byte)(value & 0xFF); 548 break; 549 550 case FORMAT_SINT16: 551 value = intToSignedBits(value, 16); 552 // Fall-through intended 553 case FORMAT_UINT16: 554 mValue[offset++] = (byte)(value & 0xFF); 555 mValue[offset] = (byte)((value >> 8) & 0xFF); 556 break; 557 558 case FORMAT_SINT32: 559 value = intToSignedBits(value, 32); 560 // Fall-through intended 561 case FORMAT_UINT32: 562 mValue[offset++] = (byte)(value & 0xFF); 563 mValue[offset++] = (byte)((value >> 8) & 0xFF); 564 mValue[offset++] = (byte)((value >> 16) & 0xFF); 565 mValue[offset] = (byte)((value >> 24) & 0xFF); 566 break; 567 568 default: 569 return false; 570 } 571 return true; 572 } 573 574 /** 575 * Set the locally stored value of this characteristic. 576 * <p>See {@link #setValue(byte[])} for details. 577 * 578 * @param mantissa Mantissa for this characteristic 579 * @param exponent exponent value for this characteristic 580 * @param formatType Float format type used to transform the value parameter 581 * @param offset Offset at which the value should be placed 582 * @return true if the locally stored value has been set 583 */ setValue(int mantissa, int exponent, int formatType, int offset)584 public boolean setValue(int mantissa, int exponent, int formatType, int offset) { 585 int len = offset + getTypeLen(formatType); 586 if (mValue == null) mValue = new byte[len]; 587 if (len > mValue.length) return false; 588 589 switch (formatType) { 590 case FORMAT_SFLOAT: 591 mantissa = intToSignedBits(mantissa, 12); 592 exponent = intToSignedBits(exponent, 4); 593 mValue[offset++] = (byte)(mantissa & 0xFF); 594 mValue[offset] = (byte)((mantissa >> 8) & 0x0F); 595 mValue[offset] += (byte)((exponent & 0x0F) << 4); 596 break; 597 598 case FORMAT_FLOAT: 599 mantissa = intToSignedBits(mantissa, 24); 600 exponent = intToSignedBits(exponent, 8); 601 mValue[offset++] = (byte)(mantissa & 0xFF); 602 mValue[offset++] = (byte)((mantissa >> 8) & 0xFF); 603 mValue[offset++] = (byte)((mantissa >> 16) & 0xFF); 604 mValue[offset] += (byte)(exponent & 0xFF); 605 break; 606 607 default: 608 return false; 609 } 610 611 return true; 612 } 613 614 /** 615 * Set the locally stored value of this characteristic. 616 * <p>See {@link #setValue(byte[])} for details. 617 * 618 * @param value New value for this characteristic 619 * @return true if the locally stored value has been set 620 */ setValue(String value)621 public boolean setValue(String value) { 622 mValue = value.getBytes(); 623 return true; 624 } 625 626 /** 627 * Returns the size of a give value type. 628 */ getTypeLen(int formatType)629 private int getTypeLen(int formatType) { 630 return formatType & 0xF; 631 } 632 633 /** 634 * Convert a signed byte to an unsigned int. 635 */ unsignedByteToInt(byte b)636 private int unsignedByteToInt(byte b) { 637 return b & 0xFF; 638 } 639 640 /** 641 * Convert signed bytes to a 16-bit unsigned int. 642 */ unsignedBytesToInt(byte b0, byte b1)643 private int unsignedBytesToInt(byte b0, byte b1) { 644 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)); 645 } 646 647 /** 648 * Convert signed bytes to a 32-bit unsigned int. 649 */ unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3)650 private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) { 651 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)) 652 + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24); 653 } 654 655 /** 656 * Convert signed bytes to a 16-bit short float value. 657 */ bytesToFloat(byte b0, byte b1)658 private float bytesToFloat(byte b0, byte b1) { 659 int mantissa = unsignedToSigned(unsignedByteToInt(b0) 660 + ((unsignedByteToInt(b1) & 0x0F) << 8), 12); 661 int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4); 662 return (float)(mantissa * Math.pow(10, exponent)); 663 } 664 665 /** 666 * Convert signed bytes to a 32-bit short float value. 667 */ bytesToFloat(byte b0, byte b1, byte b2, byte b3)668 private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) { 669 int mantissa = unsignedToSigned(unsignedByteToInt(b0) 670 + (unsignedByteToInt(b1) << 8) 671 + (unsignedByteToInt(b2) << 16), 24); 672 return (float)(mantissa * Math.pow(10, b3)); 673 } 674 675 /** 676 * Convert an unsigned integer value to a two's-complement encoded 677 * signed value. 678 */ unsignedToSigned(int unsigned, int size)679 private int unsignedToSigned(int unsigned, int size) { 680 if ((unsigned & (1 << size-1)) != 0) { 681 unsigned = -1 * ((1 << size-1) - (unsigned & ((1 << size-1) - 1))); 682 } 683 return unsigned; 684 } 685 686 /** 687 * Convert an integer into the signed bits of a given length. 688 */ intToSignedBits(int i, int size)689 private int intToSignedBits(int i, int size) { 690 if (i < 0) { 691 i = (1 << size-1) + (i & ((1 << size-1) - 1)); 692 } 693 return i; 694 } 695 } 696