Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2017 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 
     17 package com.googlecode.android_scripting.facade.bluetooth;
     18 
     19 import android.app.Service;
     20 import android.bluetooth.BluetoothAdapter;
     21 import android.bluetooth.BluetoothDevice;
     22 import android.bluetooth.BluetoothGatt;
     23 import android.bluetooth.BluetoothGattCallback;
     24 import android.bluetooth.BluetoothGattCharacteristic;
     25 import android.bluetooth.BluetoothGattDescriptor;
     26 import android.bluetooth.BluetoothGattService;
     27 import android.bluetooth.BluetoothManager;
     28 import android.bluetooth.BluetoothProfile;
     29 import android.content.Context;
     30 import android.os.Bundle;
     31 
     32 import com.googlecode.android_scripting.Log;
     33 import com.googlecode.android_scripting.MainThread;
     34 import com.googlecode.android_scripting.facade.EventFacade;
     35 import com.googlecode.android_scripting.facade.FacadeManager;
     36 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
     37 import com.googlecode.android_scripting.rpc.Rpc;
     38 import com.googlecode.android_scripting.rpc.RpcParameter;
     39 import com.googlecode.android_scripting.rpc.RpcStopEvent;
     40 
     41 import java.util.ArrayList;
     42 import java.util.HashMap;
     43 import java.util.List;
     44 import java.util.UUID;
     45 import java.util.concurrent.Callable;
     46 
     47 public class GattClientFacade extends RpcReceiver {
     48     private final EventFacade mEventFacade;
     49     private BluetoothAdapter mBluetoothAdapter;
     50     private BluetoothManager mBluetoothManager;
     51     private final Service mService;
     52     private final Context mContext;
     53     private final HashMap<Integer, myBluetoothGattCallback> mGattCallbackList;
     54     private final HashMap<Integer, BluetoothGatt> mBluetoothGattList;
     55     private final HashMap<Integer, BluetoothGattCharacteristic> mCharacteristicList;
     56     private final HashMap<Integer, BluetoothGattDescriptor> mDescriptorList;
     57     private final HashMap<Integer, BluetoothGattService> mGattServiceList;
     58     private final HashMap<Integer, List<BluetoothGattService>> mBluetoothGattDiscoveredServicesList;
     59     private final HashMap<Integer, List<BluetoothDevice>> mGattServerDiscoveredDevicesList;
     60     private static int GattCallbackCount;
     61     private static int BluetoothGattDiscoveredServicesCount;
     62     private static int BluetoothGattCount;
     63     private static int CharacteristicCount;
     64     private static int DescriptorCount;
     65     private static int GattServerCallbackCount;
     66     private static int GattServerCount;
     67     private static int GattServiceCount;
     68 
     69     public GattClientFacade(FacadeManager manager) {
     70         super(manager);
     71         mService = manager.getService();
     72         mContext = mService.getApplicationContext();
     73         mBluetoothAdapter =
     74                 MainThread.run(
     75                         mService,
     76                         new Callable<BluetoothAdapter>() {
     77                             @Override
     78                             public BluetoothAdapter call() throws Exception {
     79                                 return BluetoothAdapter.getDefaultAdapter();
     80                             }
     81                         });
     82         mBluetoothManager = (BluetoothManager) mContext.getSystemService(Service.BLUETOOTH_SERVICE);
     83         mEventFacade = manager.getReceiver(EventFacade.class);
     84         mGattCallbackList = new HashMap<Integer, myBluetoothGattCallback>();
     85         mCharacteristicList = new HashMap<Integer, BluetoothGattCharacteristic>();
     86         mBluetoothGattList = new HashMap<Integer, BluetoothGatt>();
     87         mDescriptorList = new HashMap<Integer, BluetoothGattDescriptor>();
     88         mGattServiceList = new HashMap<Integer, BluetoothGattService>();
     89         mBluetoothGattDiscoveredServicesList = new HashMap<Integer, List<BluetoothGattService>>();
     90         mGattServerDiscoveredDevicesList = new HashMap<Integer, List<BluetoothDevice>>();
     91     }
     92 
     93     /**
     94      * Create a BluetoothGatt connection
     95      *
     96      * @param index of the callback to start a connection on
     97      * @param macAddress the mac address of the ble device
     98      * @param autoConnect Whether to directly connect to the remote device (false) or to
     99      *       automatically connect as soon as the remote device becomes available (true)
    100      * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
    101      *                      does not hold a GATT connection. It automatically disconnects when no
    102      *                      other GATT connections are active for the remote device.
    103      * @param transport preferred transport for GATT connections to remote dual-mode devices
    104      *       TRANSPORT_AUTO or TRANSPORT_BREDR or TRANSPORT_LE
    105      * @return the index of the BluetoothGatt object
    106      * @throws Exception
    107      */
    108     @Rpc(description = "Create a gatt connection")
    109     public int gattClientConnectGatt(
    110             @RpcParameter(name = "index") Integer index,
    111             @RpcParameter(name = "macAddress") String macAddress,
    112             @RpcParameter(name = "autoConnect") Boolean autoConnect,
    113             @RpcParameter(name = "transport") Integer transport,
    114             @RpcParameter(name = "opportunistic") Boolean opportunistic,
    115             @RpcParameter(name = "phy") Integer phy)
    116             throws Exception {
    117         if (mGattCallbackList.get(index) != null) {
    118             BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(macAddress);
    119             if (phy == null) phy = BluetoothDevice.PHY_LE_1M;
    120 
    121             BluetoothGatt mBluetoothGatt = device.connectGatt(mService.getApplicationContext(),
    122                     autoConnect, mGattCallbackList.get(index), transport, opportunistic, phy, null);
    123             BluetoothGattCount += 1;
    124             mBluetoothGattList.put(BluetoothGattCount, mBluetoothGatt);
    125             return BluetoothGattCount;
    126         } else {
    127             throw new Exception("Invalid index input:" + Integer.toString(index));
    128         }
    129     }
    130 
    131     /**
    132      * Trigger discovering of services on the BluetoothGatt object
    133      *
    134      * @param index The BluetoothGatt object index
    135      * @return true, if the remote service discovery has been started
    136      * @throws Exception
    137      */
    138     @Rpc(description = "Trigger discovering of services on the BluetoothGatt object")
    139     public boolean gattClientDiscoverServices(@RpcParameter(name = "index") Integer index)
    140             throws Exception {
    141         if (mBluetoothGattList.get(index) != null) {
    142             return mBluetoothGattList.get(index).discoverServices();
    143         } else {
    144             throw new Exception("Invalid index input:" + Integer.toString(index));
    145         }
    146     }
    147 
    148     /**
    149      * Trigger discovering of services by UUID on the BluetoothGatt object
    150      *
    151      * @param index The BluetoothGatt object index
    152      * @param uuid service UUID
    153      * @return true, if the remote service discovery has been started
    154      * @throws Exception
    155      */
    156     @Rpc(description = "Trigger discovering of services on the BluetoothGatt object")
    157     public boolean gattClientDiscoverServiceByUuid(@RpcParameter(name = "index") Integer index,
    158             @RpcParameter(name = "uuid") String uuid) throws Exception {
    159         BluetoothGatt gatt = mBluetoothGattList.get(index);
    160         if (gatt != null) {
    161             Object ret = gatt.getClass().getMethod("discoverServiceByUuid", UUID.class)
    162                             .invoke(gatt, UUID.fromString(uuid));
    163             return (Boolean) ret;
    164         } else {
    165             throw new Exception("Invalid index input:" + Integer.toString(index));
    166         }
    167     }
    168 
    169 
    170     /**
    171      * Get the services from the BluetoothGatt object
    172      *
    173      * @param index The BluetoothGatt object index
    174      * @return a list of BluetoothGattServices
    175      * @throws Exception
    176      */
    177     @Rpc(description = "Get the services from the BluetoothGatt object")
    178     public List<BluetoothGattService> gattClientGetServices(
    179             @RpcParameter(name = "index") Integer index) throws Exception {
    180         if (mBluetoothGattList.get(index) != null) {
    181             return mBluetoothGattList.get(index).getServices();
    182         } else {
    183             throw new Exception("Invalid index input:" + Integer.toString(index));
    184         }
    185     }
    186 
    187     /**
    188      * Abort reliable write of a bluetooth gatt
    189      *
    190      * @param index the bluetooth gatt index
    191      * @throws Exception
    192      */
    193     @Rpc(description = "Abort reliable write of a bluetooth gatt")
    194     public void gattClientAbortReliableWrite(@RpcParameter(name = "index") Integer index)
    195             throws Exception {
    196         if (mBluetoothGattList.get(index) != null) {
    197             mBluetoothGattList.get(index).abortReliableWrite();
    198         } else {
    199             throw new Exception("Invalid index input:" + index);
    200         }
    201     }
    202 
    203     /**
    204      * Begin reliable write of a bluetooth gatt
    205      *
    206      * @param index the bluetooth gatt index
    207      * @return
    208      * @throws Exception
    209      */
    210     @Rpc(description = "Begin reliable write of a bluetooth gatt")
    211     public boolean gattClientBeginReliableWrite(@RpcParameter(name = "index") Integer index)
    212             throws Exception {
    213         if (mBluetoothGattList.get(index) != null) {
    214             return mBluetoothGattList.get(index).beginReliableWrite();
    215         } else {
    216             throw new Exception("Invalid index input:" + index);
    217         }
    218     }
    219 
    220     /**
    221      * Configure a bluetooth gatt's MTU
    222      *
    223      * @param index the bluetooth gatt index
    224      * @param mtu the MTU to set
    225      * @return
    226      * @throws Exception
    227      */
    228     @Rpc(description = "true, if the new MTU value has been requested successfully")
    229     public boolean gattClientRequestMtu(
    230             @RpcParameter(name = "index") Integer index, @RpcParameter(name = "mtu") Integer mtu)
    231             throws Exception {
    232         if (mBluetoothGattList.get(index) != null) {
    233             return mBluetoothGattList.get(index).requestMtu(mtu);
    234         } else {
    235             throw new Exception("Invalid index input:" + index);
    236         }
    237     }
    238 
    239     /**
    240      * Read the current transmitter PHY and receiver PHY of the connection.
    241      *
    242      * @param index the bluetooth gatt index
    243      * @throws Exception
    244      */
    245     @Rpc(description = "Read PHY")
    246     public void gattClientReadPhy(@RpcParameter(name = "index") Integer index) throws Exception {
    247         if (mBluetoothGattList.get(index) != null) {
    248             mBluetoothGattList.get(index).readPhy();
    249         } else {
    250             throw new Exception("Invalid index input:" + index);
    251         }
    252     }
    253 
    254     /**
    255      * Set the preferred connection PHY.
    256      *
    257      * @param index the bluetooth gatt index
    258      * @throws Exception
    259      */
    260     @Rpc(description = "Set the preferred connection PHY")
    261     public void gattClientSetPreferredPhy(@RpcParameter(name = "index") Integer index,
    262             @RpcParameter(name = "txPhy") Integer txPhy,
    263             @RpcParameter(name = "rxPhy") Integer rxPhy,
    264             @RpcParameter(name = "txPhy") Integer phyOptions) throws Exception {
    265         if (mBluetoothGattList.get(index) != null) {
    266             mBluetoothGattList.get(index).setPreferredPhy(txPhy, rxPhy, phyOptions);
    267         } else {
    268             throw new Exception("Invalid index input:" + index);
    269         }
    270     }
    271 
    272     /**
    273      * Disconnect a bluetooth gatt
    274      *
    275      * @param index the bluetooth gatt index
    276      * @throws Exception
    277      */
    278     @Rpc(description = "Disconnect a bluetooth gatt")
    279     @RpcStopEvent("GattConnect")
    280     public void gattClientDisconnect(@RpcParameter(name = "index") Integer index) throws Exception {
    281         if (mBluetoothGattList.get(index) != null) {
    282             mBluetoothGattList.get(index).disconnect();
    283         } else {
    284             throw new Exception("Invalid index input: " + index);
    285         }
    286     }
    287 
    288     /**
    289      * Close a bluetooth gatt object
    290      *
    291      * @param index the bluetooth gatt index
    292      * @throws Exception
    293      */
    294     @Rpc(description = "Close a Bluetooth GATT object")
    295     public void gattClientClose(@RpcParameter(name = "index") Integer index) throws Exception {
    296         if (mBluetoothGattList.get(index) != null) {
    297             mBluetoothGattList.get(index).close();
    298         } else {
    299             throw new Exception("Invalid index input: " + index);
    300         }
    301     }
    302 
    303     /**
    304      * Execute reliable write on a bluetooth gatt
    305      *
    306      * @param index the bluetooth gatt index
    307      * @return true, if the request to execute the transaction has been sent
    308      * @throws Exception
    309      */
    310     @Rpc(description = "Execute reliable write on a bluetooth gatt")
    311     public boolean gattExecuteReliableWrite(@RpcParameter(name = "index") Integer index)
    312             throws Exception {
    313         if (mBluetoothGattList.get(index) != null) {
    314             return mBluetoothGattList.get(index).executeReliableWrite();
    315         } else {
    316             throw new Exception("Invalid index input:" + index);
    317         }
    318     }
    319 
    320     /**
    321      * Get a list of Bluetooth Devices connnected to the bluetooth gatt
    322      *
    323      * @param index the bluetooth gatt index
    324      * @return List of BluetoothDevice Objects
    325      * @throws Exception
    326      */
    327     @Rpc(description = "Get a list of Bluetooth Devices connnected to the bluetooth gatt")
    328     public List<BluetoothDevice> gattClientGetConnectedDevices(
    329             @RpcParameter(name = "index") Integer index) throws Exception {
    330         if (mBluetoothGattList.get(index) != null) {
    331             return mBluetoothGattList.get(index).getConnectedDevices();
    332         } else {
    333             throw new Exception("Invalid index input:" + index);
    334         }
    335     }
    336 
    337     /**
    338      * Get the remote bluetooth device this GATT client targets to
    339      *
    340      * @param index the bluetooth gatt index
    341      * @return the remote bluetooth device this gatt client targets to
    342      * @throws Exception
    343      */
    344     @Rpc(description = "Get the remote bluetooth device this GATT client targets to")
    345     public BluetoothDevice gattGetDevice(@RpcParameter(name = "index") Integer index)
    346             throws Exception {
    347         if (mBluetoothGattList.get(index) != null) {
    348             return mBluetoothGattList.get(index).getDevice();
    349         } else {
    350             throw new Exception("Invalid index input:" + index);
    351         }
    352     }
    353 
    354     /**
    355      * Get the bluetooth devices matching input connection states
    356      *
    357      * @param index the bluetooth gatt index
    358      * @param states the list of states to match
    359      * @return The list of BluetoothDevice objects that match the states
    360      * @throws Exception
    361      */
    362     @Rpc(description = "Get the bluetooth devices matching input connection states")
    363     public List<BluetoothDevice> gattClientGetDevicesMatchingConnectionStates(
    364             @RpcParameter(name = "index") Integer index, @RpcParameter(
    365                 name = "states") int[] states)
    366             throws Exception {
    367         if (mBluetoothGattList.get(index) != null) {
    368             return mBluetoothGattList.get(index).getDevicesMatchingConnectionStates(states);
    369         } else {
    370             throw new Exception("Invalid index input:" + index);
    371         }
    372     }
    373 
    374     /**
    375      * Get the service from an input UUID
    376      *
    377      * @param index the bluetooth gatt index
    378      * @return BluetoothGattService related to the bluetooth gatt
    379      * @throws Exception
    380      */
    381     @Rpc(description = "Get the service from an input UUID")
    382     public ArrayList<String> gattClientGetServiceUuidList(
    383             @RpcParameter(name = "index") Integer index)
    384             throws Exception {
    385         if (mBluetoothGattList.get(index) != null) {
    386             ArrayList<String> serviceUuidList = new ArrayList<String>();
    387             for (BluetoothGattService service : mBluetoothGattList.get(index).getServices()) {
    388                 serviceUuidList.add(service.getUuid().toString());
    389             }
    390             return serviceUuidList;
    391         } else {
    392             throw new Exception("Invalid index input:" + index);
    393         }
    394     }
    395 
    396     /**
    397      * Reads the requested characteristic from the associated remote device.
    398      *
    399      * @deprecated Use {@link #gattClientReadCharacteristicByIndex(gattIndex,
    400      *     discoveredServiceListIndex, serviceIndex, characteristicIndex)} instead.
    401      * @param gattIndex the BluetoothGatt server accociated with the device
    402      * @param discoveredServiceListIndex the index returned from the discovered services callback
    403      * @param serviceIndex the service index of the discovered services
    404      * @param characteristicUuid the characteristic uuid to read
    405      * @return true, if the read operation was initiated successfully
    406      * @throws Exception
    407      */
    408     @Rpc(description = "Reads the requested characteristic from the associated remote device.")
    409     @Deprecated
    410     public boolean gattClientReadCharacteristic(
    411             @RpcParameter(name = "gattIndex") Integer gattIndex,
    412             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    413             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
    414             @RpcParameter(name = "characteristicUuid") String characteristicUuid) throws Exception {
    415         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    416         if (bluetoothGatt == null) {
    417             throw new Exception("Invalid gattIndex " + gattIndex);
    418         }
    419         List<BluetoothGattService> gattServiceList =
    420                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    421         if (gattServiceList == null) {
    422             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    423         }
    424         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
    425         if (gattService == null) {
    426             throw new Exception("Invalid serviceIndex " + serviceIndex);
    427         }
    428         UUID cUuid = UUID.fromString(characteristicUuid);
    429         BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
    430         if (gattCharacteristic == null) {
    431             throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
    432         }
    433         return bluetoothGatt.readCharacteristic(gattCharacteristic);
    434     }
    435 
    436     /**
    437      * Reads the characteristic from the associated remote device.
    438      *
    439      * @param gattIndex the BluetoothGatt server accociated with the device
    440      * @param uuid the characteristic uuid to read
    441      * @return true, if the read operation was initiated successfully
    442      * @throws Exception
    443      */
    444     @Rpc(description = "Reads the characteristic from the associated remote device.")
    445     public boolean gattClientReadUsingCharacteristicUuid(
    446             @RpcParameter(name = "gattIndex") Integer gattIndex,
    447             @RpcParameter(name = "uuid") String uuid,
    448             @RpcParameter(name = "startHandle") Integer startHandle,
    449             @RpcParameter(name = "endHandle") Integer endHandle) throws Exception {
    450         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    451         if (bluetoothGatt == null) {
    452             throw new Exception("Invalid gattIndex " + gattIndex);
    453         }
    454         UUID cUuid = UUID.fromString(uuid);
    455         return bluetoothGatt.readUsingCharacteristicUuid(cUuid, startHandle, endHandle);
    456     }
    457 
    458     /**
    459      * Reads the requested characteristic from the associated remote device.
    460      *
    461      * @param gattIndex the BluetoothGatt server accociated with the device
    462      * @param discoveredServiceListIndex the index returned from the discovered services callback
    463      * @param serviceIndex the service index of the discovered services
    464      * @param characteristicIndex the characteristic index
    465      * @return true, if the read operation was initiated successfully
    466      * @throws Exception
    467      */
    468     @Rpc(description = "Reads the requested characteristic from the associated remote device.")
    469     public boolean gattClientReadCharacteristicByIndex(
    470             @RpcParameter(name = "gattIndex") Integer gattIndex,
    471             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    472             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
    473             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex)
    474             throws Exception {
    475         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    476         if (bluetoothGatt == null) {
    477             throw new Exception("Invalid gattIndex " + gattIndex);
    478         }
    479         List<BluetoothGattService> gattServiceList =
    480                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    481         if (gattServiceList == null) {
    482             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    483         }
    484         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
    485         if (gattService == null) {
    486             throw new Exception("Invalid serviceIndex " + serviceIndex);
    487         }
    488         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
    489         if (charList.get(characteristicIndex) == null) {
    490             throw new Exception("Invalid characteristicIndex " + characteristicIndex);
    491         }
    492         return bluetoothGatt.readCharacteristic(charList.get(characteristicIndex));
    493     }
    494 
    495     /**
    496      * Reads the requested characteristic from the associated remote device by instance id.
    497      *
    498      * @param gattIndex the BluetoothGatt server accociated with the device
    499      * @param discoveredServiceListIndex the index returned from the discovered services callback
    500      * @return true, if the read operation was initiated successfully
    501      * @throws Exception
    502      */
    503     @Rpc(description = "Reads the requested characteristic from the associated remote "
    504             + "device by instance id.")
    505     public boolean gattClientReadCharacteristicByInstanceId(
    506             @RpcParameter(name = "gattIndex") Integer gattIndex,
    507             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    508             @RpcParameter(name = "characteristicInstanceId") Integer characteristicInstanceId)
    509             throws Exception {
    510         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    511         if (bluetoothGatt == null) {
    512             throw new Exception("Invalid gattIndex " + gattIndex);
    513         }
    514         List<BluetoothGattService> gattServiceList =
    515                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    516         if (gattServiceList == null) {
    517             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    518         }
    519         for (BluetoothGattService mGattService : gattServiceList) {
    520             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
    521             for (BluetoothGattCharacteristic mGattChar : charList) {
    522                 if (mGattChar.getInstanceId() == characteristicInstanceId) {
    523                     Log.i("Found Characteristic to read. instanceId: "
    524                         + Integer.toString(characteristicInstanceId)
    525                         + " UUID: " + mGattChar.getUuid().toString());
    526                     return bluetoothGatt.readCharacteristic(mGattChar);
    527                 }
    528             }
    529         }
    530         Log.e("Failed to find Characteristic with instanceId: " + Integer.toString(
    531             characteristicInstanceId));
    532         return false;
    533     }
    534 
    535     /**
    536      * Writes the requested characteristic from the associated remote device by instance id.
    537      *
    538      * @param gattIndex the BluetoothGatt server accociated with the device
    539      * @param discoveredServiceListIndex the index returned from the discovered services callback
    540      * @param characteristicInstanceId the integer instance id of the Characteristic to write to
    541      * @param value the value to write to the characteristic
    542      * @return true, if the read operation was initiated successfully
    543      * @throws Exception
    544      */
    545     @Rpc(description = "Writes the requested characteristic from the associated remote "
    546             + "device by instance id.")
    547     public boolean gattClientWriteDescriptorByInstanceId(
    548             @RpcParameter(name = "gattIndex") Integer gattIndex,
    549             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    550             @RpcParameter(name = "descriptorInstanceId") Integer descriptorInstanceId,
    551             @RpcParameter(name = "value") byte[] value)
    552             throws Exception {
    553         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    554         if (bluetoothGatt == null) {
    555             throw new Exception("Invalid gattIndex " + gattIndex);
    556         }
    557         List<BluetoothGattService> gattServiceList =
    558                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    559         if (gattServiceList == null) {
    560             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    561         }
    562         for (BluetoothGattService mGattService : gattServiceList) {
    563             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
    564             for (BluetoothGattCharacteristic mGattChar : charList) {
    565                 List<BluetoothGattDescriptor> descList = mGattChar.getDescriptors();
    566                 for (BluetoothGattDescriptor mGattDesc : descList) {
    567                     if (mGattDesc.getInstanceId() == descriptorInstanceId) {
    568                         mGattDesc.setValue(value);
    569                         Log.i("Found Descriptor to write. instanceId: "
    570                             + Integer.toString(descriptorInstanceId)
    571                             + " UUID: " + mGattDesc.getUuid().toString());
    572                         return bluetoothGatt.writeDescriptor(mGattDesc);
    573                     }
    574                 }
    575             }
    576         }
    577         Log.e("Failed to find Descriptor with instanceId: " + Integer.toString(
    578             descriptorInstanceId));
    579         return false;
    580     }
    581 
    582     /**
    583      * Writes the requested characteristic from the associated remote device by instance id.
    584      *
    585      * @param gattIndex the BluetoothGatt server accociated with the device
    586      * @param discoveredServiceListIndex the index returned from the discovered services callback
    587      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    588      * @param value the value to write to the characteristic
    589      * @return true, if the read operation was initiated successfully
    590      * @throws Exception
    591      */
    592     @Rpc(description = "Writes the requested characteristic from the associated remote "
    593             + "device by instance id.")
    594     public boolean gattClientWriteCharacteristicByInstanceId(
    595             @RpcParameter(name = "gattIndex") Integer gattIndex,
    596             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    597             @RpcParameter(name = "characteristicInstanceId") Integer characteristicInstanceId,
    598             @RpcParameter(name = "value") byte[] value)
    599             throws Exception {
    600         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    601         if (bluetoothGatt == null) {
    602             throw new Exception("Invalid gattIndex " + gattIndex);
    603         }
    604         List<BluetoothGattService> gattServiceList =
    605                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    606         if (gattServiceList == null) {
    607             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    608         }
    609         for (BluetoothGattService mGattService : gattServiceList) {
    610             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
    611             for (BluetoothGattCharacteristic mGattChar : charList) {
    612                 if (mGattChar.getInstanceId() == characteristicInstanceId) {
    613                     mGattChar.setValue(value);
    614                     Log.i("Found Characteristic to write. instanceId: "
    615                         + Integer.toString(characteristicInstanceId)
    616                         + " UUID: " + mGattChar.getUuid().toString());
    617                     return bluetoothGatt.writeCharacteristic(mGattChar);
    618                 }
    619             }
    620         }
    621         Log.e("Failed to find Characteristic with instanceId: " + Integer.toString(
    622             characteristicInstanceId));
    623         return false;
    624     }
    625 
    626     /**
    627      * Writes the requested characteristic in which write is not permitted. For conformance tests
    628      * only.
    629      *
    630      * @param gattIndex the BluetoothGatt server accociated with the device
    631      * @param discoveredServiceListIndex the index returned from the discovered services callback
    632      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    633      * @param value the value to write to the characteristic
    634      * @return true, if the read operation was initiated successfully
    635      * @throws Exception
    636      */
    637     @Rpc(description = "Writes the requested characteristic from the associated remote "
    638             + "device by instance id.")
    639     public boolean gattClientModifyAccessAndWriteCharacteristicByInstanceId(
    640             @RpcParameter(name = "gattIndex") Integer gattIndex,
    641             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    642             @RpcParameter(name = "characteristicInstanceId") Integer characteristicInstanceId,
    643             @RpcParameter(name = "value") byte[] value)
    644             throws Exception {
    645         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    646         if (bluetoothGatt == null) {
    647             throw new Exception("Invalid gattIndex " + gattIndex);
    648         }
    649         List<BluetoothGattService> gattServiceList =
    650                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    651         if (gattServiceList == null) {
    652             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    653         }
    654         for (BluetoothGattService mGattService : gattServiceList) {
    655             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
    656             for (BluetoothGattCharacteristic mGattChar : charList) {
    657                 if (mGattChar.getInstanceId() == characteristicInstanceId) {
    658                     Log.i("Found Characteristic to write. instanceId: "
    659                         + Integer.toString(characteristicInstanceId)
    660                         + " UUID: " + mGattChar.getUuid().toString());
    661                     BluetoothGattCharacteristic modChar = new BluetoothGattCharacteristic(
    662                         mGattChar.getUuid(), 0x08, 0x10);
    663                     modChar.setInstanceId(mGattChar.getInstanceId());
    664                     mGattService.addCharacteristic(modChar);
    665                     modChar.setValue(value);
    666                     return bluetoothGatt.writeCharacteristic(modChar);
    667                 }
    668             }
    669         }
    670         Log.e("Failed to find Characteristic with instanceId: " + Integer.toString(
    671             characteristicInstanceId));
    672         return false;
    673     }
    674 
    675     /**
    676      * Writes the requested descriptor in which write is not permitted. For conformance tests only.
    677      *
    678      * @param gattIndex the BluetoothGatt server accociated with the device
    679      * @param discoveredServiceListIndex the index returned from the discovered services callback
    680      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    681      * @param value the value to write to the characteristic
    682      * @return true, if the read operation was initiated successfully
    683      * @throws Exception
    684      */
    685     @Rpc(description = "Writes a Characteristic with an invalid instanceId to each service.")
    686     public boolean gattClientWriteInvalidCharacteristicByInstanceId(
    687             @RpcParameter(name = "gattIndex") Integer gattIndex,
    688             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    689             @RpcParameter(name = "instanceId") Integer instanceId,
    690             @RpcParameter(name = "value") byte[] value)
    691             throws Exception {
    692         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    693         if (bluetoothGatt == null) {
    694             throw new Exception("Invalid gattIndex " + gattIndex);
    695         }
    696         List<BluetoothGattService> gattServiceList =
    697                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    698         if (gattServiceList == null) {
    699             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    700         }
    701         for (BluetoothGattService mGattService : gattServiceList) {
    702             BluetoothGattCharacteristic invalidHandleChar = new BluetoothGattCharacteristic(
    703                 UUID.fromString("aa7edd5a-4d1d-4f0e-883a-d145616a1630"), 0x08, 0x10);
    704             invalidHandleChar.setInstanceId(instanceId);
    705             mGattService.addCharacteristic(invalidHandleChar);
    706             invalidHandleChar.setValue(value);
    707             //todo: this used to be return bluetoothGatt. Retest with and without return
    708             bluetoothGatt.writeCharacteristic(invalidHandleChar);
    709         }
    710         return true;
    711     }
    712 
    713     /**
    714      * Writes the requested characteristic in which write is not permitted. For conformance tests
    715      * only.
    716      *
    717      * @param gattIndex the BluetoothGatt server accociated with the device
    718      * @param discoveredServiceListIndex the index returned from the discovered services callback
    719      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    720      * @param value the value to write to the characteristic
    721      * @return true, if the read operation was initiated successfully
    722      * @throws Exception
    723      */
    724     @Rpc(description = "Read the requested characteristic from the associated remote "
    725             + "device by instance id.")
    726     public boolean gattClientModifyAccessAndReadCharacteristicByInstanceId(
    727             @RpcParameter(name = "gattIndex") Integer gattIndex,
    728             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    729             @RpcParameter(name = "characteristicInstanceId") Integer characteristicInstanceId)
    730             throws Exception {
    731         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    732         if (bluetoothGatt == null) {
    733             throw new Exception("Invalid gattIndex " + gattIndex);
    734         }
    735         List<BluetoothGattService> gattServiceList =
    736                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    737         if (gattServiceList == null) {
    738             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    739         }
    740         for (BluetoothGattService mGattService : gattServiceList) {
    741             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
    742             for (BluetoothGattCharacteristic mGattChar : charList) {
    743                 if (mGattChar.getInstanceId() == characteristicInstanceId) {
    744                     Log.i("Found Characteristic to read. instanceId: "
    745                         + Integer.toString(characteristicInstanceId)
    746                         + " UUID: " + mGattChar.getUuid().toString());
    747                     BluetoothGattCharacteristic modChar = new BluetoothGattCharacteristic(
    748                         mGattChar.getUuid(), 0x02, 0x01);
    749                     modChar.setInstanceId(mGattChar.getInstanceId());
    750                     mGattService.addCharacteristic(modChar);
    751                     return bluetoothGatt.readCharacteristic(modChar);
    752                 }
    753             }
    754         }
    755         Log.e("Failed to find Characteristic with instanceId: " + Integer.toString(
    756             characteristicInstanceId));
    757         return false;
    758     }
    759 
    760     /**
    761      * Writes the requested descriptor in which write is not permitted. For conformance tests only.
    762      *
    763      * @param gattIndex the BluetoothGatt server accociated with the device
    764      * @param discoveredServiceListIndex the index returned from the discovered services callback
    765      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    766      * @param value the value to write to the characteristic
    767      * @return true, if the read operation was initiated successfully
    768      * @throws Exception
    769      */
    770     @Rpc(description = "Read a Characteristic with an invalid instanceId to each service.")
    771     public boolean gattClientReadInvalidCharacteristicByInstanceId(
    772             @RpcParameter(name = "gattIndex") Integer gattIndex,
    773             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    774             @RpcParameter(name = "characteristicInstanceId") Integer characteristicInstanceId)
    775             throws Exception {
    776         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    777         if (bluetoothGatt == null) {
    778             throw new Exception("Invalid gattIndex " + gattIndex);
    779         }
    780         List<BluetoothGattService> gattServiceList =
    781                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    782         if (gattServiceList == null) {
    783             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    784         }
    785         for (BluetoothGattService mGattService : gattServiceList) {
    786             BluetoothGattCharacteristic invalidHandleChar = new BluetoothGattCharacteristic(
    787                 UUID.fromString("aa7edd5a-4d1d-4f0e-883a-d145616a1630"), 0x02, 0x01);
    788             invalidHandleChar.setInstanceId(characteristicInstanceId);
    789             mGattService.addCharacteristic(invalidHandleChar);
    790             bluetoothGatt.readCharacteristic(invalidHandleChar);
    791         }
    792         return true;
    793     }
    794 
    795     /**
    796      * Writes the requested descriptor in which write is not permitted. For conformance tests
    797      * only.
    798      *
    799      * @param gattIndex the BluetoothGatt server accociated with the device
    800      * @param discoveredServiceListIndex the index returned from the discovered services callback
    801      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    802      * @param value the value to write to the characteristic
    803      * @return true, if the read operation was initiated successfully
    804      * @throws Exception
    805      */
    806     @Rpc(description = "Writes the requested descriptor from the associated remote "
    807             + "device by instance id.")
    808     public boolean gattClientModifyAccessAndWriteDescriptorByInstanceId(
    809             @RpcParameter(name = "gattIndex") Integer gattIndex,
    810             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    811             @RpcParameter(name = "descriptorInstanceId") Integer descriptorInstanceId,
    812             @RpcParameter(name = "value") byte[] value)
    813             throws Exception {
    814         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    815         if (bluetoothGatt == null) {
    816             throw new Exception("Invalid gattIndex " + gattIndex);
    817         }
    818         List<BluetoothGattService> gattServiceList =
    819                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    820         if (gattServiceList == null) {
    821             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    822         }
    823         for (BluetoothGattService mGattService : gattServiceList) {
    824             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
    825             for (BluetoothGattCharacteristic mGattChar : charList) {
    826                 for (BluetoothGattDescriptor mGattDesc : mGattChar.getDescriptors()) {
    827                     if (mGattDesc.getInstanceId() == descriptorInstanceId) {
    828                         Log.i("Found Descriptor to write. instanceId: "
    829                             + Integer.toString(descriptorInstanceId)
    830                             + " UUID: " + mGattChar.getUuid().toString());
    831                         BluetoothGattDescriptor modDesc = new BluetoothGattDescriptor(
    832                             mGattDesc.getUuid(), 0x10);
    833                         modDesc.setInstanceId(descriptorInstanceId);
    834                         mGattChar.addDescriptor(modDesc);
    835                         modDesc.setValue(value);
    836                         return bluetoothGatt.writeDescriptor(modDesc);
    837                     }
    838                 }
    839             }
    840         }
    841         Log.e("Failed to find Descriptor with instanceId: " + Integer.toString(
    842             descriptorInstanceId));
    843         return false;
    844     }
    845 
    846     /**
    847      * Writes the requested descriptor in which write is not permitted. For conformance tests only.
    848      *
    849      * @param gattIndex the BluetoothGatt server accociated with the device
    850      * @param discoveredServiceListIndex the index returned from the discovered services callback
    851      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    852      * @param value the value to write to the characteristic
    853      * @return true, if the read operation was initiated successfully
    854      * @throws Exception
    855      */
    856     @Rpc(description = "Writes a Characteristic with an invalid instanceId to each service.")
    857     public boolean gattClientWriteInvalidDescriptorByInstanceId(
    858             @RpcParameter(name = "gattIndex") Integer gattIndex,
    859             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    860             @RpcParameter(name = "instanceId") Integer instanceId,
    861             @RpcParameter(name = "value") byte[] value)
    862             throws Exception {
    863         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    864         if (bluetoothGatt == null) {
    865             throw new Exception("Invalid gattIndex " + gattIndex);
    866         }
    867         List<BluetoothGattService> gattServiceList =
    868                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    869         if (gattServiceList == null) {
    870             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    871         }
    872         for (BluetoothGattService mGattService : gattServiceList) {
    873             for (BluetoothGattCharacteristic mGattChar : mGattService.getCharacteristics()) {
    874                 BluetoothGattDescriptor invalidHandleDesc = new BluetoothGattDescriptor(
    875                     UUID.fromString("aa7edd5a-4d1d-4f0e-883a-d145616a1630"), 0x10);
    876                 invalidHandleDesc.setInstanceId(instanceId);
    877                 mGattChar.addDescriptor(invalidHandleDesc);
    878                 invalidHandleDesc.setValue(value);
    879                 bluetoothGatt.writeDescriptor(invalidHandleDesc);
    880             }
    881         }
    882         return true;
    883     }
    884 
    885     /**
    886      * Writes the requested descriptor in which write is not permitted. For conformance tests
    887      * only.
    888      *
    889      * @param gattIndex the BluetoothGatt server accociated with the device
    890      * @param discoveredServiceListIndex the index returned from the discovered services callback
    891      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    892      * @param value the value to write to the characteristic
    893      * @return true, if the read operation was initiated successfully
    894      * @throws Exception
    895      */
    896     @Rpc(description = "Read the requested descriptor from the associated remote "
    897             + "device by instance id.")
    898     public boolean gattClientModifyAccessAndReadDescriptorByInstanceId(
    899             @RpcParameter(name = "gattIndex") Integer gattIndex,
    900             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    901             @RpcParameter(name = "descriptorInstanceId") Integer descriptorInstanceId)
    902             throws Exception {
    903         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    904         if (bluetoothGatt == null) {
    905             throw new Exception("Invalid gattIndex " + gattIndex);
    906         }
    907         List<BluetoothGattService> gattServiceList =
    908                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    909         if (gattServiceList == null) {
    910             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    911         }
    912         for (BluetoothGattService mGattService : gattServiceList) {
    913             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
    914             for (BluetoothGattCharacteristic mGattChar : charList) {
    915                 for (BluetoothGattDescriptor mGattDesc : mGattChar.getDescriptors()) {
    916                     if (mGattDesc.getInstanceId() == descriptorInstanceId) {
    917                         Log.i("Found Descriptor to read. instanceId: "
    918                             + Integer.toString(descriptorInstanceId)
    919                             + " UUID: " + mGattDesc.getUuid().toString());
    920                         BluetoothGattDescriptor modDesc = new BluetoothGattDescriptor(
    921                             mGattDesc.getUuid(), 0x01);
    922                         modDesc.setInstanceId(descriptorInstanceId);
    923                         mGattChar.addDescriptor(modDesc);
    924                         return bluetoothGatt.readDescriptor(modDesc);
    925                     }
    926                 }
    927             }
    928         }
    929         Log.e("Failed to find Descriptor with instanceId: " + Integer.toString(
    930             descriptorInstanceId));
    931         return false;
    932     }
    933 
    934     /**
    935      * Writes the requested descriptor in which write is not permitted. For conformance tests only.
    936      *
    937      * @param gattIndex the BluetoothGatt server accociated with the device
    938      * @param discoveredServiceListIndex the index returned from the discovered services callback
    939      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    940      * @param value the value to write to the characteristic
    941      * @return true, if the read operation was initiated successfully
    942      * @throws Exception
    943      */
    944     @Rpc(description = "Read a Characteristic with an invalid instanceId to each service.")
    945     public boolean gattClientReadInvalidDescriptorByInstanceId(
    946             @RpcParameter(name = "gattIndex") Integer gattIndex,
    947             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    948             @RpcParameter(name = "descriptorInstanceId") Integer descriptorInstanceId)
    949             throws Exception {
    950         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    951         if (bluetoothGatt == null) {
    952             throw new Exception("Invalid gattIndex " + gattIndex);
    953         }
    954         List<BluetoothGattService> gattServiceList =
    955                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    956         if (gattServiceList == null) {
    957             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    958         }
    959         for (BluetoothGattService mGattService : gattServiceList) {
    960             for (BluetoothGattCharacteristic mGattChar : mGattService.getCharacteristics()) {
    961                 BluetoothGattDescriptor invalidHandleDesc = new BluetoothGattDescriptor(
    962                     UUID.fromString("aa7edd5a-4d1d-4f0e-883a-d145616a1630"), 0x01);
    963                 invalidHandleDesc.setInstanceId(descriptorInstanceId);
    964                 mGattChar.addDescriptor(invalidHandleDesc);
    965                 bluetoothGatt.readDescriptor(invalidHandleDesc);
    966             }
    967         }
    968         return true;
    969     }
    970 
    971     /**
    972      * Writes the requested characteristic in which write is not permitted. For conformance tests
    973      * only.
    974      *
    975      * @param gattIndex the BluetoothGatt server accociated with the device
    976      * @param discoveredServiceListIndex the index returned from the discovered services callback
    977      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
    978      * @param value the value to write to the characteristic
    979      * @return true, if the read operation was initiated successfully
    980      * @throws Exception
    981      */
    982     @Rpc(description = "Read the requested characteristic from the associated remote "
    983             + "device by uuid.")
    984     public boolean gattClientModifyAccessAndReadCharacteristicByUuidAndInstanceId(
    985             @RpcParameter(name = "gattIndex") Integer gattIndex,
    986             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
    987             @RpcParameter(name = "characteristicInstanceId") Integer characteristicInstanceId,
    988             @RpcParameter(name = "characteristicUuid") String characteristicUuid)
    989             throws Exception {
    990         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
    991         if (bluetoothGatt == null) {
    992             throw new Exception("Invalid gattIndex " + gattIndex);
    993         }
    994         List<BluetoothGattService> gattServiceList =
    995                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
    996         if (gattServiceList == null) {
    997             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
    998         }
    999         for (BluetoothGattService mGattService : gattServiceList) {
   1000             List<BluetoothGattCharacteristic> charList = mGattService.getCharacteristics();
   1001             for (BluetoothGattCharacteristic mGattChar : charList) {
   1002                 if (mGattChar.getUuid().toString().equalsIgnoreCase(characteristicUuid) &&
   1003                         mGattChar.getInstanceId() == characteristicInstanceId) {
   1004                     Log.i("Found Characteristic to read. UUID: " + mGattChar.getUuid().toString());
   1005                     BluetoothGattCharacteristic modChar = new BluetoothGattCharacteristic(
   1006                         mGattChar.getUuid(), 0x02, 0x01);
   1007                     modChar.setInstanceId(characteristicInstanceId);
   1008                     mGattService.addCharacteristic(modChar);
   1009                     bluetoothGatt.readCharacteristic(modChar);
   1010                 }
   1011             }
   1012         }
   1013         return true;
   1014     }
   1015 
   1016     /**
   1017      * Writes the requested descriptor in which write is not permitted. For conformance tests only.
   1018      *
   1019      * @param gattIndex the BluetoothGatt server accociated with the device
   1020      * @param discoveredServiceListIndex the index returned from the discovered services callback
   1021      * @param descriptorInstanceId the integer instance id of the Characteristic to write to
   1022      * @param value the value to write to the characteristic
   1023      * @return true, if the read operation was initiated successfully
   1024      * @throws Exception
   1025      */
   1026     @Rpc(description = "Read a Characteristic with an invalid Uuid to each service.")
   1027     public boolean gattClientReadInvalidCharacteristicByUuidAndInstanceId(
   1028             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1029             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1030             @RpcParameter(name = "characteristicUuid") String characteristicUuid)
   1031             throws Exception {
   1032         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1033         if (bluetoothGatt == null) {
   1034             throw new Exception("Invalid gattIndex " + gattIndex);
   1035         }
   1036         List<BluetoothGattService> gattServiceList =
   1037                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1038         if (gattServiceList == null) {
   1039             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1040         }
   1041         for (BluetoothGattService mGattService : gattServiceList) {
   1042             BluetoothGattCharacteristic invalidHandleChar = new BluetoothGattCharacteristic(
   1043                 UUID.fromString(characteristicUuid), 0x02, 0x01);
   1044             mGattService.addCharacteristic(invalidHandleChar);
   1045             bluetoothGatt.readCharacteristic(invalidHandleChar);
   1046         }
   1047         return true;
   1048     }
   1049 
   1050     /**
   1051      * /** Reads the value for a given descriptor from the associated remote device
   1052      *
   1053      * @deprecated Use {@link #gattClientReadDescriptorByIndex(
   1054      * gattIndex, discoveredServiceListIndex, serviceIndex, characteristicIndex, descriptorIndex)}
   1055      * instead.
   1056      * @param gattIndex - the gatt index to use
   1057      * @param discoveredServiceListIndex - the discvered serivice list index
   1058      * @param serviceIndex - the servce index of the discoveredServiceListIndex
   1059      * @param characteristicUuid - the characteristic uuid in which the descriptor is
   1060      * @param descriptorUuid - the descriptor uuid to read
   1061      * @return
   1062      * @throws Exception
   1063      */
   1064     @Deprecated
   1065     @Rpc(description = "Reads the value for a given descriptor from the associated remote device")
   1066     public boolean gattClientReadDescriptor(
   1067             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1068             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1069             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1070             @RpcParameter(name = "characteristicUuid") String characteristicUuid,
   1071             @RpcParameter(name = "descriptorUuid") String descriptorUuid) throws Exception {
   1072         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1073         if (bluetoothGatt == null) {
   1074             throw new Exception("Invalid gattIndex " + gattIndex);
   1075         }
   1076         List<BluetoothGattService> gattServiceList = mBluetoothGattDiscoveredServicesList.get(
   1077                       discoveredServiceListIndex);
   1078         if (gattServiceList == null) {
   1079             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1080         }
   1081         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1082         if (gattService == null) {
   1083             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1084         }
   1085         UUID cUuid = UUID.fromString(characteristicUuid);
   1086         BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
   1087         if (gattCharacteristic == null) {
   1088             throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
   1089         }
   1090         UUID dUuid = UUID.fromString(descriptorUuid);
   1091         BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(dUuid);
   1092         if (gattDescriptor == null) {
   1093             throw new Exception("Invalid descriptor uuid: " + descriptorUuid);
   1094         }
   1095         return bluetoothGatt.readDescriptor(gattDescriptor);
   1096     }
   1097 
   1098 
   1099     /**
   1100      * /** Reads the value for a given descriptor from the associated remote device
   1101      *
   1102      * @param gattIndex - the gatt index to use
   1103      * @param discoveredServiceListIndex - the discvered serivice list index
   1104      * @param serviceIndex - the servce index of the discoveredServiceListIndex
   1105      * @param characteristicIndex - the characteristic index
   1106      * @param descriptorIndex - the descriptor index to read
   1107      * @return
   1108      * @throws Exception
   1109      */
   1110     @Rpc(description = "Reads the value for a given descriptor from the associated remote device")
   1111     public boolean gattClientReadDescriptorByIndex(
   1112             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1113             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1114             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1115             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex,
   1116             @RpcParameter(name = "descriptorIndex") Integer descriptorIndex)
   1117             throws Exception {
   1118         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1119         if (bluetoothGatt == null) {
   1120             throw new Exception("Invalid gattIndex " + gattIndex);
   1121         }
   1122         List<BluetoothGattService> gattServiceList =
   1123                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1124         if (gattServiceList == null) {
   1125             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1126         }
   1127         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1128         if (gattService == null) {
   1129             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1130         }
   1131         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1132         if (charList.get(characteristicIndex) == null) {
   1133             throw new Exception("Invalid characteristicIndex " + characteristicIndex);
   1134         }
   1135         BluetoothGattCharacteristic gattCharacteristic = charList.get(characteristicIndex);
   1136         List<BluetoothGattDescriptor> descList = gattCharacteristic.getDescriptors();
   1137         if (descList.get(descriptorIndex) == null) {
   1138             throw new Exception("Invalid descriptorIndex " + descriptorIndex);
   1139         }
   1140         return bluetoothGatt.readDescriptor(descList.get(descriptorIndex));
   1141     }
   1142 
   1143     /**
   1144      * Write the value of a given descriptor to the associated remote device
   1145      *
   1146      * @deprecated Use {@link #gattClientWriteDescriptorByIndex(
   1147      * gattIndex, discoveredServiceListIndex, serviceIndex, characteristicIndex, descriptorIndex)}
   1148      * instead.
   1149      * @param index the bluetooth gatt index
   1150      * @param serviceIndex the service index to write to
   1151      * @param characteristicUuid the uuid where the descriptor lives
   1152      * @param descriptorIndex the descriptor index
   1153      * @return true, if the write operation was initiated successfully
   1154      * @throws Exception
   1155      */
   1156     @Deprecated
   1157     @Rpc(description = "Write the value of a given descriptor to the associated remote device")
   1158     public boolean gattClientWriteDescriptor(
   1159             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1160             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1161             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1162             @RpcParameter(name = "characteristicUuid") String characteristicUuid,
   1163             @RpcParameter(name = "descriptorUuid") String descriptorUuid) throws Exception {
   1164         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1165         if (bluetoothGatt == null) {
   1166             throw new Exception("Invalid gattIndex " + gattIndex);
   1167         }
   1168         List<BluetoothGattService> discoveredServiceList =
   1169                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1170         if (discoveredServiceList == null) {
   1171             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1172         }
   1173         BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
   1174         if (gattService == null) {
   1175             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1176         }
   1177         UUID cUuid = UUID.fromString(characteristicUuid);
   1178         BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
   1179         if (gattCharacteristic == null) {
   1180             throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
   1181         }
   1182         UUID dUuid = UUID.fromString(descriptorUuid);
   1183         BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(dUuid);
   1184         if (gattDescriptor == null) {
   1185             throw new Exception("Invalid descriptor uuid: " + descriptorUuid);
   1186         }
   1187         return bluetoothGatt.writeDescriptor(gattDescriptor);
   1188     }
   1189 
   1190     /**
   1191      * Write the value of a given descriptor to the associated remote device
   1192      *
   1193      * @param index the bluetooth gatt index
   1194      * @param serviceIndex the service index to write to
   1195      * @param characteristicIndex the characteristic index to write to
   1196      * @param descriptorIndex the descriptor index to write to
   1197      * @return true, if the write operation was initiated successfully
   1198      * @throws Exception
   1199      */
   1200     @Rpc(description = "Write the value of a given descriptor to the associated remote device")
   1201     public boolean gattClientWriteDescriptorByIndex(
   1202             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1203             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1204             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1205             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex,
   1206             @RpcParameter(name = "descriptorIndex") Integer descriptorIndex)
   1207             throws Exception {
   1208         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1209         if (bluetoothGatt == null) {
   1210             throw new Exception("Invalid gattIndex " + gattIndex);
   1211         }
   1212         List<BluetoothGattService> gattServiceList =
   1213                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1214         if (gattServiceList == null) {
   1215             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1216         }
   1217         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1218         if (gattService == null) {
   1219             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1220         }
   1221         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1222         if (charList.get(characteristicIndex) == null) {
   1223             throw new Exception("Invalid characteristicIndex " + characteristicIndex);
   1224         }
   1225         BluetoothGattCharacteristic gattCharacteristic = charList.get(characteristicIndex);
   1226         List<BluetoothGattDescriptor> descList = gattCharacteristic.getDescriptors();
   1227         if (descList.get(descriptorIndex) == null) {
   1228             throw new Exception("Invalid descriptorIndex " + descriptorIndex);
   1229         }
   1230         return bluetoothGatt.writeDescriptor(descList.get(descriptorIndex));
   1231     }
   1232 
   1233     /**
   1234      * Write the value to a discovered descriptor.
   1235      *
   1236      * @deprecated Use {@link #gattClientDescriptorSetValueByIndex(
   1237      *  gattIndex, discoveredServiceListIndex, serviceIndex, characteristicIndex, descriptorIndex,
   1238      *  value)} instead.
   1239      * @param gattIndex - the gatt index to use
   1240      * @param discoveredServiceListIndex - the discovered service list index
   1241      * @param serviceIndex - the service index of the discoveredServiceListIndex
   1242      * @param characteristicUuid - the characteristic uuid in which the descriptor is
   1243      * @param descriptorUuid - the descriptor uuid to read
   1244      * @param value - the value to set the descriptor to
   1245      * @return true is the value was set to the descriptor
   1246      * @throws Exception
   1247      */
   1248     @Deprecated
   1249     @Rpc(description = "Write the value of a given descriptor to the associated remote device")
   1250     public boolean gattClientDescriptorSetValue(
   1251             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1252             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1253             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1254             @RpcParameter(name = "characteristicUuid") String characteristicUuid,
   1255             @RpcParameter(name = "descriptorUuid") String descriptorUuid,
   1256             @RpcParameter(name = "value") byte[] value) throws Exception {
   1257         if (mBluetoothGattList.get(gattIndex) == null) {
   1258             throw new Exception("Invalid gattIndex " + gattIndex);
   1259         }
   1260         List<BluetoothGattService> discoveredServiceList =
   1261                   mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1262         if (discoveredServiceList == null) {
   1263             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1264         }
   1265         BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
   1266         if (gattService == null) {
   1267             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1268         }
   1269         UUID cUuid = UUID.fromString(characteristicUuid);
   1270         BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
   1271         if (gattCharacteristic == null) {
   1272             throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
   1273         }
   1274         UUID dUuid = UUID.fromString(descriptorUuid);
   1275         BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(dUuid);
   1276         if (gattDescriptor == null) {
   1277             throw new Exception("Invalid descriptor uuid: " + descriptorUuid);
   1278         }
   1279         return gattDescriptor.setValue(value);
   1280     }
   1281 
   1282     /**
   1283      * Write the value to a discovered descriptor.
   1284      *
   1285      * @param gattIndex - the gatt index to use
   1286      * @param discoveredServiceListIndex - the discovered service list index
   1287      * @param serviceIndex - the service index of the discoveredServiceListIndex
   1288      * @param characteristicIndex - the characteristic index
   1289      * @param descriptorIndex - the descriptor index to set
   1290      * @param value - the value to set the descriptor to
   1291      * @return true is the value was set to the descriptor
   1292      * @throws Exception
   1293      */
   1294     @Rpc(description = "Write the value of a given descriptor to the associated remote device")
   1295     public boolean gattClientDescriptorSetValueByIndex(
   1296             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1297             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1298             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1299             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex,
   1300             @RpcParameter(name = "descriptorIndex") Integer descriptorIndex,
   1301             @RpcParameter(name = "value") byte[] value)
   1302             throws Exception {
   1303         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1304         if (bluetoothGatt == null) {
   1305             throw new Exception("Invalid gattIndex " + gattIndex);
   1306         }
   1307         List<BluetoothGattService> gattServiceList =
   1308                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1309         if (gattServiceList == null) {
   1310             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1311         }
   1312         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1313         if (gattService == null) {
   1314             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1315         }
   1316         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1317         if (charList.get(characteristicIndex) == null) {
   1318             throw new Exception("Invalid characteristicIndex " + characteristicIndex);
   1319         }
   1320         BluetoothGattCharacteristic gattCharacteristic = charList.get(characteristicIndex);
   1321         List<BluetoothGattDescriptor> descList = gattCharacteristic.getDescriptors();
   1322         if (descList.get(descriptorIndex) == null) {
   1323             throw new Exception("Invalid descriptorIndex " + descriptorIndex);
   1324         }
   1325         return descList.get(descriptorIndex).setValue(value);
   1326     }
   1327 
   1328 
   1329     /**
   1330      * Write the value of a given characteristic to the associated remote device
   1331      *
   1332      * @deprecated Use {@link #gattClientWriteCharacteristicByIndex(
   1333      *  gattIndex, discoveredServiceListIndex, serviceIndex, characteristicIndex)} instead.
   1334      * @param index the bluetooth gatt index
   1335      * @param serviceIndex the service where the characteristic lives
   1336      * @param characteristicUuid the characteristic uuid to write to
   1337      * @return true, if the write operation was successful
   1338      * @throws Exception
   1339      */
   1340     @Deprecated
   1341     @Rpc(description = "Write the value of a given characteristic to the associated remote device")
   1342     public boolean gattClientWriteCharacteristic(
   1343             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1344             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1345             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1346             @RpcParameter(name = "characteristicUuid") String characteristicUuid) throws Exception {
   1347         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1348         if (bluetoothGatt == null) {
   1349             throw new Exception("Invalid gattIndex " + gattIndex);
   1350         }
   1351         List<BluetoothGattService> discoveredServiceList =
   1352                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1353         if (discoveredServiceList == null) {
   1354             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1355         }
   1356         BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
   1357         if (gattService == null) {
   1358             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1359         }
   1360         UUID cUuid = UUID.fromString(characteristicUuid);
   1361         BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
   1362         if (gattCharacteristic == null) {
   1363             throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
   1364         }
   1365         return bluetoothGatt.writeCharacteristic(gattCharacteristic);
   1366     }
   1367 
   1368     /**
   1369      * Write the value of a given characteristic to the associated remote device
   1370      *
   1371      * @param index the bluetooth gatt index
   1372      * @param serviceIndex the service where the characteristic lives
   1373      * @param characteristicIndex the characteristic index
   1374      * @return true, if the write operation was successful
   1375      * @throws Exception
   1376      */
   1377     @Rpc(description = "Write the value of a given characteristic to the associated remote device")
   1378     public boolean gattClientWriteCharacteristicByIndex(
   1379             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1380             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1381             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1382             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex)
   1383             throws Exception {
   1384         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1385         if (bluetoothGatt == null) {
   1386             throw new Exception("Invalid gattIndex " + gattIndex);
   1387         }
   1388         List<BluetoothGattService> gattServiceList =
   1389                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1390         if (gattServiceList == null) {
   1391             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1392         }
   1393         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1394         if (gattService == null) {
   1395             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1396         }
   1397         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1398         if (charList.get(characteristicIndex) == null) {
   1399             throw new Exception("Invalid characteristicIndex " + characteristicIndex);
   1400         }
   1401         return bluetoothGatt.writeCharacteristic(charList.get(characteristicIndex));
   1402     }
   1403 
   1404     /**
   1405      * PTS HELPER... Write the value of a given characteristic to the associated remote device
   1406      *
   1407      * @param index the bluetooth gatt index
   1408      * @param serviceIndex the service where the characteristic lives
   1409      * @param characteristicIndex the characteristic index
   1410      * @return true, if the write operation was successful
   1411      * @throws Exception
   1412      */
   1413     @Rpc(description = "Write the value of a given characteristic to the associated remote device")
   1414     public boolean gattClientReadInvalidCharacteristicInstanceId(
   1415             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1416             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1417             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1418             @RpcParameter(name = "instanceId") Integer instanceId)
   1419             throws Exception {
   1420         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1421         if (bluetoothGatt == null) {
   1422             throw new Exception("Invalid gattIndex " + gattIndex);
   1423         }
   1424         List<BluetoothGattService> gattServiceList =
   1425                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1426         if (gattServiceList == null) {
   1427             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1428         }
   1429         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1430         if (gattService == null) {
   1431             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1432         }
   1433         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1434         charList.get(0).setInstanceId(instanceId);
   1435         return bluetoothGatt.readCharacteristic(charList.get(0));
   1436     }
   1437 
   1438     /**
   1439      * Get the input Characteristic's instance ID.
   1440      *
   1441      * @param index the bluetooth gatt index
   1442      * @param serviceIndex the service where the characteristic lives
   1443      * @param characteristicIndex the characteristic index
   1444      * @return true, if the write operation was successful
   1445      * @throws Exception
   1446      */
   1447     @Rpc(description = "Write the value of a given characteristic to the associated remote device")
   1448     public Integer gattClientGetCharacteristicInstanceId(
   1449             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1450             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1451             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1452             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex)
   1453             throws Exception {
   1454         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1455         if (bluetoothGatt == null) {
   1456             throw new Exception("Invalid gattIndex " + gattIndex);
   1457         }
   1458         List<BluetoothGattService> gattServiceList =
   1459                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1460         if (gattServiceList == null) {
   1461             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1462         }
   1463         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1464         if (gattService == null) {
   1465             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1466         }
   1467         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1468         if (charList.get(characteristicIndex) == null) {
   1469             throw new Exception("Invalid characteristicIndex " + characteristicIndex);
   1470         }
   1471         return charList.get(characteristicIndex).getInstanceId();
   1472     }
   1473 
   1474     /**
   1475      * Get the input Descriptor's instance ID.
   1476      *
   1477      * @param index the bluetooth gatt index
   1478      * @param serviceIndex the service where the characteristic lives
   1479      * @param characteristicIndex the characteristic index
   1480      * @param descriptorIndex the descriptor index
   1481      * @return true, if the write operation was successful
   1482      * @throws Exception
   1483      */
   1484     @Rpc(description = "Write the value of a given characteristic to the associated remote device")
   1485     public Integer gattClientGetDescriptorInstanceId(
   1486             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1487             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1488             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1489             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex,
   1490             @RpcParameter(name = "descriptorIndex") Integer descriptorIndex)
   1491             throws Exception {
   1492         BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex);
   1493         if (bluetoothGatt == null) {
   1494             throw new Exception("Invalid gattIndex " + gattIndex);
   1495         }
   1496         List<BluetoothGattService> gattServiceList =
   1497                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1498         if (gattServiceList == null) {
   1499             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1500         }
   1501         BluetoothGattService gattService = gattServiceList.get(serviceIndex);
   1502         if (gattService == null) {
   1503             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1504         }
   1505         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1506         if (charList.get(characteristicIndex) == null) {
   1507             throw new Exception("Invalid characteristicIndex " + characteristicIndex);
   1508         }
   1509         BluetoothGattCharacteristic gattCharacteristic = charList.get(characteristicIndex);
   1510         if (gattCharacteristic == null) {
   1511             throw new Exception("Invalid characteristicIndex " + serviceIndex);
   1512         }
   1513         List<BluetoothGattDescriptor> descList = gattCharacteristic.getDescriptors();
   1514         if (descList.get(descriptorIndex) == null) {
   1515             throw new Exception("Invalid descriptorIndex " + descriptorIndex);
   1516         }
   1517         return descList.get(descriptorIndex).getInstanceId();
   1518     }
   1519 
   1520     /**
   1521      * Write the value to a discovered characteristic.
   1522      *
   1523      * @deprecated Use {@link #gattClientCharacteristicSetValueByIndex(
   1524      *  gattIndex, discoveredServiceListIndex, serviceIndex, characteristicIndex, value)} instead.
   1525      * @param gattIndex - the gatt index to use
   1526      * @param discoveredServiceListIndex - the discovered service list index
   1527      * @param serviceIndex - the service index of the discoveredServiceListIndex
   1528      * @param characteristicUuid - the characteristic uuid in which the descriptor is
   1529      * @param value - the value to set the characteristic to
   1530      * @return true, if the value was set to the characteristic
   1531      * @throws Exception
   1532      */
   1533     @Deprecated
   1534     @Rpc(description = "Write the value of a given characteristic to the associated remote device")
   1535     public boolean gattClientCharacteristicSetValue(
   1536             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1537             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1538             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1539             @RpcParameter(name = "characteristicUuid") String characteristicUuid,
   1540             @RpcParameter(name = "value") byte[] value) throws Exception {
   1541         if (mBluetoothGattList.get(gattIndex) == null) {
   1542             throw new Exception("Invalid gattIndex " + gattIndex);
   1543         }
   1544         List<BluetoothGattService> discoveredServiceList =
   1545                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1546         if (discoveredServiceList == null) {
   1547             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1548         }
   1549         BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
   1550         if (gattService == null) {
   1551             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1552         }
   1553         UUID cUuid = UUID.fromString(characteristicUuid);
   1554         BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
   1555         if (gattCharacteristic == null) {
   1556             throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
   1557         }
   1558         return gattCharacteristic.setValue(value);
   1559     }
   1560 
   1561     /**
   1562      * Write the value to a discovered characteristic.
   1563      *
   1564      * @param gattIndex - the gatt index to use
   1565      * @param discoveredServiceListIndex - the discovered service list index
   1566      * @param serviceIndex - the service index of the discoveredServiceListIndex
   1567      * @param characteristicIndex - the characteristic index
   1568      * @param value - the value to set the characteristic to
   1569      * @return true, if the value was set to the characteristic
   1570      * @throws Exception
   1571      */
   1572     @Rpc(description = "Write the value of a given characteristic to the associated remote device")
   1573     public boolean gattClientCharacteristicSetValueByIndex(
   1574             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1575             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1576             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1577             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex,
   1578             @RpcParameter(name = "value") byte[] value)
   1579             throws Exception {
   1580         if (mBluetoothGattList.get(gattIndex) == null) {
   1581             throw new Exception("Invalid gattIndex " + gattIndex);
   1582         }
   1583         List<BluetoothGattService> discoveredServiceList =
   1584                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1585         if (discoveredServiceList == null) {
   1586             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1587         }
   1588         BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
   1589         if (gattService == null) {
   1590             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1591         }
   1592         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1593         if (charList.get(characteristicIndex) == null) {
   1594             throw new Exception("Invalid characteristicIndex: " + characteristicIndex);
   1595         }
   1596         return charList.get(characteristicIndex).setValue(value);
   1597     }
   1598 
   1599     /**
   1600      * Set write type to a discovered characteristic.
   1601      *
   1602      * @deprecated Use {@link #gattClientCharacteristicSetWriteTypeByIndex(
   1603      *  gattIndex, discoveredServiceListIndex, serviceIndex, ccharacteristicUuid, writeType)}
   1604      * instead.
   1605      * @param gattIndex - the gatt index to use
   1606      * @param discoveredServiceListIndex - the discovered service list index
   1607      * @param serviceIndex - the service index of the discoveredServiceListIndex
   1608      * @param characteristicUuid - the characteristic uuid in which the descriptor is
   1609      * @param writeType - the write type for characteristic
   1610      * @return true, if the value was set to the characteristic
   1611      * @throws Exception
   1612      */
   1613     @Deprecated
   1614     @Rpc(description = "Set write type of a given characteristic to the associated remote device")
   1615     public boolean gattClientCharacteristicSetWriteType(
   1616             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1617             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1618             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1619             @RpcParameter(name = "characteristicUuid") String characteristicUuid,
   1620             @RpcParameter(name = "writeType") Integer writeType) throws Exception {
   1621         if (mBluetoothGattList.get(gattIndex) == null) {
   1622             throw new Exception("Invalid gattIndex " + gattIndex);
   1623         }
   1624         List<BluetoothGattService> discoveredServiceList =
   1625                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1626         if (discoveredServiceList == null) {
   1627             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1628         }
   1629         BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
   1630         if (gattService == null) {
   1631             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1632         }
   1633         UUID cUuid = UUID.fromString(characteristicUuid);
   1634         BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid);
   1635         if (gattCharacteristic == null) {
   1636             throw new Exception("Invalid characteristic uuid: " + characteristicUuid);
   1637         }
   1638         gattCharacteristic.setWriteType(writeType);
   1639         return true;
   1640     }
   1641 
   1642     /**
   1643      * Set write type to a discovered characteristic.
   1644      *
   1645      * @param gattIndex - the gatt index to use
   1646      * @param discoveredServiceListIndex - the discovered service list index
   1647      * @param serviceIndex - the service index of the discoveredServiceListIndex
   1648      * @param characteristicIndex - the characteristic index
   1649      * @param writeType - the write type for characteristic
   1650      * @return true, if the value was set to the characteristic
   1651      * @throws Exception
   1652      */
   1653     @Rpc(description = "Set write type of a given characteristic to the associated remote device")
   1654     public void gattClientCharacteristicSetWriteTypeByIndex(
   1655             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1656             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1657             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1658             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex,
   1659             @RpcParameter(name = "writeType") Integer writeType)
   1660             throws Exception {
   1661         if (mBluetoothGattList.get(gattIndex) == null) {
   1662             throw new Exception("Invalid gattIndex " + gattIndex);
   1663         }
   1664         List<BluetoothGattService> discoveredServiceList =
   1665                 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1666         if (discoveredServiceList == null) {
   1667             throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex);
   1668         }
   1669         BluetoothGattService gattService = discoveredServiceList.get(serviceIndex);
   1670         if (gattService == null) {
   1671             throw new Exception("Invalid serviceIndex " + serviceIndex);
   1672         }
   1673         List<BluetoothGattCharacteristic> charList = gattService.getCharacteristics();
   1674         if (charList.get(characteristicIndex) == null) {
   1675             throw new Exception("Invalid characteristicIndex: " + characteristicIndex);
   1676         }
   1677         charList.get(characteristicIndex).setWriteType(writeType);
   1678     }
   1679 
   1680     /**
   1681      * Read the RSSI for a connected remote device
   1682      *
   1683      * @param index the bluetooth gatt index
   1684      * @return true, if the RSSI value has been requested successfully
   1685      * @throws Exception
   1686      */
   1687     @Rpc(description = "Read the RSSI for a connected remote device")
   1688     public boolean gattClientReadRSSI(
   1689             @RpcParameter(name = "index") Integer index) throws Exception {
   1690         if (mBluetoothGattList.get(index) != null) {
   1691             return mBluetoothGattList.get(index).readRemoteRssi();
   1692         } else {
   1693             throw new Exception("Invalid index input:" + index);
   1694         }
   1695     }
   1696 
   1697     /**
   1698      * Clears the internal cache and forces a refresh of the services from the remote device
   1699      *
   1700      * @param index the bluetooth gatt index
   1701      * @return Clears the internal cache and forces a refresh of the services from the remote
   1702      *         device.
   1703      * @throws Exception
   1704      */
   1705     @Rpc(description = "Clears the internal cache and forces a refresh of the services from the "
   1706             + "remote device")
   1707     public boolean gattClientRefresh(@RpcParameter(name = "index") Integer index) throws Exception {
   1708         if (mBluetoothGattList.get(index) != null) {
   1709             return mBluetoothGattList.get(index).refresh();
   1710         } else {
   1711             throw new Exception("Invalid index input:" + index);
   1712         }
   1713     }
   1714 
   1715     /**
   1716      * Request a connection parameter update.
   1717      *
   1718      * @param index the bluetooth gatt index
   1719      * @param connectionPriority connection priority
   1720      * @return boolean True if successful False otherwise.
   1721      * @throws Exception
   1722      */
   1723     @Rpc(description = "Request a connection parameter update. from the Bluetooth Gatt")
   1724     public boolean gattClientRequestConnectionPriority(
   1725             @RpcParameter(name = "index") Integer index,
   1726             @RpcParameter(name = "connectionPriority") Integer connectionPriority)
   1727             throws Exception {
   1728         boolean result = false;
   1729         if (mBluetoothGattList.get(index) != null) {
   1730             result = mBluetoothGattList.get(index).requestConnectionPriority(connectionPriority);
   1731         } else {
   1732             throw new Exception("Invalid index input:" + index);
   1733         }
   1734         return result;
   1735     }
   1736 
   1737     /**
   1738      * Sets the characteristic notification of a bluetooth gatt
   1739      *
   1740      * @deprecated Use {@link #gattClientSetCharacteristicNotificationByIndex(
   1741      *  gattIndex, discoveredServiceListIndex, serviceIndex, characteristicIndex, enable)} instead.
   1742      * @param index the bluetooth gatt index
   1743      * @param characteristicIndex the characteristic index
   1744      * @param enable Enable or disable notifications/indications for a given characteristic
   1745      * @return true, if the requested notification status was set successfully
   1746      * @throws Exception
   1747      */
   1748     @Deprecated
   1749     @Rpc(description = "Sets the characteristic notification of a bluetooth gatt")
   1750     public boolean gattClientSetCharacteristicNotification(
   1751             @RpcParameter(name = "gattIndex")
   1752             Integer gattIndex,
   1753             @RpcParameter(name = "discoveredServiceListIndex")
   1754             Integer discoveredServiceListIndex,
   1755             @RpcParameter(name = "serviceIndex")
   1756             Integer serviceIndex,
   1757             @RpcParameter(name = "characteristicUuid")
   1758             String characteristicUuid,
   1759             @RpcParameter(name = "enable")
   1760             Boolean enable
   1761             ) throws Exception {
   1762         if (mBluetoothGattList.get(gattIndex) != null) {
   1763             if(mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex) != null) {
   1764                 List<BluetoothGattService> discoveredServiceList =
   1765                     mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1766                 if (discoveredServiceList.get(serviceIndex) != null) {
   1767                     UUID cUuid = UUID.fromString(characteristicUuid);
   1768                     if (discoveredServiceList.get(serviceIndex).getCharacteristic(cUuid) != null) {
   1769                         return mBluetoothGattList.get(gattIndex).setCharacteristicNotification(
   1770                                 discoveredServiceList.get(serviceIndex).getCharacteristic(cUuid), enable);
   1771                     } else {
   1772                         throw new Exception ("Invalid characteristic uuid: " + characteristicUuid);
   1773                     }
   1774                 } else {
   1775                     throw new Exception ("Invalid serviceIndex " + serviceIndex);
   1776                 }
   1777             } else {
   1778                 throw new Exception("Invalid discoveredServiceListIndex: " + discoveredServiceListIndex);
   1779             }
   1780         } else {
   1781             throw new Exception("Invalid gattIndex input: " + gattIndex);
   1782         }
   1783     }
   1784 
   1785     /**
   1786      * Sets the characteristic notification of a bluetooth gatt
   1787      *
   1788      * @param gattIndex the bluetooth gatt index
   1789      * @param characteristicIndex the characteristic index
   1790      * @param enable Enable or disable notifications/indications for a given characteristic
   1791      * @return true, if the requested notification status was set successfully
   1792      * @throws Exception
   1793      */
   1794     @Rpc(description = "Sets the characteristic notification of a bluetooth gatt")
   1795     public boolean gattClientSetCharacteristicNotificationByIndex(
   1796             @RpcParameter(name = "gattIndex") Integer gattIndex,
   1797             @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex,
   1798             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1799             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex,
   1800             @RpcParameter(name = "enable") Boolean enable)
   1801             throws Exception {
   1802         if (mBluetoothGattList.get(gattIndex) != null) {
   1803             if (mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex) != null) {
   1804                 List<BluetoothGattService> discoveredServiceList =
   1805                         mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex);
   1806                 if (discoveredServiceList.get(serviceIndex) != null) {
   1807                     List<BluetoothGattCharacteristic> charList =
   1808                             discoveredServiceList.get(serviceIndex).getCharacteristics();
   1809                     if (charList.get(characteristicIndex) != null) {
   1810                         return mBluetoothGattList
   1811                                 .get(gattIndex)
   1812                                 .setCharacteristicNotification(charList.get(characteristicIndex),
   1813                                     enable);
   1814                     } else {
   1815                         throw new Exception("Invalid characteristicIndex: " + characteristicIndex);
   1816                     }
   1817                 } else {
   1818                     throw new Exception("Invalid serviceIndex " + serviceIndex);
   1819                 }
   1820             } else {
   1821                 throw new Exception(
   1822                     "Invalid discoveredServiceListIndex: " + discoveredServiceListIndex);
   1823             }
   1824         } else {
   1825             throw new Exception("Invalid gattIndex input: " + gattIndex);
   1826         }
   1827     }
   1828 
   1829     /**
   1830      * Create a new GattCallback object
   1831      *
   1832      * @return the index of the callback object
   1833      */
   1834     @Rpc(description = "Create a new GattCallback object")
   1835     public Integer gattCreateGattCallback() {
   1836         GattCallbackCount += 1;
   1837         int index = GattCallbackCount;
   1838         mGattCallbackList.put(index, new myBluetoothGattCallback(index));
   1839         return index;
   1840     }
   1841 
   1842     /**
   1843      * Returns the list of discovered Bluetooth Gatt Services.
   1844      *
   1845      * @throws Exception
   1846      */
   1847     @Rpc(description = "Get Bluetooth Gatt Services")
   1848     public int gattClientGetDiscoveredServicesCount(@RpcParameter(name = "index") Integer index)
   1849             throws Exception {
   1850         if (mBluetoothGattDiscoveredServicesList.get(index) != null) {
   1851             return mBluetoothGattDiscoveredServicesList.get(index).size();
   1852         } else {
   1853             throw new Exception("Invalid index input:" + index);
   1854         }
   1855     }
   1856 
   1857     /**
   1858      * Returns the discovered Bluetooth Gatt Service Uuid.
   1859      *
   1860      * @throws Exception
   1861      */
   1862     @Rpc(description = "Get Bluetooth Gatt Service Uuid")
   1863     public String gattClientGetDiscoveredServiceUuid(
   1864             @RpcParameter(name = "index") Integer index,
   1865             @RpcParameter(name = "serviceIndex") Integer serviceIndex)
   1866             throws Exception {
   1867         List<BluetoothGattService> mBluetoothServiceList =
   1868                 mBluetoothGattDiscoveredServicesList.get(index);
   1869         if (mBluetoothServiceList != null) {
   1870             return mBluetoothServiceList.get(serviceIndex).getUuid().toString();
   1871         } else {
   1872             throw new Exception("Invalid index input:" + index);
   1873         }
   1874     }
   1875 
   1876     /**
   1877      * Get discovered characteristic uuids from the pheripheral device.
   1878      *
   1879      * @param index the index of the bluetooth gatt discovered services list
   1880      * @param serviceIndex the service to get
   1881      * @return the list of characteristic uuids
   1882      * @throws Exception
   1883      */
   1884     @Rpc(description = "Get Bluetooth Gatt Services")
   1885     public ArrayList<String> gattClientGetDiscoveredCharacteristicUuids(
   1886             @RpcParameter(name = "index") Integer index,
   1887             @RpcParameter(name = "serviceIndex") Integer serviceIndex)
   1888             throws Exception {
   1889         if (mBluetoothGattDiscoveredServicesList.get(index) != null) {
   1890             if (mBluetoothGattDiscoveredServicesList.get(index).get(serviceIndex) != null) {
   1891                 ArrayList<String> uuidList = new ArrayList<String>();
   1892                 List<BluetoothGattCharacteristic> charList =
   1893                         mBluetoothGattDiscoveredServicesList.get(index).get(
   1894                             serviceIndex).getCharacteristics();
   1895                 for (BluetoothGattCharacteristic mChar : charList) {
   1896                     uuidList.add(mChar.getUuid().toString());
   1897                 }
   1898                 return uuidList;
   1899             } else {
   1900                 throw new Exception("Invalid serviceIndex input:" + index);
   1901             }
   1902         } else {
   1903             throw new Exception("Invalid index input:" + index);
   1904         }
   1905     }
   1906 
   1907     /**
   1908      * Get discovered descriptor uuids from the pheripheral device.
   1909      *
   1910      * @deprecated Use {@link #gattClientGetDiscoveredDescriptorUuidsByIndex(
   1911      *  index, serviceIndex, characteristicIndex)} instead.
   1912      * @param index the discovered services list index
   1913      * @param serviceIndex the service index of the discovered services list
   1914      * @param characteristicUuid the characteristicUuid to select from the
   1915      * discovered service which contains the list of descriptors.
   1916      * @return the list of descriptor uuids
   1917      * @throws Exception
   1918      */
   1919     @Deprecated
   1920     @Rpc(description = "Get Bluetooth Gatt Services")
   1921     public ArrayList<String> gattClientGetDiscoveredDescriptorUuids (
   1922             @RpcParameter(name = "index")
   1923             Integer index,
   1924             @RpcParameter(name = "serviceIndex")
   1925             Integer serviceIndex,
   1926             @RpcParameter(name = "characteristicUuid")
   1927             String characteristicUuid
   1928             ) throws Exception {
   1929         if (mBluetoothGattDiscoveredServicesList.get(index) != null) {
   1930             if (mBluetoothGattDiscoveredServicesList.get(index).get(serviceIndex) != null) {
   1931                 BluetoothGattService service = mBluetoothGattDiscoveredServicesList.get(
   1932                         index).get(serviceIndex);
   1933                 UUID cUuid = UUID.fromString(characteristicUuid);
   1934                 if (service.getCharacteristic(cUuid) != null) {
   1935                     ArrayList<String> uuidList = new ArrayList<String>();
   1936                     for (BluetoothGattDescriptor mDesc : service.getCharacteristic(
   1937                             cUuid).getDescriptors()) {
   1938                         uuidList.add(mDesc.getUuid().toString());
   1939                     }
   1940                     return uuidList;
   1941                 } else {
   1942                     throw new Exception("Invalid characeristicUuid : "
   1943                             + characteristicUuid);
   1944                 }
   1945             } else {
   1946                 throw new Exception("Invalid serviceIndex input:"
   1947                         + index);
   1948             }
   1949         } else {
   1950             throw new Exception("Invalid index input:"
   1951                     + index);
   1952         }
   1953     }
   1954 
   1955     /**
   1956      * Get discovered descriptor uuids from the pheripheral device.
   1957      *
   1958      * @param index the discovered services list index
   1959      * @param serviceIndex the service index of the discovered services list
   1960      * @param characteristicIndex the characteristicIndex to select from the discovered service
   1961      *       which contains the list of descriptors.
   1962      * @return the list of descriptor uuids
   1963      * @throws Exception
   1964      */
   1965     @Rpc(description = "Get Bluetooth Gatt Services")
   1966     public ArrayList<String> gattClientGetDiscoveredDescriptorUuidsByIndex(
   1967             @RpcParameter(name = "index") Integer index,
   1968             @RpcParameter(name = "serviceIndex") Integer serviceIndex,
   1969             @RpcParameter(name = "characteristicIndex") Integer characteristicIndex)
   1970             throws Exception {
   1971         if (mBluetoothGattDiscoveredServicesList.get(index) == null) {
   1972             throw new Exception("Invalid index: " + index);
   1973         }
   1974         if (mBluetoothGattDiscoveredServicesList.get(index).get(serviceIndex) == null) {
   1975             throw new Exception("Invalid serviceIndex: " + serviceIndex);
   1976         }
   1977         List<BluetoothGattCharacteristic> charList =
   1978                 mBluetoothGattDiscoveredServicesList.get(index).get(
   1979                     serviceIndex).getCharacteristics();
   1980         if (charList.get(characteristicIndex) == null) {
   1981             throw new Exception("Invalid characteristicIndex: " + characteristicIndex);
   1982         }
   1983         List<BluetoothGattDescriptor> descList = charList.get(characteristicIndex).getDescriptors();
   1984         ArrayList<String> uuidList = new ArrayList<String>();
   1985         for (BluetoothGattDescriptor mDesc : descList) {
   1986             uuidList.add(mDesc.getUuid().toString());
   1987         }
   1988         return uuidList;
   1989     }
   1990 
   1991     private class myBluetoothGattCallback extends BluetoothGattCallback {
   1992         private final Bundle mResults;
   1993         private final int index;
   1994         private final String mEventType;
   1995 
   1996         public myBluetoothGattCallback(int idx) {
   1997             mResults = new Bundle();
   1998             mEventType = "GattConnect";
   1999             index = idx;
   2000         }
   2001 
   2002         @Override
   2003         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
   2004             Log.d("gatt_connect change onConnectionStateChange " + mEventType + " " + index);
   2005             if (newState == BluetoothProfile.STATE_CONNECTED) {
   2006                 Log.d(
   2007                         "State Connected to mac address "
   2008                                 + gatt.getDevice().getAddress()
   2009                                 + " status "
   2010                                 + status);
   2011             } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
   2012                 Log.d(
   2013                         "State Disconnected from mac address "
   2014                                 + gatt.getDevice().getAddress()
   2015                                 + " status "
   2016                                 + status);
   2017             } else if (newState == BluetoothProfile.STATE_CONNECTING) {
   2018                 Log.d(
   2019                         "State Connecting to mac address "
   2020                                 + gatt.getDevice().getAddress()
   2021                                 + " status "
   2022                                 + status);
   2023             } else if (newState == BluetoothProfile.STATE_DISCONNECTING) {
   2024                 Log.d(
   2025                         "State Disconnecting from mac address "
   2026                                 + gatt.getDevice().getAddress()
   2027                                 + " status "
   2028                                 + status);
   2029             }
   2030             mResults.putInt("Status", status);
   2031             mResults.putInt("State", newState);
   2032             mEventFacade.postEvent(
   2033                     mEventType + index + "onConnectionStateChange", mResults.clone());
   2034             mResults.clear();
   2035         }
   2036 
   2037         @Override
   2038         public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
   2039             Log.d("gatt_connect change onPhyRead " + mEventType + " " + index);
   2040             mResults.putInt("TxPhy", txPhy);
   2041             mResults.putInt("RxPhy", rxPhy);
   2042             mResults.putInt("Status", status);
   2043             mEventFacade.postEvent(mEventType + index + "onPhyRead", mResults.clone());
   2044             mResults.clear();
   2045         }
   2046 
   2047         @Override
   2048         public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
   2049             Log.d("gatt_connect change onPhyUpdate " + mEventType + " " + index);
   2050             mResults.putInt("TxPhy", txPhy);
   2051             mResults.putInt("RxPhy", rxPhy);
   2052             mResults.putInt("Status", status);
   2053             mEventFacade.postEvent(mEventType + index + "onPhyUpdate", mResults.clone());
   2054             mResults.clear();
   2055         }
   2056 
   2057         @Override
   2058         public void onServicesDiscovered(BluetoothGatt gatt, int status) {
   2059             Log.d("gatt_connect change onServicesDiscovered " + mEventType + " " + index);
   2060             int idx = BluetoothGattDiscoveredServicesCount++;
   2061             mBluetoothGattDiscoveredServicesList.put(idx, gatt.getServices());
   2062             mResults.putInt("ServicesIndex", idx);
   2063             mResults.putInt("Status", status);
   2064             mEventFacade.postEvent(mEventType + index + "onServicesDiscovered", mResults.clone());
   2065             mResults.clear();
   2066         }
   2067 
   2068         @Override
   2069         public void onCharacteristicRead(
   2070                 BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
   2071             Log.d("gatt_connect change onCharacteristicRead " + mEventType + " " + index);
   2072             mResults.putInt("Status", status);
   2073             mResults.putString("CharacteristicUuid", characteristic.getUuid().toString());
   2074             mResults.putByteArray("CharacteristicValue", characteristic.getValue());
   2075             mEventFacade.postEvent(mEventType + index + "onCharacteristicRead", mResults.clone());
   2076             mResults.clear();
   2077         }
   2078 
   2079         @Override
   2080         public void onCharacteristicWrite(
   2081                 BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
   2082             Log.d("gatt_connect change onCharacteristicWrite " + mEventType + " " + index);
   2083             mResults.putInt("Status", status);
   2084             mResults.putString("CharacteristicUuid", characteristic.getUuid().toString());
   2085             mResults.putByteArray("CharacteristicValue", characteristic.getValue());
   2086             mEventFacade.postEvent(mEventType + index + "onCharacteristicWrite", mResults.clone());
   2087             mResults.clear();
   2088         }
   2089 
   2090         @Override
   2091         public void onCharacteristicChanged(
   2092                 BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
   2093             Log.d("gatt_connect change onCharacteristicChanged " + mEventType + " " + index);
   2094             mResults.putInt("ID", index);
   2095             mResults.putString("CharacteristicUuid", characteristic.getUuid().toString());
   2096             mResults.putByteArray("CharacteristicValue", characteristic.getValue());
   2097             mEventFacade.postEvent(
   2098                     mEventType + index + "onCharacteristicChanged", mResults.clone());
   2099             mResults.clear();
   2100         }
   2101 
   2102         @Override
   2103         public void onDescriptorRead(
   2104                 BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
   2105             Log.d("gatt_connect change onServicesDiscovered " + mEventType + " " + index);
   2106             mResults.putInt("Status", status);
   2107             mResults.putString("DescriptorUuid", descriptor.getUuid().toString());
   2108             mEventFacade.postEvent(mEventType + index + "onDescriptorRead", mResults.clone());
   2109             mResults.clear();
   2110         }
   2111 
   2112         @Override
   2113         public void onDescriptorWrite(
   2114                 BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
   2115             Log.d("gatt_connect change onDescriptorWrite " + mEventType + " " + index);
   2116             mResults.putInt("ID", index);
   2117             mResults.putInt("Status", status);
   2118             mResults.putString("DescriptorUuid", descriptor.getUuid().toString());
   2119             mEventFacade.postEvent(mEventType + index + "onDescriptorWrite", mResults.clone());
   2120             mResults.clear();
   2121         }
   2122 
   2123         @Override
   2124         public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
   2125             Log.d("gatt_connect change onReliableWriteCompleted " + mEventType + " " + index);
   2126             mResults.putInt("Status", status);
   2127             mEventFacade.postEvent(
   2128                     mEventType + index + "onReliableWriteCompleted", mResults.clone());
   2129             mResults.clear();
   2130         }
   2131 
   2132         @Override
   2133         public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
   2134             Log.d("gatt_connect change onReadRemoteRssi " + mEventType + " " + index);
   2135             mResults.putInt("Status", status);
   2136             mResults.putInt("Rssi", rssi);
   2137             mEventFacade.postEvent(mEventType + index + "onReadRemoteRssi", mResults.clone());
   2138             mResults.clear();
   2139         }
   2140 
   2141         @Override
   2142         public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
   2143             Log.d("gatt_connect change onMtuChanged " + mEventType + " " + index);
   2144             mResults.putInt("Status", status);
   2145             mResults.putInt("MTU", mtu);
   2146             mEventFacade.postEvent(mEventType + index + "onMtuChanged", mResults.clone());
   2147             mResults.clear();
   2148         }
   2149 
   2150         public void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency,
   2151                                             int timeout, int status) {
   2152             Log.d("gatt_connect change onConnecitonUpdated " + mEventType + " " + index
   2153                     + ", interval: " + interval + ", latency: " + latency
   2154                     + ", timeout: " + timeout + ", status: " + status);
   2155 
   2156             mResults.putInt("Status", status);
   2157             mResults.putInt("Interval", interval);
   2158             mResults.putInt("Latency", latency);
   2159             mResults.putInt("Timeout", timeout);
   2160             mEventFacade.postEvent(mEventType + index + "onConnectionUpdated", mResults.clone());
   2161             mResults.clear();
   2162         }
   2163     }
   2164 
   2165     @Override
   2166     public void shutdown() {
   2167         if (!mBluetoothGattList.isEmpty()) {
   2168             if (mBluetoothGattList.values() != null) {
   2169                 for (BluetoothGatt mBluetoothGatt : mBluetoothGattList.values()) {
   2170                     mBluetoothGatt.close();
   2171                 }
   2172             }
   2173         }
   2174         mGattCallbackList.clear();
   2175     }
   2176 }
   2177