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