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