1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.bluetooth;
17
18import android.os.Parcel;
19import android.os.Parcelable;
20import android.os.ParcelUuid;
21import java.util.ArrayList;
22import java.util.List;
23import 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 */
32public 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     */
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     */
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     */
252    public BluetoothGattCharacteristic(UUID uuid, int instanceId,
253                                       int properties, int permissions) {
254        initCharacteristic(null, uuid, instanceId, properties, permissions);
255    }
256
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     */
278    public int describeContents() {
279        return 0;
280    }
281
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
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     */
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     */
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     */
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     */
362    public BluetoothGattService getService() {
363        return mService;
364    }
365
366    /**
367     * Sets the service associated with this device.
368     * @hide
369     */
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     */
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     */
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     */
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     */
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     */
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     */
438    public void setWriteType(int writeType) {
439        mWriteType = writeType;
440    }
441
442    /**
443     * Set the desired key size.
444     * @hide
445     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
689    private int getTypeLen(int formatType) {
690        return formatType & 0xF;
691    }
692
693    /**
694     * Convert a signed byte to an unsigned int.
695     */
696    private int unsignedByteToInt(byte b) {
697        return b & 0xFF;
698    }
699
700    /**
701     * Convert signed bytes to a 16-bit unsigned int.
702     */
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     */
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     */
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     */
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     */
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     */
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