GattService.java revision ccd5f131d51ef8019c87628b992bc67cbbcc2ea6
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.bluetooth.gatt;
18
19import android.app.Service;
20import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothDevice;
22import android.bluetooth.BluetoothLeAdvertiseScanData.AdvertisementData;
23import android.bluetooth.BluetoothLeAdvertiser;
24import android.bluetooth.BluetoothLeAdvertiser.AdvertiseCallback;
25import android.bluetooth.BluetoothLeScanFilter;
26import android.bluetooth.BluetoothLeScanner.ScanResult;
27import android.bluetooth.BluetoothLeScanner.Settings;
28import android.bluetooth.BluetoothProfile;
29import android.bluetooth.BluetoothUuid;
30import android.bluetooth.IBluetoothGatt;
31import android.bluetooth.IBluetoothGattCallback;
32import android.bluetooth.IBluetoothGattServerCallback;
33import android.content.Intent;
34import android.os.IBinder;
35import android.os.Message;
36import android.os.ParcelUuid;
37import android.os.RemoteException;
38import android.os.SystemClock;
39import android.util.Log;
40
41import com.android.bluetooth.btservice.ProfileService;
42
43import java.nio.ByteBuffer;
44import java.nio.ByteOrder;
45import java.util.ArrayList;
46import java.util.HashMap;
47import java.util.HashSet;
48import java.util.List;
49import java.util.Map;
50import java.util.Objects;
51import java.util.Set;
52import java.util.UUID;
53import java.util.concurrent.TimeUnit;
54
55/**
56 * Provides Bluetooth Gatt profile, as a service in
57 * the Bluetooth application.
58 * @hide
59 */
60public class GattService extends ProfileService {
61    private static final boolean DBG = GattServiceConfig.DBG;
62    private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService";
63    private static final int DEFAULT_SCAN_INTERVAL_MILLIS = 200;
64
65    /**
66     * Max packet size for ble advertising, defined in Bluetooth Specification Version 4.0 [Vol 3].
67     */
68    private static final int ADVERTISING_PACKET_MAX_BYTES = 31;
69    /**
70     * Size overhead for advertising flag.
71     */
72    private static final int ADVERTISING_FLAGS_BYTES = 3;
73    /**
74     * Size overhead per field. Usually it's just one byte of field length and one byte of
75     * field type.
76     */
77    private static final int FIELD_OVERHEAD_BYTES = 2;
78
79    /**
80     * Byte size of 16 bit service uuid.
81     */
82    private static final int SHORT_UUID_BYTES = 2;
83    /**
84     * Byte size of 128 bit service uuid.
85     */
86    private static final int FULL_UUID_BYTES = 16;
87
88    static final int SCAN_FILTER_ENABLED = 1;
89    static final int SCAN_FILTER_MODIFIED = 2;
90
91    /**
92     * Search queue to serialize remote onbject inspection.
93     */
94    SearchQueue mSearchQueue = new SearchQueue();
95
96    /**
97     * List of our registered clients.
98     */
99
100    class ClientMap extends ContextMap<IBluetoothGattCallback> {}
101    ClientMap mClientMap = new ClientMap();
102
103    /**
104     * List of our registered server apps.
105     */
106    class ServerMap extends ContextMap<IBluetoothGattServerCallback> {}
107    ServerMap mServerMap = new ServerMap();
108
109    /**
110     * Server handle map.
111     */
112    HandleMap mHandleMap = new HandleMap();
113    private List<UUID> mAdvertisingServiceUuids = new ArrayList<UUID>();
114
115    private int mAdvertisingClientIf = 0;
116
117    private byte[] mServiceData = new byte[0];
118    private int mManufacturerCode = -1;
119    private byte[] mManufacturerData = new byte[0];
120    private Integer mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STOPPED;
121    private final Object mLock = new Object();
122    private static int lastConfiguredDutyCycle = 0;
123
124    /**
125     * Pending service declaration queue
126     */
127    private List<ServiceDeclaration> mServiceDeclarations = new ArrayList<ServiceDeclaration>();
128
129    private ServiceDeclaration addDeclaration() {
130        synchronized (mServiceDeclarations) {
131            mServiceDeclarations.add(new ServiceDeclaration());
132        }
133        return getActiveDeclaration();
134    }
135
136    private ServiceDeclaration getActiveDeclaration() {
137        synchronized (mServiceDeclarations) {
138            if (mServiceDeclarations.size() > 0)
139                return mServiceDeclarations.get(mServiceDeclarations.size() - 1);
140        }
141        return null;
142    }
143
144    private ServiceDeclaration getPendingDeclaration() {
145        synchronized (mServiceDeclarations) {
146            if (mServiceDeclarations.size() > 0)
147                return mServiceDeclarations.get(0);
148        }
149        return null;
150    }
151
152    private void removePendingDeclaration() {
153        synchronized (mServiceDeclarations) {
154            if (mServiceDeclarations.size() > 0)
155                mServiceDeclarations.remove(0);
156        }
157    }
158
159    /**
160     * List of clients interested in scan results.
161     */
162    private List<ScanClient> mScanQueue = new ArrayList<ScanClient>();
163    private Set<BluetoothLeScanFilter> mScanFilters = new HashSet<BluetoothLeScanFilter>();
164
165    private GattServiceStateMachine mStateMachine;
166    private ScanClient getScanClient(int appIf, boolean isServer) {
167        for(ScanClient client : mScanQueue) {
168            if (client.appIf == appIf && client.isServer == isServer) {
169                return client;
170            }
171        }
172        return null;
173    }
174
175    private void removeScanClient(int appIf, boolean isServer) {
176        for(ScanClient client : mScanQueue) {
177          if (client.appIf == appIf && client.isServer == isServer) {
178                mScanQueue.remove(client);
179                break;
180            }
181        }
182    }
183
184    /**
185     * Reliable write queue
186     */
187    private Set<String> mReliableQueue = new HashSet<String>();
188
189    static {
190        classInitNative();
191    }
192
193    protected String getName() {
194        return TAG;
195    }
196
197    protected IProfileServiceBinder initBinder() {
198        return new BluetoothGattBinder(this);
199    }
200
201    protected boolean start() {
202        if (DBG) Log.d(TAG, "start()");
203        initializeNative();
204        mStateMachine = GattServiceStateMachine.make(this);
205        return true;
206    }
207
208    protected boolean stop() {
209        if (DBG) Log.d(TAG, "stop()");
210        mClientMap.clear();
211        mServerMap.clear();
212        mSearchQueue.clear();
213        mScanQueue.clear();
214        mScanFilters.clear();
215        mHandleMap.clear();
216        mServiceDeclarations.clear();
217        mStateMachine.doQuit();
218        mReliableQueue.clear();
219        return true;
220    }
221
222    protected boolean cleanup() {
223        if (DBG) Log.d(TAG, "cleanup()");
224        cleanupNative();
225        mStateMachine.cleanup();
226        return true;
227    }
228
229    @Override
230    public int onStartCommand(Intent intent, int flags, int startId) {
231        if (GattDebugUtils.handleDebugAction(this, intent)) {
232            return Service.START_NOT_STICKY;
233        }
234        return super.onStartCommand(intent, flags, startId);
235    }
236
237    /**
238     * DeathReceipient handlers used to unregister applications that
239     * disconnect ungracefully (ie. crash or forced close).
240     */
241
242    class ClientDeathRecipient implements IBinder.DeathRecipient {
243        int mAppIf;
244
245        public ClientDeathRecipient(int appIf) {
246            mAppIf = appIf;
247        }
248
249        public void binderDied() {
250            if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
251            if (mAdvertisingClientIf == mAppIf) {
252                stopAdvertising(true);  // force stop advertising.
253            } else {
254                if (getScanClient(mAppIf, false) != null) {
255                    stopScan(mAppIf, false);
256                } else {
257                    stopMultiAdvertising(mAppIf);
258                }
259            }
260            unregisterClient(mAppIf);
261        }
262    }
263
264    class ServerDeathRecipient implements IBinder.DeathRecipient {
265        int mAppIf;
266
267        public ServerDeathRecipient(int appIf) {
268            mAppIf = appIf;
269        }
270
271        public void binderDied() {
272            if (DBG) Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!");
273            unregisterServer(mAppIf);
274        }
275    }
276
277    /**
278     * Handlers for incoming service calls
279     */
280    private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {
281        private GattService mService;
282
283        public BluetoothGattBinder(GattService svc) {
284            mService = svc;
285        }
286
287        public boolean cleanup()  {
288            mService = null;
289            return true;
290        }
291
292        private GattService getService() {
293            if (mService  != null && mService.isAvailable()) return mService;
294            Log.e(TAG, "getService() - Service requested, but not available!");
295            return null;
296        }
297
298        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
299            GattService service = getService();
300            if (service == null) return new ArrayList<BluetoothDevice>();
301            return service.getDevicesMatchingConnectionStates(states);
302        }
303
304        public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
305            GattService service = getService();
306            if (service == null) return;
307            service.registerClient(uuid.getUuid(), callback);
308        }
309
310        public void unregisterClient(int clientIf) {
311            GattService service = getService();
312            if (service == null) return;
313            service.unregisterClient(clientIf);
314        }
315
316        public void startScan(int appIf, boolean isServer) {
317            GattService service = getService();
318            if (service == null) return;
319            service.startScan(appIf, isServer);
320        }
321
322        public void startScanWithUuids(int appIf, boolean isServer, ParcelUuid[] ids) {
323            GattService service = getService();
324            if (service == null) return;
325            UUID[] uuids = new UUID[ids.length];
326            for(int i = 0; i != ids.length; ++i) {
327                uuids[i] = ids[i].getUuid();
328            }
329            service.startScanWithUuids(appIf, isServer, uuids);
330        }
331
332        public void startScanWithUuidsScanParam(int appIf, boolean isServer,
333                ParcelUuid[] ids, int scanWindow, int scanInterval) {
334            GattService service = getService();
335            if (service == null) return;
336            UUID[] uuids = new UUID[ids.length];
337            for(int i = 0; i < ids.length; ++i) {
338                uuids[i] = ids[i].getUuid();
339            }
340            service.startScanWithUuidsScanParam(appIf, isServer, uuids,
341                    scanWindow, scanInterval);
342        }
343
344        @Override
345        public void startScanWithFilters(int appIf, boolean isServer, Settings settings,
346                List<BluetoothLeScanFilter> filters) {
347            GattService service = getService();
348            if (service == null) return;
349            service.startScanWithFilters(appIf, isServer, settings, filters);
350        }
351
352        public void stopScan(int appIf, boolean isServer) {
353            GattService service = getService();
354            if (service == null) return;
355            service.stopScan(appIf, isServer);
356        }
357
358        public void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
359            GattService service = getService();
360            if (service == null) return;
361            service.clientConnect(clientIf, address, isDirect, transport);
362        }
363
364        public void clientDisconnect(int clientIf, String address) {
365            GattService service = getService();
366            if (service == null) return;
367            service.clientDisconnect(clientIf, address);
368        }
369
370        public void refreshDevice(int clientIf, String address) {
371            GattService service = getService();
372            if (service == null) return;
373            service.refreshDevice(clientIf, address);
374        }
375
376        public void discoverServices(int clientIf, String address) {
377            GattService service = getService();
378            if (service == null) return;
379            service.discoverServices(clientIf, address);
380        }
381
382        public void readCharacteristic(int clientIf, String address, int srvcType,
383                                       int srvcInstanceId, ParcelUuid srvcId,
384                                       int charInstanceId, ParcelUuid charId,
385                                       int authReq) {
386            GattService service = getService();
387            if (service == null) return;
388            service.readCharacteristic(clientIf, address, srvcType, srvcInstanceId,
389                                       srvcId.getUuid(), charInstanceId,
390                                       charId.getUuid(), authReq);
391        }
392
393        public void writeCharacteristic(int clientIf, String address, int srvcType,
394                             int srvcInstanceId, ParcelUuid srvcId,
395                             int charInstanceId, ParcelUuid charId,
396                             int writeType, int authReq, byte[] value) {
397            GattService service = getService();
398            if (service == null) return;
399            service.writeCharacteristic(clientIf, address, srvcType, srvcInstanceId,
400                                       srvcId.getUuid(), charInstanceId,
401                                       charId.getUuid(), writeType, authReq,
402                                       value);
403        }
404
405        public void readDescriptor(int clientIf, String address, int srvcType,
406                            int srvcInstanceId, ParcelUuid srvcId,
407                            int charInstanceId, ParcelUuid charId,
408                            int descrInstanceId, ParcelUuid descrId,
409                            int authReq) {
410            GattService service = getService();
411            if (service == null) return;
412            service.readDescriptor(clientIf, address, srvcType,
413                                   srvcInstanceId, srvcId.getUuid(),
414                                   charInstanceId, charId.getUuid(),
415                                   descrInstanceId, descrId.getUuid(),
416                                   authReq);
417        }
418
419        public void writeDescriptor(int clientIf, String address, int srvcType,
420                            int srvcInstanceId, ParcelUuid srvcId,
421                            int charInstanceId, ParcelUuid charId,
422                            int descrInstanceId, ParcelUuid descrId,
423                            int writeType, int authReq, byte[] value) {
424            GattService service = getService();
425            if (service == null) return;
426            service.writeDescriptor(clientIf, address, srvcType,
427                                    srvcInstanceId, srvcId.getUuid(),
428                                    charInstanceId, charId.getUuid(),
429                                    descrInstanceId, descrId.getUuid(),
430                                    writeType, authReq, value);
431        }
432
433        public void beginReliableWrite(int clientIf, String address) {
434            GattService service = getService();
435            if (service == null) return;
436            service.beginReliableWrite(clientIf, address);
437        }
438
439        public void endReliableWrite(int clientIf, String address, boolean execute) {
440            GattService service = getService();
441            if (service == null) return;
442            service.endReliableWrite(clientIf, address, execute);
443        }
444
445        public void registerForNotification(int clientIf, String address, int srvcType,
446                            int srvcInstanceId, ParcelUuid srvcId,
447                            int charInstanceId, ParcelUuid charId,
448                            boolean enable) {
449            GattService service = getService();
450            if (service == null) return;
451            service.registerForNotification(clientIf, address, srvcType, srvcInstanceId,
452                                       srvcId.getUuid(), charInstanceId,
453                                       charId.getUuid(), enable);
454        }
455
456        public void readRemoteRssi(int clientIf, String address) {
457            GattService service = getService();
458            if (service == null) return;
459            service.readRemoteRssi(clientIf, address);
460        }
461
462        public void configureMTU(int clientIf, String address, int mtu) {
463            GattService service = getService();
464            if (service == null) return;
465            service.configureMTU(clientIf, address, mtu);
466        }
467
468        public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback) {
469            GattService service = getService();
470            if (service == null) return;
471            service.registerServer(uuid.getUuid(), callback);
472        }
473
474        public void unregisterServer(int serverIf) {
475            GattService service = getService();
476            if (service == null) return;
477            service.unregisterServer(serverIf);
478        }
479
480        public void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
481            GattService service = getService();
482            if (service == null) return;
483            service.serverConnect(serverIf, address, isDirect, transport);
484        }
485
486        public void serverDisconnect(int serverIf, String address) {
487            GattService service = getService();
488            if (service == null) return;
489            service.serverDisconnect(serverIf, address);
490        }
491
492        public void beginServiceDeclaration(int serverIf, int srvcType,
493                                            int srvcInstanceId, int minHandles,
494                                            ParcelUuid srvcId, boolean advertisePreferred) {
495            GattService service = getService();
496            if (service == null) return;
497            service.beginServiceDeclaration(serverIf, srvcType, srvcInstanceId,
498                               minHandles, srvcId.getUuid(), advertisePreferred);
499        }
500
501        public void addIncludedService(int serverIf, int srvcType,
502                            int srvcInstanceId, ParcelUuid srvcId) {
503            GattService service = getService();
504            if (service == null) return;
505            service.addIncludedService(serverIf, srvcType, srvcInstanceId,
506                                            srvcId.getUuid());
507        }
508
509        public void addCharacteristic(int serverIf, ParcelUuid charId,
510                            int properties, int permissions) {
511            GattService service = getService();
512            if (service == null) return;
513            service.addCharacteristic(serverIf, charId.getUuid(), properties,
514                                      permissions);
515        }
516
517        public void addDescriptor(int serverIf, ParcelUuid descId,
518                           int permissions) {
519            GattService service = getService();
520            if (service == null) return;
521            service.addDescriptor(serverIf, descId.getUuid(), permissions);
522        }
523
524        public void endServiceDeclaration(int serverIf) {
525            GattService service = getService();
526            if (service == null) return;
527            service.endServiceDeclaration(serverIf);
528        }
529
530        public void removeService(int serverIf, int srvcType,
531                           int srvcInstanceId, ParcelUuid srvcId) {
532            GattService service = getService();
533            if (service == null) return;
534            service.removeService(serverIf, srvcType, srvcInstanceId,
535                                  srvcId.getUuid());
536        }
537
538        public void clearServices(int serverIf) {
539            GattService service = getService();
540            if (service == null) return;
541            service.clearServices(serverIf);
542        }
543
544        public void sendResponse(int serverIf, String address, int requestId,
545                                 int status, int offset, byte[] value) {
546            GattService service = getService();
547            if (service == null) return;
548            service.sendResponse(serverIf, address, requestId, status, offset, value);
549        }
550
551        public void sendNotification(int serverIf, String address, int srvcType,
552                                              int srvcInstanceId, ParcelUuid srvcId,
553                                              int charInstanceId, ParcelUuid charId,
554                                              boolean confirm, byte[] value) {
555            GattService service = getService();
556            if (service == null) return;
557            service.sendNotification(serverIf, address, srvcType, srvcInstanceId,
558                srvcId.getUuid(), charInstanceId, charId.getUuid(), confirm, value);
559        }
560
561        @Override
562        public void startAdvertising(int appIf) throws RemoteException {
563            GattService service = getService();
564            if (service == null) return;
565            service.startAdvertising(appIf);
566        }
567
568        @Override
569        public void startMultiAdvertising(int clientIf, AdvertisementData advertiseData,
570                AdvertisementData scanResponse,
571                BluetoothLeAdvertiser.Settings settings) {
572            GattService service = getService();
573            if (service == null) return;
574            service.startMultiAdvertising(clientIf, advertiseData, scanResponse, settings);
575        }
576
577        @Override
578        public void stopMultiAdvertising(int clientIf) {
579            GattService service = getService();
580            if (service == null) return;
581            service.stopMultiAdvertising(clientIf);
582        }
583
584        @Override
585        public boolean isAdvertising() {
586            GattService service = getService();
587            if (service == null) return false;
588            return service.isAdvertising();
589        }
590
591        @Override
592        public void stopAdvertising() throws RemoteException {
593            GattService service = getService();
594            if (service == null) return;
595            service.stopAdvertising();
596        }
597
598        @Override
599        public boolean setAdvServiceData(byte[] serviceData) throws RemoteException {
600            GattService service = getService();
601            if (service == null) return false;
602            return service.setAdvServiceData(serviceData);
603        }
604
605        @Override
606        public byte[] getAdvServiceData() throws RemoteException {
607            GattService service = getService();
608            if (service == null) return null;
609            return service.getAdvServiceData();
610        }
611
612        @Override
613        public boolean setAdvManufacturerCodeAndData(int manufactureCode, byte[] manufacturerData)
614            throws RemoteException {
615            GattService service = getService();
616            if (service == null) return false;
617            return service.setAdvManufacturerCodeAndData(manufactureCode, manufacturerData);
618        }
619
620        @Override
621        public byte[] getAdvManufacturerData() throws RemoteException {
622            GattService service = getService();
623            if (service == null) return null;
624            return service.getAdvManufacturerData();
625        }
626
627        @Override
628        public List<ParcelUuid> getAdvServiceUuids() throws RemoteException {
629            GattService service = getService();
630            if (service == null) return null;
631            return service.getAdvServiceUuids();
632        }
633
634        @Override
635        public void removeAdvManufacturerCodeAndData(int manufacturerCode) throws RemoteException {
636        }
637
638    };
639
640    /**************************************************************************
641     * Callback functions - CLIENT
642     *************************************************************************/
643
644    void onScanResult(String address, int rssi, byte[] adv_data) {
645        if (DBG) Log.d(TAG, "onScanResult() - address=" + address
646                    + ", rssi=" + rssi);
647
648        List<UUID> remoteUuids = parseUuids(adv_data);
649        for (ScanClient client : mScanQueue) {
650            if (client.uuids.length > 0) {
651                int matches = 0;
652                for (UUID search : client.uuids) {
653                    for (UUID remote: remoteUuids) {
654                        if (remote.equals(search)) {
655                            ++matches;
656                            break; // Only count 1st match in case of duplicates
657                        }
658                    }
659                }
660
661                if (matches < client.uuids.length) continue;
662            }
663
664            if (!client.isServer) {
665                ClientMap.App app = mClientMap.getById(client.appIf);
666                if (app != null) {
667                    BluetoothDevice device = BluetoothAdapter.getDefaultAdapter()
668                            .getRemoteDevice(address);
669                    long scanTimeMicros =
670                            TimeUnit.NANOSECONDS.toMicros(SystemClock.elapsedRealtimeNanos());
671                    ScanResult result = new ScanResult(device, adv_data, rssi, scanTimeMicros);
672                    if (matchesFilters(client, result)) {
673                        try {
674                            app.callback.onScanResult(address, rssi, adv_data);
675                        } catch (RemoteException e) {
676                            Log.e(TAG, "Exception: " + e);
677                            mClientMap.remove(client.appIf);
678                            mScanQueue.remove(client);
679                        }
680                    }
681                }
682            } else {
683                ServerMap.App app = mServerMap.getById(client.appIf);
684                if (app != null) {
685                    try {
686                        app.callback.onScanResult(address, rssi, adv_data);
687                    } catch (RemoteException e) {
688                        Log.e(TAG, "Exception: " + e);
689                        mServerMap.remove(client.appIf);
690                        mScanQueue.remove(client);
691                    }
692                }
693            }
694        }
695    }
696
697    // Check if a scan record matches a specific filters.
698    private boolean matchesFilters(ScanClient client, ScanResult scanResult) {
699        if (client.filters == null || client.filters.isEmpty()) {
700            return true;
701        }
702        for (BluetoothLeScanFilter filter : client.filters) {
703            if (filter.matches(scanResult)) {
704                return true;
705            }
706        }
707        return false;
708    }
709
710    void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
711            throws RemoteException {
712        UUID uuid = new UUID(uuidMsb, uuidLsb);
713        if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
714        ClientMap.App app = mClientMap.getByUuid(uuid);
715        if (app != null) {
716            app.id = clientIf;
717            app.linkToDeath(new ClientDeathRecipient(clientIf));
718            app.callback.onClientRegistered(status, clientIf);
719        }
720    }
721
722    void onConnected(int clientIf, int connId, int status, String address)
723            throws RemoteException  {
724        if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf
725            + ", connId=" + connId + ", address=" + address);
726
727        if (status == 0) mClientMap.addConnection(clientIf, connId, address);
728        ClientMap.App app = mClientMap.getById(clientIf);
729        if (app != null) {
730            app.callback.onClientConnectionState(status, clientIf, true, address);
731        }
732    }
733
734    void onDisconnected(int clientIf, int connId, int status, String address)
735            throws RemoteException {
736        if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf
737            + ", connId=" + connId + ", address=" + address);
738
739        mClientMap.removeConnection(clientIf, connId);
740        mSearchQueue.removeConnId(connId);
741        ClientMap.App app = mClientMap.getById(clientIf);
742        if (app != null) {
743            app.callback.onClientConnectionState(status, clientIf, false, address);
744        }
745    }
746
747    void onSearchCompleted(int connId, int status) throws RemoteException {
748        if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status);
749        // We got all services, now let's explore characteristics...
750        continueSearch(connId, status);
751    }
752
753    void onSearchResult(int connId, int srvcType,
754            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb)
755            throws RemoteException {
756        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
757        String address = mClientMap.addressByConnId(connId);
758
759        if (DBG) Log.d(TAG, "onSearchResult() - address=" + address + ", uuid=" + uuid);
760
761        mSearchQueue.add(connId, srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb);
762
763        ClientMap.App app = mClientMap.getByConnId(connId);
764        if (app != null) {
765            app.callback.onGetService(address, srvcType, srvcInstId,
766                                        new ParcelUuid(uuid));
767        }
768    }
769
770    void onGetCharacteristic(int connId, int status, int srvcType,
771            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
772            int charInstId, long charUuidLsb, long charUuidMsb,
773            int charProp) throws RemoteException {
774
775        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
776        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
777        String address = mClientMap.addressByConnId(connId);
778
779        if (DBG) Log.d(TAG, "onGetCharacteristic() - address=" + address
780            + ", status=" + status + ", charUuid=" + charUuid + ", prop=" + charProp);
781
782        if (status == 0) {
783            mSearchQueue.add(connId, srvcType,
784                            srvcInstId, srvcUuidLsb, srvcUuidMsb,
785                            charInstId, charUuidLsb, charUuidMsb);
786
787            ClientMap.App app = mClientMap.getByConnId(connId);
788            if (app != null) {
789                app.callback.onGetCharacteristic(address, srvcType,
790                            srvcInstId, new ParcelUuid(srvcUuid),
791                            charInstId, new ParcelUuid(charUuid), charProp);
792            }
793
794            // Get next characteristic in the current service
795            gattClientGetCharacteristicNative(connId, srvcType,
796                                        srvcInstId, srvcUuidLsb, srvcUuidMsb,
797                                        charInstId, charUuidLsb, charUuidMsb);
798        } else {
799            // Check for included services next
800            gattClientGetIncludedServiceNative(connId,
801                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
802                0,0,0,0);
803        }
804    }
805
806    void onGetDescriptor(int connId, int status, int srvcType,
807            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
808            int charInstId, long charUuidLsb, long charUuidMsb,
809            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
810
811        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
812        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
813        UUID descUuid = new UUID(descrUuidMsb, descrUuidLsb);
814        String address = mClientMap.addressByConnId(connId);
815
816        if (DBG) Log.d(TAG, "onGetDescriptor() - address=" + address
817            + ", status=" + status + ", descUuid=" + descUuid);
818
819        if (status == 0) {
820            ClientMap.App app = mClientMap.getByConnId(connId);
821            if (app != null) {
822                app.callback.onGetDescriptor(address, srvcType,
823                            srvcInstId, new ParcelUuid(srvcUuid),
824                            charInstId, new ParcelUuid(charUuid),
825                            descrInstId, new ParcelUuid(descUuid));
826            }
827
828            // Get next descriptor for the current characteristic
829            gattClientGetDescriptorNative(connId, srvcType,
830                                    srvcInstId, srvcUuidLsb, srvcUuidMsb,
831                                    charInstId, charUuidLsb, charUuidMsb,
832                                    descrInstId, descrUuidLsb, descrUuidMsb);
833        } else {
834            // Explore the next service
835            continueSearch(connId, 0);
836        }
837    }
838
839    void onGetIncludedService(int connId, int status, int srvcType,
840            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, int inclSrvcType,
841            int inclSrvcInstId, long inclSrvcUuidLsb, long inclSrvcUuidMsb)
842            throws RemoteException {
843        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
844        UUID inclSrvcUuid = new UUID(inclSrvcUuidMsb, inclSrvcUuidLsb);
845        String address = mClientMap.addressByConnId(connId);
846
847        if (DBG) Log.d(TAG, "onGetIncludedService() - address=" + address
848            + ", status=" + status + ", uuid=" + srvcUuid
849            + ", inclUuid=" + inclSrvcUuid);
850
851        if (status == 0) {
852            ClientMap.App app = mClientMap.getByConnId(connId);
853            if (app != null) {
854                app.callback.onGetIncludedService(address,
855                    srvcType, srvcInstId, new ParcelUuid(srvcUuid),
856                    inclSrvcType, inclSrvcInstId, new ParcelUuid(inclSrvcUuid));
857            }
858
859            // Find additional included services
860            gattClientGetIncludedServiceNative(connId,
861                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
862                inclSrvcType, inclSrvcInstId, inclSrvcUuidLsb, inclSrvcUuidMsb);
863        } else {
864            // Discover descriptors now
865            continueSearch(connId, 0);
866        }
867    }
868
869    void onRegisterForNotifications(int connId, int status, int registered, int srvcType,
870            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
871            int charInstId, long charUuidLsb, long charUuidMsb) {
872        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
873        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
874        String address = mClientMap.addressByConnId(connId);
875
876        if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address
877            + ", status=" + status + ", registered=" + registered
878            + ", charUuid=" + charUuid);
879    }
880
881    void onNotify(int connId, String address, int srvcType,
882            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
883            int charInstId, long charUuidLsb, long charUuidMsb,
884            boolean isNotify, byte[] data) throws RemoteException {
885        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
886        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
887
888        if (DBG) Log.d(TAG, "onNotify() - address=" + address
889            + ", charUuid=" + charUuid + ", length=" + data.length);
890
891        ClientMap.App app = mClientMap.getByConnId(connId);
892        if (app != null) {
893            app.callback.onNotify(address, srvcType,
894                        srvcInstId, new ParcelUuid(srvcUuid),
895                        charInstId, new ParcelUuid(charUuid),
896                        data);
897        }
898    }
899
900    void onReadCharacteristic(int connId, int status, int srvcType,
901            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
902            int charInstId, long charUuidLsb, long charUuidMsb,
903            int charType, byte[] data) throws RemoteException {
904
905        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
906        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
907        String address = mClientMap.addressByConnId(connId);
908
909        if (DBG) Log.d(TAG, "onReadCharacteristic() - address=" + address
910            + ", status=" + status + ", length=" + data.length);
911
912        ClientMap.App app = mClientMap.getByConnId(connId);
913        if (app != null) {
914            app.callback.onCharacteristicRead(address, status, srvcType,
915                        srvcInstId, new ParcelUuid(srvcUuid),
916                        charInstId, new ParcelUuid(charUuid), data);
917        }
918    }
919
920    void onWriteCharacteristic(int connId, int status, int srvcType,
921            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
922            int charInstId, long charUuidLsb, long charUuidMsb)
923            throws RemoteException {
924
925        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
926        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
927        String address = mClientMap.addressByConnId(connId);
928
929        if (DBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address
930            + ", status=" + status);
931
932        ClientMap.App app = mClientMap.getByConnId(connId);
933        if (app != null) {
934            app.callback.onCharacteristicWrite(address, status, srvcType,
935                        srvcInstId, new ParcelUuid(srvcUuid),
936                        charInstId, new ParcelUuid(charUuid));
937        }
938    }
939
940    void onExecuteCompleted(int connId, int status) throws RemoteException {
941        String address = mClientMap.addressByConnId(connId);
942        if (DBG) Log.d(TAG, "onExecuteCompleted() - address=" + address
943            + ", status=" + status);
944
945        ClientMap.App app = mClientMap.getByConnId(connId);
946        if (app != null) {
947            app.callback.onExecuteWrite(address, status);
948        }
949    }
950
951    void onReadDescriptor(int connId, int status, int srvcType,
952            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
953            int charInstId, long charUuidLsb, long charUuidMsb,
954            int descrInstId, long descrUuidLsb, long descrUuidMsb,
955            int charType, byte[] data) throws RemoteException {
956
957        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
958        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
959        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
960        String address = mClientMap.addressByConnId(connId);
961
962        if (DBG) Log.d(TAG, "onReadDescriptor() - address=" + address
963            + ", status=" + status + ", length=" + data.length);
964
965        ClientMap.App app = mClientMap.getByConnId(connId);
966        if (app != null) {
967            app.callback.onDescriptorRead(address, status, srvcType,
968                        srvcInstId, new ParcelUuid(srvcUuid),
969                        charInstId, new ParcelUuid(charUuid),
970                        descrInstId, new ParcelUuid(descrUuid), data);
971        }
972    }
973
974    void onWriteDescriptor(int connId, int status, int srvcType,
975            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
976            int charInstId, long charUuidLsb, long charUuidMsb,
977            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
978
979        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
980        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
981        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
982        String address = mClientMap.addressByConnId(connId);
983
984        if (DBG) Log.d(TAG, "onWriteDescriptor() - address=" + address
985            + ", status=" + status);
986
987        ClientMap.App app = mClientMap.getByConnId(connId);
988        if (app != null) {
989            app.callback.onDescriptorWrite(address, status, srvcType,
990                        srvcInstId, new ParcelUuid(srvcUuid),
991                        charInstId, new ParcelUuid(charUuid),
992                        descrInstId, new ParcelUuid(descrUuid));
993        }
994    }
995
996    void onReadRemoteRssi(int clientIf, String address,
997                    int rssi, int status) throws RemoteException{
998        if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" +
999                     address + ", rssi=" + rssi + ", status=" + status);
1000
1001        ClientMap.App app = mClientMap.getById(clientIf);
1002        if (app != null) {
1003            app.callback.onReadRemoteRssi(address, rssi, status);
1004        }
1005    }
1006
1007    void onScanFilterConfig(int action, int status) {
1008        log("action = " + action + " status = " + status);
1009        Message message = mStateMachine.obtainMessage();
1010        if (status != 0) {
1011            // If something is wrong with filter configuration, just start scan.
1012            message.what = GattServiceStateMachine.ENABLE_BLE_SCAN;
1013            mStateMachine.sendMessage(message);
1014            return;
1015        }
1016        message.arg1 = action;
1017        if (action == SCAN_FILTER_MODIFIED) {
1018            if (mScanFilters.isEmpty()) {
1019                message.what = GattServiceStateMachine.ENABLE_BLE_SCAN;
1020            } else {
1021                message.what = GattServiceStateMachine.ADD_SCAN_FILTER;
1022            }
1023        } else {
1024            if (action == SCAN_FILTER_ENABLED) {
1025                message.what = GattServiceStateMachine.ENABLE_BLE_SCAN;
1026            }
1027        }
1028        mStateMachine.sendMessage(message);
1029    }
1030
1031    void onAdvertiseCallback(int status, int clientIf) throws RemoteException {
1032        if (DBG) Log.d(TAG, "onClientListen() status=" + status);
1033        synchronized (mLock) {
1034            if (DBG) Log.d(TAG, "state" + mAdvertisingState);
1035            // Invalid advertising state
1036            if (mAdvertisingState == BluetoothAdapter.STATE_ADVERTISE_STARTED ||
1037                    mAdvertisingState == BluetoothAdapter.STATE_ADVERTISE_STOPPED) {
1038                Log.e(TAG, "invalid callback state " + mAdvertisingState);
1039                return;
1040            }
1041
1042            // Force stop advertising, no callback.
1043            if (mAdvertisingState == BluetoothAdapter.STATE_ADVERTISE_FORCE_STOPPING) {
1044                mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STOPPED;
1045                mAdvertisingClientIf = 0;
1046                sendBroadcast(new Intent(
1047                        BluetoothAdapter.ACTION_BLUETOOTH_ADVERTISING_STOPPED));
1048                return;
1049            }
1050
1051            if (mAdvertisingState == BluetoothAdapter.STATE_ADVERTISE_STARTING) {
1052                if (status == 0) {
1053                    mAdvertisingClientIf = clientIf;
1054                    mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STARTED;
1055                    sendBroadcast(new Intent(
1056                            BluetoothAdapter.ACTION_BLUETOOTH_ADVERTISING_STARTED));
1057                } else {
1058                    mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STOPPED;
1059                }
1060            } else if (mAdvertisingState == BluetoothAdapter.STATE_ADVERTISE_STOPPING) {
1061                if (status == 0) {
1062                    mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STOPPED;
1063                    sendBroadcast(new Intent(
1064                            BluetoothAdapter.ACTION_BLUETOOTH_ADVERTISING_STOPPED));
1065                    mAdvertisingClientIf = 0;
1066                } else {
1067                    mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STARTED;
1068                }
1069            }
1070        }
1071        ClientMap.App app = mClientMap.getById(clientIf);
1072        if (app == null || app.callback == null) {
1073            Log.e(TAG, "app or callback is null");
1074            return;
1075        }
1076        app.callback.onAdvertiseStateChange(mAdvertisingState, status);
1077    }
1078
1079    void onMultipleAdvertiseCallback(int clientIf, int status) throws RemoteException {
1080        ClientMap.App app = mClientMap.getById(clientIf);
1081        if (app == null || app.callback == null) {
1082            Log.e(TAG, "app or callback is null");
1083            return;
1084        }
1085        app.callback.onMultiAdvertiseCallback(status);
1086    }
1087
1088    void onConfigureMTU(int connId, int status, int mtu) throws RemoteException {
1089        String address = mClientMap.addressByConnId(connId);
1090
1091        if (DBG) Log.d(TAG, "onConfigureMTU() address=" + address + ", status="
1092            + status + ", mtu=" + mtu);
1093
1094        ClientMap.App app = mClientMap.getByConnId(connId);
1095        if (app != null) {
1096            app.callback.onConfigureMTU(address, mtu, status);
1097        }
1098    }
1099
1100    void onClientEnable(int status, int clientIf) throws RemoteException{
1101        if (DBG) Log.d(TAG, "onClientEnable() - clientIf=" + clientIf + ", status=" + status);
1102        if (status == 0) {
1103            Message message = mStateMachine.obtainMessage(
1104                    GattServiceStateMachine.SET_ADVERTISING_DATA);
1105            message.arg1 = clientIf;
1106            mStateMachine.sendMessage(message);
1107        } else {
1108            Message message =
1109                    mStateMachine.obtainMessage(GattServiceStateMachine.CANCEL_ADVERTISING);
1110            message.arg1 = clientIf;
1111            mStateMachine.sendMessage(message);
1112        }
1113    }
1114
1115    void onClientUpdate(int status, int client_if) throws RemoteException {
1116        if (DBG) Log.d(TAG, "onClientUpdate() - client_if=" + client_if
1117            + ", status=" + status);
1118    }
1119
1120    void onClientData(int status, int clientIf) throws RemoteException{
1121        if (DBG) Log.d(TAG, "onClientData() - clientIf=" + clientIf
1122            + ", status=" + status);
1123
1124        ClientMap.App app = mClientMap.getById(clientIf);
1125        if (app != null) {
1126            if (status == 0) {
1127                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.SUCCESS);
1128            } else {
1129                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.CONTROLLER_FAILURE);
1130            }
1131        }
1132    }
1133
1134    void onClientDisable(int status, int client_if) throws RemoteException{
1135        if (DBG) Log.d(TAG, "onClientDisable() - client_if=" + client_if
1136            + ", status=" + status);
1137
1138        ClientMap.App app = mClientMap.getById(client_if);
1139        if (app != null) {
1140            Log.d(TAG, "Client app is not null!");
1141            if (status == 0) {
1142                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.SUCCESS);
1143            } else {
1144                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.CONTROLLER_FAILURE);
1145            }
1146        }
1147    }
1148
1149    /**************************************************************************
1150     * GATT Service functions - Shared CLIENT/SERVER
1151     *************************************************************************/
1152
1153    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
1154        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1155
1156        final int DEVICE_TYPE_BREDR = 0x1;
1157
1158        Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice,
1159                                                                 Integer>();
1160
1161        // Add paired LE devices
1162
1163        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
1164        for (BluetoothDevice device : bondedDevices) {
1165            if (getDeviceType(device) != DEVICE_TYPE_BREDR) {
1166                deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
1167            }
1168        }
1169
1170        // Add connected deviceStates
1171
1172        Set<String> connectedDevices = new HashSet<String>();
1173        connectedDevices.addAll(mClientMap.getConnectedDevices());
1174        connectedDevices.addAll(mServerMap.getConnectedDevices());
1175
1176        for (String address : connectedDevices ) {
1177            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1178            if (device != null) {
1179                deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
1180            }
1181        }
1182
1183        // Create matching device sub-set
1184
1185        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
1186
1187        for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
1188            for(int state : states) {
1189                if (entry.getValue() == state) {
1190                    deviceList.add(entry.getKey());
1191                }
1192            }
1193        }
1194
1195        return deviceList;
1196    }
1197
1198    void startScan(int appIf, boolean isServer) {
1199        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1200
1201        if (DBG) Log.d(TAG, "startScan() - queue=" + mScanQueue.size());
1202
1203        if (getScanClient(appIf, isServer) == null) {
1204            if (DBG) Log.d(TAG, "startScan() - adding client=" + appIf);
1205            mScanQueue.add(new ScanClient(appIf, isServer));
1206        }
1207        configureScanParams();
1208    }
1209
1210
1211    void startScanWithUuids(int appIf, boolean isServer, UUID[] uuids) {
1212        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1213
1214        if (DBG) Log.d(TAG, "startScanWithUuids() - queue=" + mScanQueue.size());
1215
1216        if (getScanClient(appIf, isServer) == null) {
1217            if (DBG) Log.d(TAG, "startScanWithUuids() - adding client=" + appIf);
1218            mScanQueue.add(new ScanClient(appIf, isServer, uuids));
1219        }
1220        configureScanParams();
1221    }
1222
1223    void startScanWithUuidsScanParam(int appIf, boolean isServer, UUID[] uuids,
1224                int scanWindow, int scanInterval) {
1225        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1226
1227        if (DBG) Log.d(TAG, "startScanWithUuidsScanParam() - queue=" + mScanQueue.size());
1228
1229        if (getScanClient(appIf, isServer) == null) {
1230            if (DBG) Log.d(TAG, "startScanWithUuidsScanParam() - adding client=" + appIf
1231                            + " scanWindow=" + scanWindow + " scanInterval=" + scanInterval);
1232            mScanQueue.add(new ScanClient(appIf, isServer, uuids, scanWindow, scanInterval));
1233        }
1234
1235        configureScanParams();
1236    }
1237
1238    void startScanWithFilters(int appIf, boolean isServer, Settings settings,
1239            List<BluetoothLeScanFilter> filters) {
1240        if (DBG) Log.d(TAG, "start scan with filters " + filters.size());
1241        enforceAdminPermission();
1242        // TODO: use settings to configure scan params.
1243        // TODO: move logic to state machine to avoid locking.
1244        synchronized(mScanQueue) {
1245            if (getScanClient(appIf, isServer) == null) {
1246                if (DBG) Log.d(TAG, "startScan() - adding client=" + appIf);
1247                mScanQueue.add(new ScanClient(appIf, isServer, settings, filters));
1248            }
1249            Set<BluetoothLeScanFilter> newFilters = configureScanFiltersLocked();
1250            if (!Objects.deepEquals(newFilters, mScanFilters)) {
1251                mScanFilters = newFilters;
1252                // Restart scan using new filters.
1253                sendStopScanMessage();
1254                sendStartScanMessage(mScanFilters);
1255            }
1256        }
1257    }
1258
1259    void configureScanParams() {
1260        if (DBG) Log.d(TAG, "configureScanParams() - queue=" + mScanQueue.size());
1261
1262        int scanWindow = 0, scanInterval = 0;
1263        int curDutyCycle = 0;
1264
1265        for(ScanClient client : mScanQueue) {
1266            // Pick the highest duty cycle - most stressful on battery
1267            int newDutyCycle = (client.scanWindow * 100)/client.scanInterval;
1268            if (newDutyCycle > curDutyCycle && newDutyCycle <= 100) {
1269                curDutyCycle = newDutyCycle;
1270                scanWindow = client.scanWindow;
1271                scanInterval = client.scanInterval;
1272            }
1273        }
1274
1275        if (DBG) Log.d(TAG, "configureScanParams() - dutyCyle=" + curDutyCycle +
1276                    " scanWindow=" + scanWindow + " scanInterval=" + scanInterval +
1277                    " lastConfiguredDutyCycle=" + lastConfiguredDutyCycle);
1278
1279        if (curDutyCycle != 0) {
1280            if (curDutyCycle != lastConfiguredDutyCycle) {
1281                // convert scanWindow and scanInterval from ms to LE scan units(0.625ms)
1282                scanWindow = (scanWindow * 1000)/625;
1283                scanInterval = (scanInterval * 1000)/625;
1284                // Presence of scan clients means scan is active.
1285                sendStopScanMessage();
1286                gattSetScanParametersNative(scanInterval, scanWindow);
1287                lastConfiguredDutyCycle = curDutyCycle;
1288                mScanFilters.clear();
1289                sendStartScanMessage(mScanFilters);
1290            } else {
1291                // Duty cycle did not change but scan filters changed.
1292                if (!mScanFilters.isEmpty()) {
1293                    mScanFilters.clear();
1294                    sendStopScanMessage();
1295                    sendStartScanMessage(mScanFilters);
1296                }
1297            }
1298        } else {
1299            lastConfiguredDutyCycle = curDutyCycle;
1300            sendStopScanMessage();
1301            if (DBG) Log.d(TAG, "configureScanParams() - queue emtpy, scan stopped");
1302        }
1303    }
1304
1305    private Set<BluetoothLeScanFilter> configureScanFiltersLocked() {
1306        Set<BluetoothLeScanFilter> filters = new HashSet<BluetoothLeScanFilter>();
1307        for (ScanClient client : mScanQueue) {
1308            if (client.filters == null || client.filters.isEmpty()) {
1309                filters.clear();
1310                return filters;
1311            }
1312            filters.addAll(client.filters);
1313        }
1314        return filters;
1315    }
1316
1317    private void sendStartScanMessage(Set<BluetoothLeScanFilter> filters) {
1318        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.START_BLE_SCAN);
1319        message.obj = filters;
1320        mStateMachine.sendMessage(message);
1321    }
1322
1323    private void sendStopScanMessage() {
1324        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.STOP_BLE_SCAN);
1325        mStateMachine.sendMessage(message);
1326    }
1327
1328    void stopScan(int appIf, boolean isServer) {
1329        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH_ADMIN permission");
1330
1331        if (DBG) Log.d(TAG, "stopScan() - queue=" + mScanQueue.size());
1332        removeScanClient(appIf, isServer);
1333        configureScanParams();
1334
1335        if (mScanQueue.isEmpty()) {
1336            if (DBG) Log.d(TAG, "stopScan() - queue empty; stopping scan");
1337        }
1338    }
1339
1340    /**************************************************************************
1341     * GATT Service functions - CLIENT
1342     *************************************************************************/
1343
1344    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
1345        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1346
1347        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1348        mClientMap.add(uuid, callback);
1349        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1350                                    uuid.getMostSignificantBits());
1351    }
1352
1353    void unregisterClient(int clientIf) {
1354        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1355
1356        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1357        mClientMap.remove(clientIf);
1358        gattClientUnregisterAppNative(clientIf);
1359    }
1360
1361    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1362        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1363
1364        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1365        gattClientConnectNative(clientIf, address, isDirect, transport);
1366    }
1367
1368    void clientDisconnect(int clientIf, String address) {
1369        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1370
1371        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1372        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1373
1374        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1375    }
1376
1377    synchronized boolean setAdvServiceData(byte[] serviceData) {
1378        enforcePrivilegedPermission();
1379        if (serviceData == null) return false;
1380        // Calculate how many more bytes are needed for advertising service data field.
1381        int extraBytes = (mServiceData == null) ?
1382                FIELD_OVERHEAD_BYTES + serviceData.length :
1383                    serviceData.length - mServiceData.length;
1384        if (getAvailableSize() < extraBytes) {
1385            Log.e(TAG, "cannot set service data, available size " + getAvailableSize());
1386            return false;
1387        }
1388        mServiceData = serviceData;
1389        return true;
1390    }
1391
1392    byte[] getAdvServiceData() {
1393        enforcePrivilegedPermission();
1394        return mServiceData;
1395    }
1396
1397    synchronized boolean setAdvManufacturerCodeAndData(
1398        int manufacturerCode, byte[] manufacturerData) {
1399        enforcePrivilegedPermission();
1400        if (manufacturerCode <= 0 || manufacturerData == null) {
1401            return false;
1402        }
1403        if (mManufacturerCode > 0 && mManufacturerData != null) {
1404            Log.e(TAG, "manufacture data is already set");
1405            return false;
1406        }
1407        if (getAvailableSize() <
1408            FIELD_OVERHEAD_BYTES + manufacturerData.length) {
1409            Log.e(TAG, "cannot set manu data, available size " + getAvailableSize());
1410            return false;
1411        }
1412        this.mManufacturerCode = manufacturerCode;
1413        this.mManufacturerData = manufacturerData;
1414        return true;
1415    }
1416
1417    void removeAdvManufacturerCodeAndData(int manufacturerCode) {
1418        enforcePrivilegedPermission();
1419        if (mManufacturerCode != manufacturerCode) {
1420            return;
1421        }
1422        mManufacturerCode = -1;
1423        mManufacturerData = new byte[0];
1424    }
1425
1426    byte[] getAdvManufacturerData() {
1427        enforcePrivilegedPermission();
1428        return mManufacturerData;
1429    }
1430
1431    synchronized List<ParcelUuid> getAdvServiceUuids() {
1432        enforcePrivilegedPermission();;
1433        boolean fullUuidFound = false;
1434        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1435        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1436            if (entry.advertisePreferred) {
1437                ParcelUuid parcelUuid = new ParcelUuid(entry.uuid);
1438                if (BluetoothUuid.is16BitUuid(parcelUuid)) {
1439                    serviceUuids.add(parcelUuid);
1440                } else {
1441                    // Allow at most one 128 bit service uuid to be advertised.
1442                    if (!fullUuidFound) {
1443                      fullUuidFound = true;
1444                      serviceUuids.add(parcelUuid);
1445                    }
1446                }
1447            }
1448        }
1449        return serviceUuids;
1450    }
1451
1452    boolean isAdvertising() {
1453        enforcePrivilegedPermission();
1454        return mAdvertisingState != BluetoothAdapter.STATE_ADVERTISE_STOPPED;
1455    }
1456
1457    void startAdvertising(int clientIf) {
1458        enforcePrivilegedPermission();
1459        if (DBG) Log.d(TAG, "start advertising for app - " + clientIf);
1460        List<ParcelUuid> serviceUuids = getAdvServiceUuids();
1461        int advertisingServiceUuidLength = serviceUuids == null ? 0 : serviceUuids.size();
1462
1463        // Note according to Bluetooth Spec Version 4.0, for advertising and scan response data
1464        // "all numerical multi-byte entities and values shall use little-endian byte order".
1465        ByteBuffer advertisingUuidBytes = ByteBuffer.allocate(advertisingServiceUuidLength * 16)
1466                .order(ByteOrder.LITTLE_ENDIAN);
1467        for (ParcelUuid parcelUuid : serviceUuids) {
1468            UUID uuid = parcelUuid.getUuid();
1469            // Least signifcant bits first as the advertising uuid should be in little-endian.
1470            advertisingUuidBytes.putLong(uuid.getLeastSignificantBits())
1471                    .putLong(uuid.getMostSignificantBits());
1472        }
1473
1474        // Set advertising data.
1475        gattSetAdvDataNative(clientIf,
1476                false,  // not scan response data
1477                false,  // no device name
1478                false,  // no tx power included
1479                DEFAULT_SCAN_INTERVAL_MILLIS,
1480                DEFAULT_SCAN_INTERVAL_MILLIS,
1481                0,  // no appearance limit
1482                mManufacturerData,
1483                mServiceData,
1484                advertisingUuidBytes.array());
1485
1486        // Start advertising if advertising is not already started.
1487        if (!isAdvertising()) {
1488            gattAdvertiseNative(clientIf, true);
1489            mAdvertisingClientIf = clientIf;
1490            mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STARTING;
1491        }
1492    }
1493
1494    void stopAdvertising() {
1495        stopAdvertising(false);
1496    }
1497
1498    void stopAdvertising(boolean forceStop) {
1499        enforcePrivilegedPermission();
1500        gattAdvertiseNative(mAdvertisingClientIf, false);
1501        synchronized (mLock) {
1502            if (forceStop) {
1503                mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_FORCE_STOPPING;
1504            } else {
1505                mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STOPPING;
1506            }
1507        }
1508    }
1509
1510    void startMultiAdvertising(int clientIf, AdvertisementData advertiseData,
1511            AdvertisementData scanResponse, BluetoothLeAdvertiser.Settings settings) {
1512        enforceAdminPermission();
1513        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.START_ADVERTISING);
1514        message.obj = new AdvertiseClient(clientIf, settings, advertiseData, scanResponse);
1515        mStateMachine.sendMessage(message);
1516    }
1517
1518    void stopMultiAdvertising(int clientIf) {
1519        enforceAdminPermission();
1520        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.STOP_ADVERTISING);
1521        message.arg1 = clientIf;
1522        mStateMachine.sendMessage(message);
1523    }
1524
1525    List<String> getConnectedDevices() {
1526        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1527
1528        Set<String> connectedDevAddress = new HashSet<String>();
1529        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1530        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1531        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1532        return connectedDeviceList;
1533    }
1534
1535    void refreshDevice(int clientIf, String address) {
1536        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1537
1538        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1539        gattClientRefreshNative(clientIf, address);
1540    }
1541
1542    void discoverServices(int clientIf, String address) {
1543        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1544
1545        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1546        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1547
1548        if (connId != null)
1549            gattClientSearchServiceNative(connId, true, 0, 0);
1550        else
1551            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1552    }
1553
1554    void readCharacteristic(int clientIf, String address, int srvcType,
1555                            int srvcInstanceId, UUID srvcUuid,
1556                            int charInstanceId, UUID charUuid, int authReq) {
1557        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1558
1559        if (DBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1560
1561        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1562        if (connId != null)
1563            gattClientReadCharacteristicNative(connId, srvcType,
1564                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1565                srvcUuid.getMostSignificantBits(), charInstanceId,
1566                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1567                authReq);
1568        else
1569            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1570    }
1571
1572    void writeCharacteristic(int clientIf, String address, int srvcType,
1573                             int srvcInstanceId, UUID srvcUuid,
1574                             int charInstanceId, UUID charUuid, int writeType,
1575                             int authReq, byte[] value) {
1576        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1577
1578        if (DBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1579
1580        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1581
1582        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1583        if (connId != null)
1584            gattClientWriteCharacteristicNative(connId, srvcType,
1585                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1586                srvcUuid.getMostSignificantBits(), charInstanceId,
1587                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1588                writeType, authReq, value);
1589        else
1590            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1591    }
1592
1593    void readDescriptor(int clientIf, String address, int srvcType,
1594                            int srvcInstanceId, UUID srvcUuid,
1595                            int charInstanceId, UUID charUuid,
1596                            int descrInstanceId, UUID descrUuid,
1597                            int authReq) {
1598        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1599
1600        if (DBG) Log.d(TAG, "readDescriptor() - address=" + address);
1601
1602        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1603        if (connId != null)
1604            gattClientReadDescriptorNative(connId, srvcType,
1605                srvcInstanceId,
1606                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1607                charInstanceId,
1608                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1609                descrInstanceId,
1610                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1611                authReq);
1612        else
1613            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1614    };
1615
1616    void writeDescriptor(int clientIf, String address, int srvcType,
1617                            int srvcInstanceId, UUID srvcUuid,
1618                            int charInstanceId, UUID charUuid,
1619                            int descrInstanceId, UUID descrUuid,
1620                            int writeType, int authReq, byte[] value) {
1621        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1622
1623        if (DBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1624
1625        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1626        if (connId != null)
1627            gattClientWriteDescriptorNative(connId, srvcType,
1628                srvcInstanceId,
1629                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1630                charInstanceId,
1631                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1632                descrInstanceId,
1633                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1634                writeType, authReq, value);
1635        else
1636            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1637    }
1638
1639    void beginReliableWrite(int clientIf, String address) {
1640        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1641
1642        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1643        mReliableQueue.add(address);
1644    }
1645
1646    void endReliableWrite(int clientIf, String address, boolean execute) {
1647        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1648
1649        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1650                                + " execute: " + execute);
1651        mReliableQueue.remove(address);
1652
1653        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1654        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1655    }
1656
1657    void registerForNotification(int clientIf, String address, int srvcType,
1658                int srvcInstanceId, UUID srvcUuid,
1659                int charInstanceId, UUID charUuid,
1660                boolean enable) {
1661        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1662
1663        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1664
1665        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1666        if (connId != null) {
1667            gattClientRegisterForNotificationsNative(clientIf, address,
1668                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1669                srvcUuid.getMostSignificantBits(), charInstanceId,
1670                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1671                enable);
1672        } else {
1673            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1674        }
1675    }
1676
1677    void readRemoteRssi(int clientIf, String address) {
1678        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1679
1680        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1681        gattClientReadRemoteRssiNative(clientIf, address);
1682    }
1683
1684    void configureMTU(int clientIf, String address, int mtu) {
1685        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1686
1687        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1688        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1689        if (connId != null) {
1690            gattClientConfigureMTUNative(connId, mtu);
1691        } else {
1692            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1693        }
1694    }
1695
1696    /**************************************************************************
1697     * Callback functions - SERVER
1698     *************************************************************************/
1699
1700    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1701            throws RemoteException {
1702
1703        UUID uuid = new UUID(uuidMsb, uuidLsb);
1704        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1705        ServerMap.App app = mServerMap.getByUuid(uuid);
1706        if (app != null) {
1707            app.id = serverIf;
1708            app.linkToDeath(new ServerDeathRecipient(serverIf));
1709            app.callback.onServerRegistered(status, serverIf);
1710        }
1711    }
1712
1713    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1714                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1715                        throws RemoteException {
1716        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1717        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1718            + ", handle=" + srvcHandle);
1719        if (status == 0) {
1720            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1721                mAdvertisingServiceUuids.remove(uuid));
1722        }
1723
1724        continueServiceDeclaration(serverIf, status, srvcHandle);
1725    }
1726
1727    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1728                                int includedSrvcHandle) throws RemoteException {
1729        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1730            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1731        continueServiceDeclaration(serverIf, status, srvcHandle);
1732    }
1733
1734    void onCharacteristicAdded(int status, int serverIf,
1735                               long charUuidLsb, long charUuidMsb,
1736                               int srvcHandle, int charHandle)
1737                               throws RemoteException {
1738            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1739        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1740            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1741        if (status == 0)
1742            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1743        continueServiceDeclaration(serverIf, status, srvcHandle);
1744    }
1745
1746    void onDescriptorAdded(int status, int serverIf,
1747                           long descrUuidLsb, long descrUuidMsb,
1748                           int srvcHandle, int descrHandle)
1749                           throws RemoteException {
1750            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1751        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1752            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1753        if (status == 0)
1754            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1755        continueServiceDeclaration(serverIf, status, srvcHandle);
1756    }
1757
1758    void onServiceStarted(int status, int serverIf, int srvcHandle)
1759            throws RemoteException {
1760        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1761            + ", status=" + status);
1762        if (status == 0)
1763            mHandleMap.setStarted(serverIf, srvcHandle, true);
1764    }
1765
1766    void onServiceStopped(int status, int serverIf, int srvcHandle)
1767            throws RemoteException {
1768        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1769            + ", status=" + status);
1770        if (status == 0)
1771            mHandleMap.setStarted(serverIf, srvcHandle, false);
1772        stopNextService(serverIf, status);
1773    }
1774
1775    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1776        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1777            + ", status=" + status);
1778        mHandleMap.deleteService(serverIf, srvcHandle);
1779    }
1780
1781    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1782            throws RemoteException {
1783
1784        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1785            + ", address=" + address + ", connected=" + connected);
1786
1787        ServerMap.App app = mServerMap.getById(serverIf);
1788        if (app == null) return;
1789
1790        if (connected) {
1791            mServerMap.addConnection(serverIf, connId, address);
1792        } else {
1793            mServerMap.removeConnection(serverIf, connId);
1794        }
1795
1796        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1797    }
1798
1799    void onAttributeRead(String address, int connId, int transId,
1800                            int attrHandle, int offset, boolean isLong)
1801                            throws RemoteException {
1802        if (DBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1803            + ", address=" + address + ", handle=" + attrHandle
1804            + ", requestId=" + transId + ", offset=" + offset);
1805
1806        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1807        if (entry == null) return;
1808
1809        if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid
1810            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1811
1812        mHandleMap.addRequest(transId, attrHandle);
1813
1814        ServerMap.App app = mServerMap.getById(entry.serverIf);
1815        if (app == null) return;
1816
1817        switch(entry.type) {
1818            case HandleMap.TYPE_CHARACTERISTIC:
1819            {
1820                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1821                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1822                    serviceEntry.serviceType, serviceEntry.instance,
1823                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1824                    new ParcelUuid(entry.uuid));
1825                break;
1826            }
1827
1828            case HandleMap.TYPE_DESCRIPTOR:
1829            {
1830                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1831                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1832                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1833                    serviceEntry.serviceType, serviceEntry.instance,
1834                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1835                    new ParcelUuid(charEntry.uuid),
1836                    new ParcelUuid(entry.uuid));
1837                break;
1838            }
1839
1840            default:
1841                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1842                break;
1843        }
1844    }
1845
1846    void onAttributeWrite(String address, int connId, int transId,
1847                            int attrHandle, int offset, int length,
1848                            boolean needRsp, boolean isPrep,
1849                            byte[] data)
1850                            throws RemoteException {
1851        if (DBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1852            + ", address=" + address + ", handle=" + attrHandle
1853            + ", requestId=" + transId + ", isPrep=" + isPrep
1854            + ", offset=" + offset);
1855
1856        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1857        if (entry == null) return;
1858
1859        if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid
1860            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1861
1862        mHandleMap.addRequest(transId, attrHandle);
1863
1864        ServerMap.App app = mServerMap.getById(entry.serverIf);
1865        if (app == null) return;
1866
1867        switch(entry.type) {
1868            case HandleMap.TYPE_CHARACTERISTIC:
1869            {
1870                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1871                app.callback.onCharacteristicWriteRequest(address, transId,
1872                            offset, length, isPrep, needRsp,
1873                            serviceEntry.serviceType, serviceEntry.instance,
1874                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1875                            new ParcelUuid(entry.uuid), data);
1876                break;
1877            }
1878
1879            case HandleMap.TYPE_DESCRIPTOR:
1880            {
1881                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1882                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1883                app.callback.onDescriptorWriteRequest(address, transId,
1884                            offset, length, isPrep, needRsp,
1885                            serviceEntry.serviceType, serviceEntry.instance,
1886                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1887                            new ParcelUuid(charEntry.uuid),
1888                            new ParcelUuid(entry.uuid), data);
1889                break;
1890            }
1891
1892            default:
1893                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1894                break;
1895        }
1896    }
1897
1898    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1899            throws RemoteException {
1900        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1901            + ", address=" + address + ", transId=" + transId);
1902
1903        ServerMap.App app = mServerMap.getByConnId(connId);
1904        if (app == null) return;
1905
1906        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1907    }
1908
1909    void onResponseSendCompleted(int status, int attrHandle) {
1910        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1911    }
1912
1913    /**************************************************************************
1914     * GATT Service functions - SERVER
1915     *************************************************************************/
1916
1917    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1918        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1919
1920        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1921        mServerMap.add(uuid, callback);
1922        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1923                                    uuid.getMostSignificantBits());
1924    }
1925
1926    void unregisterServer(int serverIf) {
1927        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1928
1929        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1930
1931        deleteServices(serverIf);
1932
1933        mServerMap.remove(serverIf);
1934        gattServerUnregisterAppNative(serverIf);
1935    }
1936
1937    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1938        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1939
1940        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1941        gattServerConnectNative(serverIf, address, isDirect,transport);
1942    }
1943
1944    void serverDisconnect(int serverIf, String address) {
1945        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1946
1947        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1948        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1949
1950        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1951    }
1952
1953    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1954                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1955        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1956
1957        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1958        ServiceDeclaration serviceDeclaration = addDeclaration();
1959        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1960            advertisePreferred);
1961    }
1962
1963    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1964                            UUID srvcUuid) {
1965        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1966
1967        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1968        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1969    }
1970
1971    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1972                           int permissions) {
1973        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1974
1975        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1976        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1977    }
1978
1979    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1980        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1981
1982        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1983        getActiveDeclaration().addDescriptor(descUuid, permissions);
1984    }
1985
1986    void endServiceDeclaration(int serverIf) {
1987        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1988
1989        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1990
1991        if (getActiveDeclaration() == getPendingDeclaration()) {
1992            try {
1993                continueServiceDeclaration(serverIf, (byte)0, 0);
1994            } catch (RemoteException e) {
1995                Log.e(TAG,""+e);
1996            }
1997        }
1998    }
1999
2000    void removeService(int serverIf, int srvcType,
2001                  int srvcInstanceId, UUID srvcUuid) {
2002        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2003
2004        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
2005
2006        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
2007        if (srvcHandle == 0) return;
2008        gattServerDeleteServiceNative(serverIf, srvcHandle);
2009    }
2010
2011    void clearServices(int serverIf) {
2012        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2013
2014        if (DBG) Log.d(TAG, "clearServices()");
2015        deleteServices(serverIf);
2016    }
2017
2018    void sendResponse(int serverIf, String address, int requestId,
2019                      int status, int offset, byte[] value) {
2020        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2021
2022        if (DBG) Log.d(TAG, "sendResponse() - address=" + address);
2023
2024        int handle = 0;
2025        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
2026        if (entry != null) handle = entry.handle;
2027
2028        int connId = mServerMap.connIdByAddress(serverIf, address);
2029        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
2030                                     handle, offset, value, (byte)0);
2031        mHandleMap.deleteRequest(requestId);
2032    }
2033
2034    void sendNotification(int serverIf, String address, int srvcType,
2035                                 int srvcInstanceId, UUID srvcUuid,
2036                                 int charInstanceId, UUID charUuid,
2037                                 boolean confirm, byte[] value) {
2038        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2039
2040        if (DBG) Log.d(TAG, "sendNotification() - address=" + address);
2041
2042        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
2043        if (srvcHandle == 0) return;
2044
2045        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
2046        if (charHandle == 0) return;
2047
2048        int connId = mServerMap.connIdByAddress(serverIf, address);
2049        if (connId == 0) return;
2050
2051        if (confirm) {
2052            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
2053        } else {
2054            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
2055        }
2056    }
2057
2058
2059    /**************************************************************************
2060     * Private functions
2061     *************************************************************************/
2062
2063    private int getDeviceType(BluetoothDevice device) {
2064        int type = gattClientGetDeviceTypeNative(device.getAddress());
2065        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
2066            + ", type=" + type);
2067        return type;
2068    }
2069
2070    private synchronized int getAvailableSize() {
2071        enforcePrivilegedPermission();
2072        int availableSize = ADVERTISING_PACKET_MAX_BYTES - ADVERTISING_FLAGS_BYTES;
2073
2074        for (ParcelUuid parcelUuid : getAdvServiceUuids()) {
2075            if (BluetoothUuid.is16BitUuid(parcelUuid)) {
2076                availableSize -= FIELD_OVERHEAD_BYTES + SHORT_UUID_BYTES;
2077            } else {
2078                availableSize -= FIELD_OVERHEAD_BYTES + FULL_UUID_BYTES;
2079            }
2080        }
2081        if (mManufacturerCode > 0 && mManufacturerData != null) {
2082            availableSize -= (FIELD_OVERHEAD_BYTES + mManufacturerData.length);
2083        }
2084        if (mServiceData != null) {
2085            availableSize -= (FIELD_OVERHEAD_BYTES + mServiceData.length);
2086        }
2087        return availableSize;
2088    }
2089
2090    private void enforceAdminPermission() {
2091        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
2092    }
2093
2094    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
2095    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
2096    private void enforcePrivilegedPermission() {
2097        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
2098            "Need BLUETOOTH_PRIVILEGED permission");
2099    }
2100
2101    private void continueSearch(int connId, int status) throws RemoteException {
2102        if (status == 0 && !mSearchQueue.isEmpty()) {
2103            SearchQueue.Entry svc = mSearchQueue.pop();
2104
2105            if (svc.charUuidLsb == 0) {
2106                // Characteristic is up next
2107                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
2108                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
2109            } else {
2110                // Descriptor is up next
2111                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
2112                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
2113                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
2114            }
2115        } else {
2116            ClientMap.App app = mClientMap.getByConnId(connId);
2117            if (app != null) {
2118                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
2119            }
2120        }
2121    }
2122
2123    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
2124        if (mServiceDeclarations.size() == 0) return;
2125        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
2126
2127        boolean finished = false;
2128
2129        ServiceDeclaration.Entry entry = null;
2130        if (status == 0)
2131            entry = getPendingDeclaration().getNext();
2132
2133        if (entry != null) {
2134            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
2135                + entry.type);
2136            switch(entry.type) {
2137                case ServiceDeclaration.TYPE_SERVICE:
2138                    if (entry.advertisePreferred) {
2139                        mAdvertisingServiceUuids.add(entry.uuid);
2140                    }
2141                    gattServerAddServiceNative(serverIf, entry.serviceType,
2142                        entry.instance,
2143                        entry.uuid.getLeastSignificantBits(),
2144                        entry.uuid.getMostSignificantBits(),
2145                        getPendingDeclaration().getNumHandles());
2146                    break;
2147
2148                case ServiceDeclaration.TYPE_CHARACTERISTIC:
2149                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
2150                        entry.uuid.getLeastSignificantBits(),
2151                        entry.uuid.getMostSignificantBits(),
2152                        entry.properties, entry.permissions);
2153                    break;
2154
2155                case ServiceDeclaration.TYPE_DESCRIPTOR:
2156                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2157                        entry.uuid.getLeastSignificantBits(),
2158                        entry.uuid.getMostSignificantBits(),
2159                        entry.permissions);
2160                    break;
2161
2162                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2163                {
2164                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2165                                            entry.serviceType, entry.instance);
2166                    if (inclSrvc != 0) {
2167                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2168                                                           inclSrvc);
2169                    } else {
2170                        finished = true;
2171                    }
2172                    break;
2173                }
2174            }
2175        } else {
2176            gattServerStartServiceNative(serverIf, srvcHandle,
2177                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2178            finished = true;
2179        }
2180
2181        if (finished) {
2182            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2183            ServerMap.App app = mServerMap.getById(serverIf);
2184            if (app != null) {
2185                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2186
2187                if (serviceEntry != null) {
2188                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2189                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2190                } else {
2191                    app.callback.onServiceAdded(status, 0, 0, null);
2192                }
2193            }
2194            removePendingDeclaration();
2195
2196            if (getPendingDeclaration() != null) {
2197                continueServiceDeclaration(serverIf, (byte)0, 0);
2198            }
2199        }
2200    }
2201
2202    private void stopNextService(int serverIf, int status) throws RemoteException {
2203        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2204            + ", status=" + status);
2205
2206        if (status == 0) {
2207            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2208            for(HandleMap.Entry entry : entries) {
2209                if (entry.type != HandleMap.TYPE_SERVICE ||
2210                    entry.serverIf != serverIf ||
2211                    entry.started == false)
2212                        continue;
2213
2214                gattServerStopServiceNative(serverIf, entry.handle);
2215                return;
2216            }
2217        }
2218    }
2219
2220    private void deleteServices(int serverIf) {
2221        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2222
2223        /*
2224         * Figure out which handles to delete.
2225         * The handles are copied into a new list to avoid race conditions.
2226         */
2227        List<Integer> handleList = new ArrayList<Integer>();
2228        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2229        for(HandleMap.Entry entry : entries) {
2230            if (entry.type != HandleMap.TYPE_SERVICE ||
2231                entry.serverIf != serverIf)
2232                    continue;
2233            handleList.add(entry.handle);
2234        }
2235
2236        /* Now actually delete the services.... */
2237        for(Integer handle : handleList) {
2238            gattServerDeleteServiceNative(serverIf, handle);
2239        }
2240    }
2241
2242    private List<UUID> parseUuids(byte[] adv_data) {
2243        List<UUID> uuids = new ArrayList<UUID>();
2244
2245        int offset = 0;
2246        while(offset < (adv_data.length-2)) {
2247            int len = adv_data[offset++];
2248            if (len == 0) break;
2249
2250            int type = adv_data[offset++];
2251            switch (type) {
2252                case 0x02: // Partial list of 16-bit UUIDs
2253                case 0x03: // Complete list of 16-bit UUIDs
2254                    while (len > 1) {
2255                        int uuid16 = adv_data[offset++];
2256                        uuid16 += (adv_data[offset++] << 8);
2257                        len -= 2;
2258                        uuids.add(UUID.fromString(String.format(
2259                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2260                    }
2261                    break;
2262
2263                default:
2264                    offset += (len - 1);
2265                    break;
2266            }
2267        }
2268
2269        return uuids;
2270    }
2271
2272    /**************************************************************************
2273     * GATT Test functions
2274     *************************************************************************/
2275
2276    void gattTestCommand(int command, UUID uuid1, String bda1,
2277                         int p1, int p2, int p3, int p4, int p5) {
2278        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2279        if (uuid1 != null)
2280            gattTestNative(command, uuid1.getLeastSignificantBits(),
2281                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2282        else
2283            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2284    }
2285
2286    private native void gattTestNative(int command,
2287                                    long uuid1_lsb, long uuid1_msb, String bda1,
2288                                    int p1, int p2, int p3, int p4, int p5);
2289
2290    /**************************************************************************
2291     * Native functions prototypes
2292     *************************************************************************/
2293
2294    private native static void classInitNative();
2295    private native void initializeNative();
2296    private native void cleanupNative();
2297
2298    private native int gattClientGetDeviceTypeNative(String address);
2299
2300    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2301                                                    long app_uuid_msb);
2302
2303    private native void gattClientUnregisterAppNative(int clientIf);
2304
2305    private native void gattSetScanParametersNative(int scan_interval, int scan_window);
2306
2307    private native void gattClientConnectNative(int clientIf, String address,
2308            boolean isDirect, int transport);
2309
2310    private native void gattClientDisconnectNative(int clientIf, String address,
2311            int conn_id);
2312
2313    private native void gattClientRefreshNative(int clientIf, String address);
2314
2315    private native void gattClientSearchServiceNative(int conn_id,
2316            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2317
2318    private native void gattClientGetCharacteristicNative(int conn_id,
2319            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2320            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2321            long char_id_uuid_msb);
2322
2323    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2324            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2325            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2326            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2327
2328    private native void gattClientGetIncludedServiceNative(int conn_id,
2329            int service_type, int service_id_inst_id,
2330            long service_id_uuid_lsb, long service_id_uuid_msb,
2331            int incl_service_id_inst_id, int incl_service_type,
2332            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2333
2334    private native void gattClientReadCharacteristicNative(int conn_id,
2335            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2336            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2337            long char_id_uuid_msb, int authReq);
2338
2339    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2340            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2341            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2342            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2343            int authReq);
2344
2345    private native void gattClientWriteCharacteristicNative(int conn_id,
2346            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2347            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2348            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2349
2350    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2351            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2352            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2353            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2354            int write_type, int auth_req, byte[] value);
2355
2356    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2357
2358    private native void gattClientRegisterForNotificationsNative(int clientIf,
2359            String address, int service_type, int service_id_inst_id,
2360            long service_id_uuid_lsb, long service_id_uuid_msb,
2361            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2362            boolean enable);
2363
2364    private native void gattClientReadRemoteRssiNative(int clientIf,
2365            String address);
2366
2367    private native void gattAdvertiseNative(int client_if, boolean start);
2368
2369    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2370
2371    private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
2372            boolean inclTxPower, int minInterval, int maxInterval,
2373            int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
2374
2375    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2376                                                    long app_uuid_msb);
2377
2378    private native void gattServerUnregisterAppNative(int serverIf);
2379
2380    private native void gattServerConnectNative(int server_if, String address,
2381                                             boolean is_direct, int transport);
2382
2383    private native void gattServerDisconnectNative(int serverIf, String address,
2384                                              int conn_id);
2385
2386    private native void gattServerAddServiceNative (int server_if,
2387            int service_type, int service_id_inst_id,
2388            long service_id_uuid_lsb, long service_id_uuid_msb,
2389            int num_handles);
2390
2391    private native void gattServerAddIncludedServiceNative (int server_if,
2392            int svc_handle, int included_svc_handle);
2393
2394    private native void gattServerAddCharacteristicNative (int server_if,
2395            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2396            int properties, int permissions);
2397
2398    private native void gattServerAddDescriptorNative (int server_if,
2399            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2400            int permissions);
2401
2402    private native void gattServerStartServiceNative (int server_if,
2403            int svc_handle, int transport );
2404
2405    private native void gattServerStopServiceNative (int server_if,
2406                                                     int svc_handle);
2407
2408    private native void gattServerDeleteServiceNative (int server_if,
2409                                                       int svc_handle);
2410
2411    private native void gattServerSendIndicationNative (int server_if,
2412            int attr_handle, int conn_id, byte[] val);
2413
2414    private native void gattServerSendNotificationNative (int server_if,
2415            int attr_handle, int conn_id, byte[] val);
2416
2417    private native void gattServerSendResponseNative (int server_if,
2418            int conn_id, int trans_id, int status, int handle, int offset,
2419            byte[] val, int auth_req);
2420}
2421