19908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta/*
29908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * Copyright (C) 2013 The Android Open Source Project
39908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta *
49908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * Licensed under the Apache License, Version 2.0 (the "License");
59908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * you may not use this file except in compliance with the License.
69908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * You may obtain a copy of the License at
79908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta *
89908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta *      http://www.apache.org/licenses/LICENSE-2.0
99908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta *
109908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * Unless required by applicable law or agreed to in writing, software
119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * distributed under the License is distributed on an "AS IS" BASIS,
129908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * See the License for the specific language governing permissions and
149908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * limitations under the License.
159908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta */
169908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
179908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battapackage android.bluetooth;
189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
199908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport android.bluetooth.BluetoothAdapter;
209908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport android.bluetooth.BluetoothDevice;
219908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport android.bluetooth.BluetoothProfile;
229908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport android.content.Context;
239908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport android.os.ParcelUuid;
249908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport android.os.RemoteException;
259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport android.util.Log;
269908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
279908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport java.util.ArrayList;
289908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport java.util.List;
299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battaimport java.util.UUID;
309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
319908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta/**
32ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie * Public API for the Bluetooth GATT Profile server role.
339908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta *
34ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie * <p>This class provides Bluetooth GATT server role functionality,
35061cfd0049b1f44af9469a3e6db71b6cbc049413Andre Eisenbach * allowing applications to create Bluetooth Smart services and
36061cfd0049b1f44af9469a3e6db71b6cbc049413Andre Eisenbach * characteristics.
379908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta *
389908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
39061cfd0049b1f44af9469a3e6db71b6cbc049413Andre Eisenbach * via IPC.  Use {@link BluetoothManager#openGattServer} to get an instance
40061cfd0049b1f44af9469a3e6db71b6cbc049413Andre Eisenbach * of this class.
419908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta */
429908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Battapublic final class BluetoothGattServer implements BluetoothProfile {
439908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    private static final String TAG = "BluetoothGattServer";
449908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    private static final boolean DBG = true;
4555d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach    private static final boolean VDBG = false;
469908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
47ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private final Context mContext;
489908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    private BluetoothAdapter mAdapter;
499908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    private IBluetoothGatt mService;
509908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    private BluetoothGattServerCallback mCallback;
519908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
52ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private Object mServerIfLock = new Object();
53ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private int mServerIf;
54b88fa824ab6337684de9aa8437c4952df4f1a75eGanesh Ganapathi Batta    private int mTransport;
559908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    private List<BluetoothGattService> mServices;
569908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
57ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private static final int CALLBACK_REG_TIMEOUT = 10000;
589908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
599908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
609908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * Bluetooth GATT interface callbacks
619908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
629908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    private final IBluetoothGattServerCallback mBluetoothGattServerCallback =
639908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        new IBluetoothGattServerCallback.Stub() {
649908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
659908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Application interface registered - app is ready to go
669908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
679908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
689908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onServerRegistered(int status, int serverIf) {
699908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status
709908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + " serverIf=" + serverIf);
71ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                synchronized(mServerIfLock) {
72ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    if (mCallback != null) {
73ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        mServerIf = serverIf;
74ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        mServerIfLock.notify();
75ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    } else {
76ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        // registration timeout
77ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                        Log.e(TAG, "onServerRegistered: mCallback is null");
78ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                    }
799908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
809908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
819908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
829908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
839908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Callback reporting an LE scan result.
849908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
859908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
869908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onScanResult(String address, int rssi, byte[] advData) {
8755d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach                if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
88ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                // no op
899908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
909908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
919908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
929908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Server connection state changed
939908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
949908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
959908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onServerConnectionState(int status, int serverIf,
969908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                                boolean connected, String address) {
979908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (DBG) Log.d(TAG, "onServerConnectionState() - status=" + status
989908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + " serverIf=" + serverIf + " device=" + address);
999908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                try {
1009908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status,
1019908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                                      connected ? BluetoothProfile.STATE_CONNECTED :
1029908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                                      BluetoothProfile.STATE_DISCONNECTED);
1039908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                } catch (Exception ex) {
1040998ff13498ed004956d1de428eb0c4dcd33c1fbMike Lockwood                    Log.w(TAG, "Unhandled exception in callback", ex);
1059908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
1069908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
1079908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1089908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
1099908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Service has been added
1109908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
1119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
1129908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onServiceAdded(int status, int srvcType,
1139908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                       int srvcInstId, ParcelUuid srvcId) {
1149908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID srvcUuid = srvcId.getUuid();
1159908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (DBG) Log.d(TAG, "onServiceAdded() - service=" + srvcUuid
1169908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "status=" + status);
1179908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
1199908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (service == null) return;
1209908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1219908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                try {
1229908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mCallback.onServiceAdded((int)status, service);
1239908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                } catch (Exception ex) {
1240998ff13498ed004956d1de428eb0c4dcd33c1fbMike Lockwood                    Log.w(TAG, "Unhandled exception in callback", ex);
1259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
1269908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
1279908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1289908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
1299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Remote client characteristic read request.
1309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
1319908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
1329908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onCharacteristicReadRequest(String address, int transId,
1339908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int offset, boolean isLong, int srvcType, int srvcInstId,
1349908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            ParcelUuid srvcId, int charInstId, ParcelUuid charId) {
1359908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID srvcUuid = srvcId.getUuid();
1369908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID charUuid = charId.getUuid();
13755d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach                if (VDBG) Log.d(TAG, "onCharacteristicReadRequest() - "
1389908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "service=" + srvcUuid + ", characteristic=" + charUuid);
1399908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1409908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothDevice device = mAdapter.getRemoteDevice(address);
1419908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
1429908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (service == null) return;
1439908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
144ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
1459908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (characteristic == null) return;
1469908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1479908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                try {
1489908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mCallback.onCharacteristicReadRequest(device, transId, offset, characteristic);
1499908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                } catch (Exception ex) {
1500998ff13498ed004956d1de428eb0c4dcd33c1fbMike Lockwood                    Log.w(TAG, "Unhandled exception in callback", ex);
1519908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
1529908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
1539908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1549908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
1559908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Remote client descriptor read request.
1569908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
1579908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
1589908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onDescriptorReadRequest(String address, int transId,
1599908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int offset, boolean isLong, int srvcType, int srvcInstId,
1609908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            ParcelUuid srvcId, int charInstId, ParcelUuid charId,
1619908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            ParcelUuid descrId) {
1629908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID srvcUuid = srvcId.getUuid();
1639908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID charUuid = charId.getUuid();
1649908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID descrUuid = descrId.getUuid();
16555d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach                if (VDBG) Log.d(TAG, "onCharacteristicReadRequest() - "
1669908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "service=" + srvcUuid + ", characteristic=" + charUuid
1679908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "descriptor=" + descrUuid);
1689908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1699908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothDevice device = mAdapter.getRemoteDevice(address);
1709908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
1719908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (service == null) return;
1729908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1739908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
1749908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (characteristic == null) return;
1759908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1769908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid);
1779908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (descriptor == null) return;
1789908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1799908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                try {
1809908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mCallback.onDescriptorReadRequest(device, transId, offset, descriptor);
1819908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                } catch (Exception ex) {
1820998ff13498ed004956d1de428eb0c4dcd33c1fbMike Lockwood                    Log.w(TAG, "Unhandled exception in callback", ex);
1839908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
1849908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
1859908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1869908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
1879908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Remote client characteristic write request.
1889908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
1899908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
1909908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onCharacteristicWriteRequest(String address, int transId,
1919908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int offset, int length, boolean isPrep, boolean needRsp,
1929908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int srvcType, int srvcInstId, ParcelUuid srvcId,
1939908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int charInstId, ParcelUuid charId, byte[] value) {
1949908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID srvcUuid = srvcId.getUuid();
1959908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID charUuid = charId.getUuid();
19655d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach                if (VDBG) Log.d(TAG, "onCharacteristicWriteRequest() - "
1979908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "service=" + srvcUuid + ", characteristic=" + charUuid);
1989908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
1999908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothDevice device = mAdapter.getRemoteDevice(address);
2009908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
2019908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (service == null) return;
2029908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2039908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
2049908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (characteristic == null) return;
2059908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2069908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                try {
2079908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mCallback.onCharacteristicWriteRequest(device, transId, characteristic,
2089908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                                           isPrep, needRsp, offset, value);
2099908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                } catch (Exception ex) {
2100998ff13498ed004956d1de428eb0c4dcd33c1fbMike Lockwood                    Log.w(TAG, "Unhandled exception in callback", ex);
2119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
2129908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2139908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
2149908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2159908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
2169908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Remote client descriptor write request.
2179908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
2189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
2199908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onDescriptorWriteRequest(String address, int transId,
2209908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int offset, int length, boolean isPrep, boolean needRsp,
2219908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int srvcType, int srvcInstId, ParcelUuid srvcId,
2229908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            int charInstId, ParcelUuid charId, ParcelUuid descrId,
2239908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                            byte[] value) {
2249908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID srvcUuid = srvcId.getUuid();
2259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID charUuid = charId.getUuid();
2269908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                UUID descrUuid = descrId.getUuid();
22755d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach                if (VDBG) Log.d(TAG, "onDescriptorWriteRequest() - "
2289908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "service=" + srvcUuid + ", characteristic=" + charUuid
2299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "descriptor=" + descrUuid);
2309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2319908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothDevice device = mAdapter.getRemoteDevice(address);
2329908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2339908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
2349908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (service == null) return;
2359908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2369908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
2379908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (characteristic == null) return;
2389908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2399908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid);
2409908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (descriptor == null) return;
2419908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2429908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                try {
2439908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mCallback.onDescriptorWriteRequest(device, transId, descriptor,
2449908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                                       isPrep, needRsp, offset, value);
2459908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                } catch (Exception ex) {
2460998ff13498ed004956d1de428eb0c4dcd33c1fbMike Lockwood                    Log.w(TAG, "Unhandled exception in callback", ex);
2479908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
2489908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
2499908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2509908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            /**
2519908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * Execute pending writes.
2529908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             * @hide
2539908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta             */
2549908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            public void onExecuteWrite(String address, int transId,
2559908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                       boolean execWrite) {
2569908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (DBG) Log.d(TAG, "onExecuteWrite() - "
2579908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "device=" + address + ", transId=" + transId
2589908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    + "execWrite=" + execWrite);
2599908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2609908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                BluetoothDevice device = mAdapter.getRemoteDevice(address);
2619908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                if (device == null) return;
2629908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
2639908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                try {
2649908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mCallback.onExecuteWrite(device, transId, execWrite);
2659908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                } catch (Exception ex) {
2660998ff13498ed004956d1de428eb0c4dcd33c1fbMike Lockwood                    Log.w(TAG, "Unhandled exception in callback", ex);
2679908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
2689908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
269dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach
270dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach            /**
271dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach             * A notification/indication has been sent.
272dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach             * @hide
273dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach             */
274dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach            public void onNotificationSent(String address, int status) {
27555d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach                if (VDBG) Log.d(TAG, "onNotificationSent() - "
276dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                    + "device=" + address + ", status=" + status);
277dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach
278dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                BluetoothDevice device = mAdapter.getRemoteDevice(address);
279dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                if (device == null) return;
280dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach
281dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                try {
282dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                    mCallback.onNotificationSent(device, status);
283dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                } catch (Exception ex) {
284dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                    Log.w(TAG, "Unhandled exception: " + ex);
285dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach                }
286dadefdad8ef424991feb45f02f923a2f8224285bAndre Eisenbach            }
28716bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach
28816bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach            /**
28916bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach             * The MTU for a connection has changed
29016bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach             * @hide
29116bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach             */
29216bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach            public void onMtuChanged(String address, int mtu) {
29316bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                if (DBG) Log.d(TAG, "onMtuChanged() - "
29416bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                    + "device=" + address + ", mtu=" + mtu);
29516bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach
29616bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                BluetoothDevice device = mAdapter.getRemoteDevice(address);
29716bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                if (device == null) return;
29816bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach
29916bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                try {
30016bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                    mCallback.onMtuChanged(device, mtu);
30116bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                } catch (Exception ex) {
30216bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                    Log.w(TAG, "Unhandled exception: " + ex);
30316bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach                }
30416bf846990293e1f19f042eed8e2ce5e7348ac5aAndre Eisenbach            }
3059908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        };
3069908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
3079908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
3089908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * Create a BluetoothGattServer proxy object.
3099908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
310b88fa824ab6337684de9aa8437c4952df4f1a75eGanesh Ganapathi Batta    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
3119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        mContext = context;
312ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        mService = iGatt;
3139908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        mAdapter = BluetoothAdapter.getDefaultAdapter();
314ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        mCallback = null;
315ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        mServerIf = 0;
316b88fa824ab6337684de9aa8437c4952df4f1a75eGanesh Ganapathi Batta        mTransport = transport;
3179908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        mServices = new ArrayList<BluetoothGattService>();
3189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
3199908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
3209908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
3213b64f38a167dd755977b01a339cb7724e05efbeaAndre Eisenbach     * Close this GATT server instance.
322b30f91e38c19f6728d836293446d4b9c76705e7fMatthew Xie     *
323b30f91e38c19f6728d836293446d4b9c76705e7fMatthew Xie     * Application should call this method as early as possible after it is done with
324b30f91e38c19f6728d836293446d4b9c76705e7fMatthew Xie     * this GATT server.
3259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
3263b64f38a167dd755977b01a339cb7724e05efbeaAndre Eisenbach    public void close() {
3279908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (DBG) Log.d(TAG, "close()");
328ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        unregisterCallback();
3299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
3309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
3319908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
332ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Register an application callback to start using GattServer.
3339908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
3349908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>This is an asynchronous call. The callback is used to notify
3359908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * success or failure if the function returns true.
3369908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
3379908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3389908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
339ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @param callback GATT callback handler that will receive asynchronous
340ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     *                 callbacks.
341ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @return true, the callback will be called to notify success or failure,
342ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     *         false on immediate error
3439908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
344ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
345ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        if (DBG) Log.d(TAG, "registerCallback()");
346ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        if (mService == null) {
347ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            Log.e(TAG, "GATT service not available");
3489908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            return false;
3499908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
350ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        UUID uuid = UUID.randomUUID();
351ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
3529908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
353ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        synchronized(mServerIfLock) {
354ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            if (mCallback != null) {
355ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                Log.e(TAG, "App can register callback only once");
356ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                return false;
357ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            }
358ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
359ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            mCallback = callback;
360ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            try {
361ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
362ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            } catch (RemoteException e) {
363ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                Log.e(TAG,"",e);
364ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                mCallback = null;
365ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                return false;
366ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            }
367ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
368ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            try {
369ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                mServerIfLock.wait(CALLBACK_REG_TIMEOUT);
370ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            } catch (InterruptedException e) {
371ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                Log.e(TAG, "" + e);
372ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                mCallback = null;
373ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            }
374ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
375ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            if (mServerIf == 0) {
376ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                mCallback = null;
377ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                return false;
378ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            } else {
379ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                return true;
380ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            }
381ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        }
3829908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
3839908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
3849908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
3859908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * Unregister the current application and callbacks.
3869908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
387ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    private void unregisterCallback() {
388ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
3899908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return;
3909908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
3919908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
3929908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mCallback = null;
3939908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.unregisterServer(mServerIf);
3949908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mServerIf = 0;
3959908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
3969908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
3979908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
3989908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
3999908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4009908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
401ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Returns a service by UUID, instance and type.
402ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @hide
4039908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
404ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie    /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) {
405ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        for(BluetoothGattService svc : mServices) {
406ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            if (svc.getType() == type &&
407ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                svc.getInstanceId() == instanceId &&
408ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                svc.getUuid().equals(uuid)) {
409ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie                return svc;
4109908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
4119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
412ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        return null;
4139908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
4149908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4159908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
416ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Initiate a connection to a Bluetooth GATT capable device.
4179908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>The connection may not be established right away, but will be
4199908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * completed when the remote device is available. A
4203f36660a60ce065b71f6d5eb24911012b6d66fddAndre Eisenbach     * {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
4219908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * invoked when the connection state changes as a result of this function.
4229908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4239908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>The autoConnect paramter determines whether to actively connect to
4249908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * the remote device, or rather passively scan and finalize the connection
4259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * when the remote device is in range/available. Generally, the first ever
4269908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * connection to a device should be direct (autoConnect set to false) and
4279908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * subsequent connections to known devices should be invoked with the
428ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * autoConnect parameter set to true.
4299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
4319908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4329908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param autoConnect Whether to directly connect to the remote device (false)
4339908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *                    or to automatically connect as soon as the remote
4349908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *                    device becomes available (true).
4359908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @return true, if the connection attempt was initiated successfully
4369908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
4379908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public boolean connect(BluetoothDevice device, boolean autoConnect) {
4383f36660a60ce065b71f6d5eb24911012b6d66fddAndre Eisenbach        if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect);
4399908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return false;
4409908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4419908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
4429908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.serverConnect(mServerIf, device.getAddress(),
443b88fa824ab6337684de9aa8437c4952df4f1a75eGanesh Ganapathi Batta                               autoConnect ? false : true,mTransport); // autoConnect is inverse of "isDirect"
4449908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
4459908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
4469908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            return false;
4479908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
4489908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4499908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        return true;
4509908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
4519908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4529908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
4539908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * Disconnects an established connection, or cancels a connection attempt
4549908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * currently in progress.
4559908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4569908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
4579908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4589908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param device Remote device
4599908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
4609908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public void cancelConnection(BluetoothDevice device) {
4619908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress());
4629908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return;
4639908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4649908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
4659908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.serverDisconnect(mServerIf, device.getAddress());
4669908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
4679908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
4689908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
4699908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
4709908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4719908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
4729908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * Send a response to a read or write request to a remote device.
4739908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4749908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>This function must be invoked in when a remote read/write request
475ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * is received by one of these callback methods:
4769908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4779908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <ul>
4789908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *      <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest}
4799908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *      <li>{@link BluetoothGattServerCallback#onCharacteristicWriteRequest}
4809908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *      <li>{@link BluetoothGattServerCallback#onDescriptorReadRequest}
4819908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *      <li>{@link BluetoothGattServerCallback#onDescriptorWriteRequest}
4829908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * </ul>
4839908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4849908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
4859908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
4869908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param device The remote device to send this response to
4879908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param requestId The ID of the request that was received with the callback
4889908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param status The status of the request to be sent to the remote devices
4899908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param offset Value offset for partial read/write response
4909908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param value The value of the attribute that was read/written (optional)
4919908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
4929908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public boolean sendResponse(BluetoothDevice device, int requestId,
4939908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                int status, int offset, byte[] value) {
49455d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach        if (VDBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress());
4959908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return false;
4969908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
4979908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
4989908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.sendResponse(mServerIf, device.getAddress(), requestId,
4999908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                  status, offset, value);
5009908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
5019908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
5029908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            return false;
5039908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
5049908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        return true;
5059908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
5069908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5079908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
5089908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * Send a notification or indication that a local characteristic has been
5099908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * updated.
5109908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
5119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>A notification or indication is sent to the remote device to signal
5129908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * that the characteristic has been updated. This function should be invoked
5139908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * for every client that requests notifications/indications by writing
5149908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * to the "Client Configuration" descriptor for the given characteristic.
5159908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
5169908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
5179908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
5189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param device The remote device to receive the notification/indication
5199908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param characteristic The local characteristic that has been updated
5209908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param confirm true to request confirmation from the client (indication),
5219908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *                false to send a notification
522ee3cc8bf177c03ea571a87a73d9ada83201afa63Prerepa Viswanadham     * @throws IllegalArgumentException
5239908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @return true, if the notification has been triggered successfully
5249908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
5259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public boolean notifyCharacteristicChanged(BluetoothDevice device,
5269908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    BluetoothGattCharacteristic characteristic, boolean confirm) {
52755d19e495e2b3cd744724f2d12c399217e3c565cAndre Eisenbach        if (VDBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
5289908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return false;
5299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        BluetoothGattService service = characteristic.getService();
5319908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (service == null) return false;
5329908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
533ee3cc8bf177c03ea571a87a73d9ada83201afa63Prerepa Viswanadham        if (characteristic.getValue() == null) {
534ee3cc8bf177c03ea571a87a73d9ada83201afa63Prerepa Viswanadham            throw new IllegalArgumentException("Chracteristic value is empty. Use "
535ee3cc8bf177c03ea571a87a73d9ada83201afa63Prerepa Viswanadham                    + "BluetoothGattCharacteristic#setvalue to update");
536ee3cc8bf177c03ea571a87a73d9ada83201afa63Prerepa Viswanadham        }
537ee3cc8bf177c03ea571a87a73d9ada83201afa63Prerepa Viswanadham
5389908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
5399908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.sendNotification(mServerIf, device.getAddress(),
5409908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    service.getType(), service.getInstanceId(),
5419908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
5429908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    new ParcelUuid(characteristic.getUuid()), confirm,
5439908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    characteristic.getValue());
5449908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
5459908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
5469908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            return false;
5479908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
5489908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5499908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        return true;
5509908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
5519908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5529908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
553ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Add a service to the list of services to be hosted.
5549908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
555061cfd0049b1f44af9469a3e6db71b6cbc049413Andre Eisenbach     * <p>Once a service has been addded to the the list, the service and its
556ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * included characteristics will be provided by the local device.
5579908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
558ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * <p>If the local device has already exposed services when this function
5599908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * is called, a service update notification will be sent to all clients.
5609908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
5619908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
5629908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
563ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @param service Service to be added to the list of services provided
5649908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *                by this device.
5659908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @return true, if the service has been added successfully
5669908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
5679908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public boolean addService(BluetoothGattService service) {
5689908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid());
5699908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return false;
5709908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5719908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        mServices.add(service);
5729908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5739908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
5749908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.beginServiceDeclaration(mServerIf, service.getType(),
5759908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                service.getInstanceId(), service.getHandles(),
57618c76934f62410d1499e2eb63635b5dd8da5013aWei Wang                new ParcelUuid(service.getUuid()), service.isAdvertisePreferred());
5779908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5789908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            List<BluetoothGattService> includedServices = service.getIncludedServices();
5799908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            for (BluetoothGattService includedService : includedServices) {
5809908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                mService.addIncludedService(mServerIf,
5819908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    includedService.getType(),
5829908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    includedService.getInstanceId(),
5839908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    new ParcelUuid(includedService.getUuid()));
5849908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
5859908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5869908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
5879908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            for (BluetoothGattCharacteristic characteristic : characteristics) {
5889908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                int permission = ((characteristic.getKeySize() - 7) << 12)
5899908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                    + characteristic.getPermissions();
5909908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                mService.addCharacteristic(mServerIf,
5919908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    new ParcelUuid(characteristic.getUuid()),
5929908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    characteristic.getProperties(), permission);
5939908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
5949908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
5959908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                for (BluetoothGattDescriptor descriptor: descriptors) {
5966f0ed128e46d723c82a2be1d5a45beaf302a2cb1Andre Eisenbach                    permission = ((characteristic.getKeySize() - 7) << 12)
5976f0ed128e46d723c82a2be1d5a45beaf302a2cb1Andre Eisenbach                                        + descriptor.getPermissions();
5989908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                    mService.addDescriptor(mServerIf,
5996f0ed128e46d723c82a2be1d5a45beaf302a2cb1Andre Eisenbach                        new ParcelUuid(descriptor.getUuid()), permission);
6009908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                }
6019908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
6029908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6039908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.endServiceDeclaration(mServerIf);
6049908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
6059908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
6069908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            return false;
6079908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
6089908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6099908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        return true;
6109908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
6119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6129908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
613ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Removes a service from the list of services to be provided.
6149908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
6159908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
6169908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
617ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @param service Service to be removed.
6189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @return true, if the service has been removed
6199908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
6209908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public boolean removeService(BluetoothGattService service) {
6219908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid());
6229908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return false;
6239908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6249908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        BluetoothGattService intService = getService(service.getUuid(),
6259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                                service.getInstanceId(), service.getType());
6269908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (intService == null) return false;
6279908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6289908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
6299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.removeService(mServerIf, service.getType(),
6309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                service.getInstanceId(), new ParcelUuid(service.getUuid()));
6319908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mServices.remove(intService);
6329908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
6339908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
6349908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            return false;
6359908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
6369908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6379908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        return true;
6389908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
6399908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6409908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
641ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Remove all services from the list of provided services.
6429908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
6439908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
6449908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public void clearServices() {
6459908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (DBG) Log.d(TAG, "clearServices()");
6469908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        if (mService == null || mServerIf == 0) return;
6479908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6489908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        try {
6499908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mService.clearServices(mServerIf);
6509908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            mServices.clear();
6519908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        } catch (RemoteException e) {
6529908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            Log.e(TAG,"",e);
6539908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
6549908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
6559908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6569908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
657ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Returns a list of GATT services offered by this device.
6589908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
6599908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>An application must call {@link #addService} to add a serice to the
6609908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * list of services offered by this device.
6619908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
6629908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
6639908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
6649908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @return List of services. Returns an empty list
6659908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *         if no services have been added yet.
6669908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
6679908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public List<BluetoothGattService> getServices() {
6689908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        return mServices;
6699908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
6709908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6719908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
6729908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * Returns a {@link BluetoothGattService} from the list of services offered
6739908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * by this device.
6749908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
6759908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>If multiple instances of the same service (as identified by UUID)
6769908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * exist, the first instance of the service is returned.
6779908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
6789908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
6799908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
6809908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @param uuid UUID of the requested service
6819908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     * @return BluetoothGattService if supported, or null if the requested
6829908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *         service is not offered by this device.
6839908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
6849908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public BluetoothGattService getService(UUID uuid) {
6859908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        for (BluetoothGattService service : mServices) {
6869908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            if (service.getUuid().equals(uuid)) {
6879908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta                return service;
6889908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta            }
6899908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        }
6909908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
6919908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta        return null;
6929908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
6939908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
694ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie
6959908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
696ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
697ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * with {@link BluetoothProfile#GATT} as argument
6989908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
699ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @throws UnsupportedOperationException
7009908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
7019908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    @Override
7029908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public int getConnectionState(BluetoothDevice device) {
703ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
7049908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
7059908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
7069908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
707ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
708ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * with {@link BluetoothProfile#GATT} as argument
7099908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
710ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @throws UnsupportedOperationException
7119908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
7129908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    @Override
7139908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public List<BluetoothDevice> getConnectedDevices() {
714ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        throw new UnsupportedOperationException
715ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            ("Use BluetoothManager#getConnectedDevices instead.");
7169908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
7179908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta
7189908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    /**
719ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * Not supported - please use
720ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
721ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * with {@link BluetoothProfile#GATT} as first argument
7229908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     *
723ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie     * @throws UnsupportedOperationException
7249908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta     */
7259908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    @Override
7269908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
727ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie        throw new UnsupportedOperationException
728ddf7e4756c31d0ed90802f98abeaa79df6d16b2aMatthew Xie            ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
7299908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta    }
7309908112fd085d8b0d91e0562d32eebd1884f09a5Ganesh Ganapathi Batta}
731