2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package android.bluetooth;
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;
26 * Represents a Bluetooth GATT Characteristic
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}.
32 public class BluetoothGattCharacteristic implements Parcelable {
35 * Characteristic proprty: Characteristic is broadcastable.
37 public static final int PROPERTY_BROADCAST = 0x01;
40 * Characteristic property: Characteristic is readable.
42 public static final int PROPERTY_READ = 0x02;
45 * Characteristic property: Characteristic can be written without response.
47 public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04;
50 * Characteristic property: Characteristic can be written.
52 public static final int PROPERTY_WRITE = 0x08;
55 * Characteristic property: Characteristic supports notification
57 public static final int PROPERTY_NOTIFY = 0x10;
60 * Characteristic property: Characteristic supports indication
62 public static final int PROPERTY_INDICATE = 0x20;
65 * Characteristic property: Characteristic supports write with signature
67 public static final int PROPERTY_SIGNED_WRITE = 0x40;
70 * Characteristic property: Characteristic has extended properties
72 public static final int PROPERTY_EXTENDED_PROPS = 0x80;
75 * Characteristic read permission
77 public static final int PERMISSION_READ = 0x01;
80 * Characteristic permission: Allow encrypted read operations
82 public static final int PERMISSION_READ_ENCRYPTED = 0x02;
85 * Characteristic permission: Allow reading with man-in-the-middle protection
87 public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04;
90 * Characteristic write permission
92 public static final int PERMISSION_WRITE = 0x10;
95 * Characteristic permission: Allow encrypted writes
97 public static final int PERMISSION_WRITE_ENCRYPTED = 0x20;
100 * Characteristic permission: Allow encrypted writes with man-in-the-middle
103 public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40;
106 * Characteristic permission: Allow signed write operations
108 public static final int PERMISSION_WRITE_SIGNED = 0x80;
111 * Characteristic permission: Allow signed write operations with
112 * man-in-the-middle protection
114 public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100;
117 * Write characteristic, requesting acknoledgement by the remote device
119 public static final int WRITE_TYPE_DEFAULT = 0x02;
122 * Wrtite characteristic without requiring a response by the remote device
124 public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
127 * Write characteristic including authentication signature
129 public static final int WRITE_TYPE_SIGNED = 0x04;
132 * Characteristic value format type uint8
134 public static final int FORMAT_UINT8 = 0x11;
137 * Characteristic value format type uint16
139 public static final int FORMAT_UINT16 = 0x12;
142 * Characteristic value format type uint32
144 public static final int FORMAT_UINT32 = 0x14;
147 * Characteristic value format type sint8
149 public static final int FORMAT_SINT8 = 0x21;
152 * Characteristic value format type sint16
154 public static final int FORMAT_SINT16 = 0x22;
157 * Characteristic value format type sint32
159 public static final int FORMAT_SINT32 = 0x24;
162 * Characteristic value format type sfloat (16-bit float)
164 public static final int FORMAT_SFLOAT = 0x32;
167 * Characteristic value format type float (32-bit float)
169 public static final int FORMAT_FLOAT = 0x34;
173 * The UUID of this characteristic.
176 protected UUID mUuid;
179 * Instance ID for this characteristic.
182 protected int mInstance;
185 * Characteristic properties.
188 protected int mProperties;
191 * Characteristic permissions.
194 protected int mPermissions;
197 * Key size (default = 16).
200 protected int mKeySize = 16;
203 * Write type for this characteristic.
204 * See WRITE_TYPE_* constants.
207 protected int mWriteType;
210 * Back-reference to the service this characteristic belongs to.
213 protected BluetoothGattService mService;
216 * The cached value of this characteristic.
219 protected byte[] mValue;
222 * List of descriptors included in this characteristic.
224 protected List<BluetoothGattDescriptor> mDescriptors;
227 * Create a new BluetoothGattCharacteristic.
228 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
230 * @param uuid The UUID for this characteristic
231 * @param properties Properties of this characteristic
232 * @param permissions Permissions for this characteristic
234 public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
235 initCharacteristic(null, uuid, 0, properties, permissions);
239 * Create a new BluetoothGattCharacteristic
242 /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
243 UUID uuid, int instanceId,
244 int properties, int permissions) {
245 initCharacteristic(service, uuid, instanceId, properties, permissions);
249 * Create a new BluetoothGattCharacteristic
252 public BluetoothGattCharacteristic(UUID uuid, int instanceId,
253 int properties, int permissions) {
254 initCharacteristic(null, uuid, instanceId, properties, permissions);
257 private void initCharacteristic(BluetoothGattService service,
258 UUID uuid, int instanceId,
259 int properties, int permissions) {
261 mInstance = instanceId;
262 mProperties = properties;
263 mPermissions = permissions;
266 mDescriptors = new ArrayList<BluetoothGattDescriptor>();
268 if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) {
269 mWriteType = WRITE_TYPE_NO_RESPONSE;
271 mWriteType = WRITE_TYPE_DEFAULT;
278 public int describeContents() {
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);
292 public static final Parcelable.Creator<BluetoothGattCharacteristic> CREATOR
293 = new Parcelable.Creator<BluetoothGattCharacteristic>() {
294 public BluetoothGattCharacteristic createFromParcel(Parcel in) {
295 return new BluetoothGattCharacteristic(in);
298 public BluetoothGattCharacteristic[] newArray(int size) {
299 return new BluetoothGattCharacteristic[size];
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();
311 mDescriptors = new ArrayList<BluetoothGattDescriptor>();
313 ArrayList<BluetoothGattDescriptor> descs =
314 in.createTypedArrayList(BluetoothGattDescriptor.CREATOR);
316 for (BluetoothGattDescriptor desc: descs) {
317 desc.setCharacteristic(this);
318 mDescriptors.add(desc);
324 * Returns the desired key size.
327 public int getKeySize() {
332 * Adds a descriptor to this characteristic.
333 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
335 * @param descriptor Descriptor to be added to this characteristic.
336 * @return true, if the descriptor was added to the characteristic
338 public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
339 mDescriptors.add(descriptor);
340 descriptor.setCharacteristic(this);
345 * Get a descriptor by UUID and isntance id.
348 /*package*/ BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) {
349 for(BluetoothGattDescriptor descriptor : mDescriptors) {
350 if (descriptor.getUuid().equals(uuid)
351 && descriptor.getInstanceId() == instanceId) {
359 * Returns the service this characteristic belongs to.
360 * @return The asscociated service
362 public BluetoothGattService getService() {
367 * Sets the service associated with this device.
370 /*package*/ void setService(BluetoothGattService service) {
375 * Returns the UUID of this characteristic
377 * @return UUID of this characteristic
379 public UUID getUuid() {
384 * Returns the instance ID for this characteristic.
386 * <p>If a remote device offers multiple characteristics with the same UUID,
387 * the instance ID is used to distuinguish between characteristics.
389 * @return Instance ID of this characteristic
391 public int getInstanceId() {
396 * Force the instance ID.
399 public void setInstanceId(int instanceId) {
400 mInstance = instanceId;
404 * Returns the properties of this characteristic.
406 * <p>The properties contain a bit mask of property flags indicating
407 * the features of this characteristic.
409 * @return Properties of this characteristic
411 public int getProperties() {
416 * Returns the permissions for this characteristic.
418 * @return Permissions of this characteristic
420 public int getPermissions() {
425 * Gets the write type for this characteristic.
427 * @return Write type for this characteristic
429 public int getWriteType() {
434 * Set the write type for this characteristic
436 * <p>Setting the write type of a characteristic determines how the
437 * {@link BluetoothGatt#writeCharacteristic} function write this
440 * @param writeType The write type to for this characteristic. Can be one
442 * {@link #WRITE_TYPE_DEFAULT},
443 * {@link #WRITE_TYPE_NO_RESPONSE} or
444 * {@link #WRITE_TYPE_SIGNED}.
446 public void setWriteType(int writeType) {
447 mWriteType = writeType;
451 * Set the desired key size.
454 public void setKeySize(int keySize) {
459 * Returns a list of descriptors for this characteristic.
461 * @return Descriptors for this characteristic
463 public List<BluetoothGattDescriptor> getDescriptors() {
468 * Returns a descriptor with a given UUID out of the list of
469 * descriptors for this characteristic.
471 * @return GATT descriptor object or null if no descriptor with the
472 * given UUID was found.
474 public BluetoothGattDescriptor getDescriptor(UUID uuid) {
475 for(BluetoothGattDescriptor descriptor : mDescriptors) {
476 if (descriptor.getUuid().equals(uuid)) {
484 * Get the stored value for this characteristic.
486 * <p>This function returns the stored value for this characteristic as
487 * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
488 * value of the characteristic is updated as a result of a read characteristic
489 * operation or if a characteristic update notification has been received.
491 * @return Cached value of the characteristic
493 public byte[] getValue() {
498 * Return the stored value of this characteristic.
500 * <p>The formatType parameter determines how the characteristic value
501 * is to be interpreted. For example, settting formatType to
502 * {@link #FORMAT_UINT16} specifies that the first two bytes of the
503 * characteristic value at the given offset are interpreted to generate the
506 * @param formatType The format type used to interpret the characteristic
508 * @param offset Offset at which the integer value can be found.
509 * @return Cached value of the characteristic or null of offset exceeds
512 public Integer getIntValue(int formatType, int offset) {
513 if ((offset + getTypeLen(formatType)) > mValue.length) return null;
515 switch (formatType) {
517 return unsignedByteToInt(mValue[offset]);
520 return unsignedBytesToInt(mValue[offset], mValue[offset+1]);
523 return unsignedBytesToInt(mValue[offset], mValue[offset+1],
524 mValue[offset+2], mValue[offset+3]);
526 return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8);
529 return unsignedToSigned(unsignedBytesToInt(mValue[offset],
530 mValue[offset+1]), 16);
533 return unsignedToSigned(unsignedBytesToInt(mValue[offset],
534 mValue[offset+1], mValue[offset+2], mValue[offset+3]), 32);
541 * Return the stored value of this characteristic.
542 * <p>See {@link #getValue} for details.
544 * @param formatType The format type used to interpret the characteristic
546 * @param offset Offset at which the float value can be found.
547 * @return Cached value of the characteristic at a given offset or null
548 * if the requested offset exceeds the value size.
550 public Float getFloatValue(int formatType, int offset) {
551 if ((offset + getTypeLen(formatType)) > mValue.length) return null;
553 switch (formatType) {
555 return bytesToFloat(mValue[offset], mValue[offset+1]);
558 return bytesToFloat(mValue[offset], mValue[offset+1],
559 mValue[offset+2], mValue[offset+3]);
566 * Return the stored value of this characteristic.
567 * <p>See {@link #getValue} for details.
569 * @param offset Offset at which the string value can be found.
570 * @return Cached value of the characteristic
572 public String getStringValue(int offset) {
573 if (mValue == null || offset > mValue.length) return null;
574 byte[] strBytes = new byte[mValue.length - offset];
575 for (int i=0; i != (mValue.length-offset); ++i) strBytes[i] = mValue[offset+i];
576 return new String(strBytes);
580 * Updates the locally stored value of this characteristic.
582 * <p>This function modifies the locally stored cached value of this
583 * characteristic. To send the value to the remote device, call
584 * {@link BluetoothGatt#writeCharacteristic} to send the value to the
587 * @param value New value for this characteristic
588 * @return true if the locally stored value has been set, false if the
589 * requested value could not be stored locally.
591 public boolean setValue(byte[] value) {
597 * Set the locally stored value of this characteristic.
598 * <p>See {@link #setValue(byte[])} for details.
600 * @param value New value for this characteristic
601 * @param formatType Integer format type used to transform the value parameter
602 * @param offset Offset at which the value should be placed
603 * @return true if the locally stored value has been set
605 public boolean setValue(int value, int formatType, int offset) {
606 int len = offset + getTypeLen(formatType);
607 if (mValue == null) mValue = new byte[len];
608 if (len > mValue.length) return false;
610 switch (formatType) {
612 value = intToSignedBits(value, 8);
613 // Fall-through intended
615 mValue[offset] = (byte)(value & 0xFF);
619 value = intToSignedBits(value, 16);
620 // Fall-through intended
622 mValue[offset++] = (byte)(value & 0xFF);
623 mValue[offset] = (byte)((value >> 8) & 0xFF);
627 value = intToSignedBits(value, 32);
628 // Fall-through intended
630 mValue[offset++] = (byte)(value & 0xFF);
631 mValue[offset++] = (byte)((value >> 8) & 0xFF);
632 mValue[offset++] = (byte)((value >> 16) & 0xFF);
633 mValue[offset] = (byte)((value >> 24) & 0xFF);
643 * Set the locally stored value of this characteristic.
644 * <p>See {@link #setValue(byte[])} for details.
646 * @param mantissa Mantissa for this characteristic
647 * @param exponent exponent value for this characteristic
648 * @param formatType Float format type used to transform the value parameter
649 * @param offset Offset at which the value should be placed
650 * @return true if the locally stored value has been set
652 public boolean setValue(int mantissa, int exponent, int formatType, int offset) {
653 int len = offset + getTypeLen(formatType);
654 if (mValue == null) mValue = new byte[len];
655 if (len > mValue.length) return false;
657 switch (formatType) {
659 mantissa = intToSignedBits(mantissa, 12);
660 exponent = intToSignedBits(exponent, 4);
661 mValue[offset++] = (byte)(mantissa & 0xFF);
662 mValue[offset] = (byte)((mantissa >> 8) & 0x0F);
663 mValue[offset] += (byte)((exponent & 0x0F) << 4);
667 mantissa = intToSignedBits(mantissa, 24);
668 exponent = intToSignedBits(exponent, 8);
669 mValue[offset++] = (byte)(mantissa & 0xFF);
670 mValue[offset++] = (byte)((mantissa >> 8) & 0xFF);
671 mValue[offset++] = (byte)((mantissa >> 16) & 0xFF);
672 mValue[offset] += (byte)(exponent & 0xFF);
683 * Set the locally stored value of this characteristic.
684 * <p>See {@link #setValue(byte[])} for details.
686 * @param value New value for this characteristic
687 * @return true if the locally stored value has been set
689 public boolean setValue(String value) {
690 mValue = value.getBytes();
695 * Returns the size of a give value type.
697 private int getTypeLen(int formatType) {
698 return formatType & 0xF;
702 * Convert a signed byte to an unsigned int.
704 private int unsignedByteToInt(byte b) {
709 * Convert signed bytes to a 16-bit unsigned int.
711 private int unsignedBytesToInt(byte b0, byte b1) {
712 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
716 * Convert signed bytes to a 32-bit unsigned int.
718 private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
719 return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
720 + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24);
724 * Convert signed bytes to a 16-bit short float value.
726 private float bytesToFloat(byte b0, byte b1) {
727 int mantissa = unsignedToSigned(unsignedByteToInt(b0)
728 + ((unsignedByteToInt(b1) & 0x0F) << 8), 12);
729 int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4);
730 return (float)(mantissa * Math.pow(10, exponent));
734 * Convert signed bytes to a 32-bit short float value.
736 private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
737 int mantissa = unsignedToSigned(unsignedByteToInt(b0)
738 + (unsignedByteToInt(b1) << 8)
739 + (unsignedByteToInt(b2) << 16), 24);
740 return (float)(mantissa * Math.pow(10, b3));
744 * Convert an unsigned integer value to a two's-complement encoded
747 private int unsignedToSigned(int unsigned, int size) {
748 if ((unsigned & (1 << size-1)) != 0) {
749 unsigned = -1 * ((1 << size-1) - (unsigned & ((1 << size-1) - 1)));
755 * Convert an integer into the signed bits of a given length.
757 private int intToSignedBits(int i, int size) {
759 i = (1 << size-1) + (i & ((1 << size-1) - 1));