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