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