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