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.BluetoothProfile;
23import android.bluetooth.IBluetoothGatt;
24import android.bluetooth.IBluetoothGattCallback;
25import android.bluetooth.IBluetoothGattServerCallback;
26import android.content.Intent;
27import android.os.IBinder;
28import android.os.IBinder.DeathRecipient;
29import android.os.ParcelUuid;
30import android.os.RemoteException;
31import android.util.Log;
32
33import java.util.ArrayList;
34import java.util.HashMap;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Map;
39import java.util.Set;
40import java.util.UUID;
41
42import com.android.bluetooth.btservice.ProfileService;
43import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder;
44
45/**
46 * Provides Bluetooth Gatt profile, as a service in
47 * the Bluetooth application.
48 * @hide
49 */
50public class GattService extends ProfileService {
51    private static final boolean DBG = GattServiceConfig.DBG;
52    private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService";
53    BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
54
55    /**
56     * Search queue to serialize remote onbject inspection.
57     */
58    SearchQueue mSearchQueue = new SearchQueue();
59
60    /**
61     * List of our registered clients.
62     */
63
64    class ClientMap extends ContextMap<IBluetoothGattCallback> {}
65    ClientMap mClientMap = new ClientMap();
66
67    /**
68     * List of our registered server apps.
69     */
70    class ServerMap extends ContextMap<IBluetoothGattServerCallback> {}
71    ServerMap mServerMap = new ServerMap();
72
73    /**
74     * Server handle map.
75     */
76    HandleMap mHandleMap = new HandleMap();
77
78    /**
79     * Pending service declaration queue
80     */
81    private List<ServiceDeclaration> mServiceDeclarations = new ArrayList<ServiceDeclaration>();
82
83    private ServiceDeclaration addDeclaration() {
84        synchronized (mServiceDeclarations) {
85            mServiceDeclarations.add(new ServiceDeclaration());
86        }
87        return getActiveDeclaration();
88    }
89
90    private ServiceDeclaration getActiveDeclaration() {
91        synchronized (mServiceDeclarations) {
92            if (mServiceDeclarations.size() > 0)
93                return mServiceDeclarations.get(mServiceDeclarations.size() - 1);
94        }
95        return null;
96    }
97
98    private ServiceDeclaration getPendingDeclaration() {
99        synchronized (mServiceDeclarations) {
100            if (mServiceDeclarations.size() > 0)
101                return mServiceDeclarations.get(0);
102        }
103        return null;
104    }
105
106    private void removePendingDeclaration() {
107        synchronized (mServiceDeclarations) {
108            if (mServiceDeclarations.size() > 0)
109                mServiceDeclarations.remove(0);
110        }
111    }
112
113    /**
114     * List of clients intereste in scan results.
115     */
116    private List<ScanClient> mScanQueue = new ArrayList<ScanClient>();
117
118    private ScanClient getScanClient(int appIf, boolean isServer) {
119        for(ScanClient client : mScanQueue) {
120            if (client.appIf == appIf && client.isServer == isServer) {
121                return client;
122            }
123        }
124        return null;
125    }
126
127    private void removeScanClient(int appIf, boolean isServer) {
128        for(ScanClient client : mScanQueue) {
129            if (client.appIf == appIf && client.isServer == isServer) {
130                mScanQueue.remove(client);
131                break;
132            }
133        }
134    }
135
136    /**
137     * Reliable write queue
138     */
139    private Set<String> mReliableQueue = new HashSet<String>();
140
141    static {
142        classInitNative();
143    }
144
145    protected String getName() {
146        return TAG;
147    }
148
149    protected IProfileServiceBinder initBinder() {
150        return new BluetoothGattBinder(this);
151    }
152
153    protected boolean start() {
154        if (DBG) Log.d(TAG, "start()");
155        initializeNative();
156        return true;
157    }
158
159    protected boolean stop() {
160        if (DBG) Log.d(TAG, "stop()");
161        mClientMap.clear();
162        mServerMap.clear();
163        mSearchQueue.clear();
164        mScanQueue.clear();
165        mHandleMap.clear();
166        mServiceDeclarations.clear();
167        mReliableQueue.clear();
168        return true;
169    }
170
171    protected boolean cleanup() {
172        if (DBG) Log.d(TAG, "cleanup()");
173        cleanupNative();
174        return true;
175    }
176
177    @Override
178    public int onStartCommand(Intent intent, int flags, int startId) {
179        if (GattDebugUtils.handleDebugAction(this, intent)) {
180            return Service.START_NOT_STICKY;
181        }
182        return super.onStartCommand(intent, flags, startId);
183    }
184
185    /**
186     * DeathReceipient handlers used to unregister applications that
187     * disconnect ungracefully (ie. crash or forced close).
188     */
189
190    class ClientDeathRecipient implements IBinder.DeathRecipient {
191        int mAppIf;
192
193        public ClientDeathRecipient(int appIf) {
194            mAppIf = appIf;
195        }
196
197        public void binderDied() {
198            if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
199            stopScan(mAppIf, false);
200            unregisterClient(mAppIf);
201        }
202    }
203
204    class ServerDeathRecipient implements IBinder.DeathRecipient {
205        int mAppIf;
206
207        public ServerDeathRecipient(int appIf) {
208            mAppIf = appIf;
209        }
210
211        public void binderDied() {
212            if (DBG) Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!");
213            unregisterServer(mAppIf);
214        }
215    }
216
217    /**
218     * Handlers for incoming service calls
219     */
220    private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {
221        private GattService mService;
222
223        public BluetoothGattBinder(GattService svc) {
224            mService = svc;
225        }
226
227        public boolean cleanup()  {
228            mService = null;
229            return true;
230        }
231
232        private GattService getService() {
233            if (mService  != null && mService.isAvailable()) return mService;
234            Log.e(TAG, "getService() - Service requested, but not available!");
235            return null;
236        }
237
238        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
239            GattService service = getService();
240            if (service == null) return new ArrayList<BluetoothDevice>();
241            return service.getDevicesMatchingConnectionStates(states);
242        }
243
244        public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
245            GattService service = getService();
246            if (service == null) return;
247            service.registerClient(uuid.getUuid(), callback);
248        }
249
250        public void unregisterClient(int clientIf) {
251            GattService service = getService();
252            if (service == null) return;
253            service.unregisterClient(clientIf);
254        }
255
256        public void startScan(int appIf, boolean isServer) {
257            GattService service = getService();
258            if (service == null) return;
259            service.startScan(appIf, isServer);
260        }
261
262        public void startScanWithUuids(int appIf, boolean isServer, ParcelUuid[] ids) {
263            GattService service = getService();
264            if (service == null) return;
265            UUID[] uuids = new UUID[ids.length];
266            for(int i = 0; i != ids.length; ++i) {
267                uuids[i] = ids[i].getUuid();
268            }
269            service.startScanWithUuids(appIf, isServer, uuids);
270        }
271
272        public void stopScan(int appIf, boolean isServer) {
273            GattService service = getService();
274            if (service == null) return;
275            service.stopScan(appIf, isServer);
276        }
277
278        public void clientConnect(int clientIf, String address, boolean isDirect) {
279            GattService service = getService();
280            if (service == null) return;
281            service.clientConnect(clientIf, address, isDirect);
282        }
283
284        public void clientDisconnect(int clientIf, String address) {
285            GattService service = getService();
286            if (service == null) return;
287            service.clientDisconnect(clientIf, address);
288        }
289
290        public void clientListen(int clientIf, boolean start) {
291            GattService service = getService();
292            if (service == null) return;
293            service.clientListen(clientIf, start);
294        }
295
296        public void refreshDevice(int clientIf, String address) {
297            GattService service = getService();
298            if (service == null) return;
299            service.refreshDevice(clientIf, address);
300        }
301
302        public void discoverServices(int clientIf, String address) {
303            GattService service = getService();
304            if (service == null) return;
305            service.discoverServices(clientIf, address);
306        }
307
308        public void readCharacteristic(int clientIf, String address, int srvcType,
309                                       int srvcInstanceId, ParcelUuid srvcId,
310                                       int charInstanceId, ParcelUuid charId,
311                                       int authReq) {
312            GattService service = getService();
313            if (service == null) return;
314            service.readCharacteristic(clientIf, address, srvcType, srvcInstanceId,
315                                       srvcId.getUuid(), charInstanceId,
316                                       charId.getUuid(), authReq);
317        }
318
319        public void writeCharacteristic(int clientIf, String address, int srvcType,
320                             int srvcInstanceId, ParcelUuid srvcId,
321                             int charInstanceId, ParcelUuid charId,
322                             int writeType, int authReq, byte[] value) {
323            GattService service = getService();
324            if (service == null) return;
325            service.writeCharacteristic(clientIf, address, srvcType, srvcInstanceId,
326                                       srvcId.getUuid(), charInstanceId,
327                                       charId.getUuid(), writeType, authReq,
328                                       value);
329        }
330
331        public void readDescriptor(int clientIf, String address, int srvcType,
332                            int srvcInstanceId, ParcelUuid srvcId,
333                            int charInstanceId, ParcelUuid charId,
334                            int descrInstanceId, ParcelUuid descrId,
335                            int authReq) {
336            GattService service = getService();
337            if (service == null) return;
338            service.readDescriptor(clientIf, address, srvcType,
339                                   srvcInstanceId, srvcId.getUuid(),
340                                   charInstanceId, charId.getUuid(),
341                                   descrInstanceId, descrId.getUuid(),
342                                   authReq);
343        }
344
345        public void writeDescriptor(int clientIf, String address, int srvcType,
346                            int srvcInstanceId, ParcelUuid srvcId,
347                            int charInstanceId, ParcelUuid charId,
348                            int descrInstanceId, ParcelUuid descrId,
349                            int writeType, int authReq, byte[] value) {
350            GattService service = getService();
351            if (service == null) return;
352            service.writeDescriptor(clientIf, address, srvcType,
353                                    srvcInstanceId, srvcId.getUuid(),
354                                    charInstanceId, charId.getUuid(),
355                                    descrInstanceId, descrId.getUuid(),
356                                    writeType, authReq, value);
357        }
358
359        public void beginReliableWrite(int clientIf, String address) {
360            GattService service = getService();
361            if (service == null) return;
362            service.beginReliableWrite(clientIf, address);
363        }
364
365        public void endReliableWrite(int clientIf, String address, boolean execute) {
366            GattService service = getService();
367            if (service == null) return;
368            service.endReliableWrite(clientIf, address, execute);
369        }
370
371        public void registerForNotification(int clientIf, String address, int srvcType,
372                            int srvcInstanceId, ParcelUuid srvcId,
373                            int charInstanceId, ParcelUuid charId,
374                            boolean enable) {
375            GattService service = getService();
376            if (service == null) return;
377            service.registerForNotification(clientIf, address, srvcType, srvcInstanceId,
378                                       srvcId.getUuid(), charInstanceId,
379                                       charId.getUuid(), enable);
380        }
381
382        public void readRemoteRssi(int clientIf, String address) {
383            GattService service = getService();
384            if (service == null) return;
385            service.readRemoteRssi(clientIf, address);
386        }
387
388        public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback) {
389            GattService service = getService();
390            if (service == null) return;
391            service.registerServer(uuid.getUuid(), callback);
392        }
393
394        public void unregisterServer(int serverIf) {
395            GattService service = getService();
396            if (service == null) return;
397            service.unregisterServer(serverIf);
398        }
399
400        public void serverConnect(int serverIf, String address, boolean isDirect) {
401            GattService service = getService();
402            if (service == null) return;
403            service.serverConnect(serverIf, address, isDirect);
404        }
405
406        public void serverDisconnect(int serverIf, String address) {
407            GattService service = getService();
408            if (service == null) return;
409            service.serverDisconnect(serverIf, address);
410        }
411
412        public void beginServiceDeclaration(int serverIf, int srvcType,
413                                            int srvcInstanceId, int minHandles,
414                                            ParcelUuid srvcId) {
415            GattService service = getService();
416            if (service == null) return;
417            service.beginServiceDeclaration(serverIf, srvcType, srvcInstanceId,
418                               minHandles, srvcId.getUuid());
419        }
420
421        public void addIncludedService(int serverIf, int srvcType,
422                            int srvcInstanceId, ParcelUuid srvcId) {
423            GattService service = getService();
424            if (service == null) return;
425            service.addIncludedService(serverIf, srvcType, srvcInstanceId,
426                                            srvcId.getUuid());
427        }
428
429        public void addCharacteristic(int serverIf, ParcelUuid charId,
430                            int properties, int permissions) {
431            GattService service = getService();
432            if (service == null) return;
433            service.addCharacteristic(serverIf, charId.getUuid(), properties,
434                                      permissions);
435        }
436
437        public void addDescriptor(int serverIf, ParcelUuid descId,
438                           int permissions) {
439            GattService service = getService();
440            if (service == null) return;
441            service.addDescriptor(serverIf, descId.getUuid(), permissions);
442        }
443
444        public void endServiceDeclaration(int serverIf) {
445            GattService service = getService();
446            if (service == null) return;
447            service.endServiceDeclaration(serverIf);
448        }
449
450        public void removeService(int serverIf, int srvcType,
451                           int srvcInstanceId, ParcelUuid srvcId) {
452            GattService service = getService();
453            if (service == null) return;
454            service.removeService(serverIf, srvcType, srvcInstanceId,
455                                  srvcId.getUuid());
456        }
457
458        public void clearServices(int serverIf) {
459            GattService service = getService();
460            if (service == null) return;
461            service.clearServices(serverIf);
462        }
463
464        public void sendResponse(int serverIf, String address, int requestId,
465                                 int status, int offset, byte[] value) {
466            GattService service = getService();
467            if (service == null) return;
468            service.sendResponse(serverIf, address, requestId, status, offset, value);
469        }
470
471        public void sendNotification(int serverIf, String address, int srvcType,
472                                              int srvcInstanceId, ParcelUuid srvcId,
473                                              int charInstanceId, ParcelUuid charId,
474                                              boolean confirm, byte[] value) {
475            GattService service = getService();
476            if (service == null) return;
477            service.sendNotification(serverIf, address, srvcType, srvcInstanceId,
478                srvcId.getUuid(), charInstanceId, charId.getUuid(), confirm, value);
479        }
480
481        public void setAdvData(int serverIf, boolean setScanRsp, boolean inclName,
482                                boolean inclTxPower, int minInterval, int maxInterval,
483                                int appearance, byte[] manufacturerData) {
484            GattService service = getService();
485            if (service == null) return;
486            service.setAdvData(serverIf, setScanRsp, inclName, inclTxPower,
487                minInterval, maxInterval, appearance, manufacturerData);
488        }
489    };
490
491    /**************************************************************************
492     * Callback functions - CLIENT
493     *************************************************************************/
494
495    void onScanResult(String address, int rssi, byte[] adv_data) {
496        if (DBG) Log.d(TAG, "onScanResult() - address=" + address
497                    + ", rssi=" + rssi);
498
499        List<UUID> remoteUuids = parseUuids(adv_data);
500        for (ScanClient client : mScanQueue) {
501            if (client.uuids.length > 0) {
502                int matches = 0;
503                for (UUID search : client.uuids) {
504                    for (UUID remote: remoteUuids) {
505                        if (remote.equals(search)) {
506                            ++matches;
507                            break; // Only count 1st match in case of duplicates
508                        }
509                    }
510                }
511
512                if (matches < client.uuids.length) continue;
513            }
514
515            if (!client.isServer) {
516                ClientMap.App app = mClientMap.getById(client.appIf);
517                if (app != null) {
518                    try {
519                        app.callback.onScanResult(address, rssi, adv_data);
520                    } catch (RemoteException e) {
521                        Log.e(TAG, "Exception: " + e);
522                        mClientMap.remove(client.appIf);
523                        mScanQueue.remove(client);
524                    }
525                }
526            } else {
527                ServerMap.App app = mServerMap.getById(client.appIf);
528                if (app != null) {
529                    try {
530                        app.callback.onScanResult(address, rssi, adv_data);
531                    } catch (RemoteException e) {
532                        Log.e(TAG, "Exception: " + e);
533                        mServerMap.remove(client.appIf);
534                        mScanQueue.remove(client);
535                    }
536                }
537            }
538        }
539    }
540
541    void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
542            throws RemoteException {
543        UUID uuid = new UUID(uuidMsb, uuidLsb);
544        if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
545        ClientMap.App app = mClientMap.getByUuid(uuid);
546        if (app != null) {
547            app.id = clientIf;
548            app.linkToDeath(new ClientDeathRecipient(clientIf));
549            app.callback.onClientRegistered(status, clientIf);
550        }
551    }
552
553    void onConnected(int clientIf, int connId, int status, String address)
554            throws RemoteException  {
555        if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf
556            + ", connId=" + connId + ", address=" + address);
557
558        if (status == 0) mClientMap.addConnection(clientIf, connId, address);
559        ClientMap.App app = mClientMap.getById(clientIf);
560        if (app != null) {
561            app.callback.onClientConnectionState(status, clientIf, true, address);
562        }
563    }
564
565    void onDisconnected(int clientIf, int connId, int status, String address)
566            throws RemoteException {
567        if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf
568            + ", connId=" + connId + ", address=" + address);
569
570        mClientMap.removeConnection(clientIf, connId);
571        mSearchQueue.removeConnId(connId);
572        ClientMap.App app = mClientMap.getById(clientIf);
573        if (app != null) {
574            app.callback.onClientConnectionState(status, clientIf, false, address);
575        }
576    }
577
578    void onSearchCompleted(int connId, int status) throws RemoteException {
579        if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status);
580        // We got all services, now let's explore characteristics...
581        continueSearch(connId, status);
582    }
583
584    void onSearchResult(int connId, int srvcType,
585            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb)
586            throws RemoteException {
587        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
588        String address = mClientMap.addressByConnId(connId);
589
590        if (DBG) Log.d(TAG, "onSearchResult() - address=" + address + ", uuid=" + uuid);
591
592        mSearchQueue.add(connId, srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb);
593
594        ClientMap.App app = mClientMap.getByConnId(connId);
595        if (app != null) {
596            app.callback.onGetService(address, srvcType, srvcInstId,
597                                        new ParcelUuid(uuid));
598        }
599    }
600
601    void onGetCharacteristic(int connId, int status, int srvcType,
602            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
603            int charInstId, long charUuidLsb, long charUuidMsb,
604            int charProp) throws RemoteException {
605
606        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
607        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
608        String address = mClientMap.addressByConnId(connId);
609
610        if (DBG) Log.d(TAG, "onGetCharacteristic() - address=" + address
611            + ", status=" + status + ", charUuid=" + charUuid + ", prop=" + charProp);
612
613        if (status == 0) {
614            mSearchQueue.add(connId, srvcType,
615                            srvcInstId, srvcUuidLsb, srvcUuidMsb,
616                            charInstId, charUuidLsb, charUuidMsb);
617
618            ClientMap.App app = mClientMap.getByConnId(connId);
619            if (app != null) {
620                app.callback.onGetCharacteristic(address, srvcType,
621                            srvcInstId, new ParcelUuid(srvcUuid),
622                            charInstId, new ParcelUuid(charUuid), charProp);
623            }
624
625            // Get next characteristic in the current service
626            gattClientGetCharacteristicNative(connId, srvcType,
627                                        srvcInstId, srvcUuidLsb, srvcUuidMsb,
628                                        charInstId, charUuidLsb, charUuidMsb);
629        } else {
630            // Check for included services next
631            gattClientGetIncludedServiceNative(connId,
632                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
633                0,0,0,0);
634        }
635    }
636
637    void onGetDescriptor(int connId, int status, int srvcType,
638            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
639            int charInstId, long charUuidLsb, long charUuidMsb,
640            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
641
642        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
643        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
644        UUID descUuid = new UUID(descrUuidMsb, descrUuidLsb);
645        String address = mClientMap.addressByConnId(connId);
646
647        if (DBG) Log.d(TAG, "onGetDescriptor() - address=" + address
648            + ", status=" + status + ", descUuid=" + descUuid);
649
650        if (status == 0) {
651            ClientMap.App app = mClientMap.getByConnId(connId);
652            if (app != null) {
653                app.callback.onGetDescriptor(address, srvcType,
654                            srvcInstId, new ParcelUuid(srvcUuid),
655                            charInstId, new ParcelUuid(charUuid),
656                            descrInstId, new ParcelUuid(descUuid));
657            }
658
659            // Get next descriptor for the current characteristic
660            gattClientGetDescriptorNative(connId, srvcType,
661                                    srvcInstId, srvcUuidLsb, srvcUuidMsb,
662                                    charInstId, charUuidLsb, charUuidMsb,
663                                    descrInstId, descrUuidLsb, descrUuidMsb);
664        } else {
665            // Explore the next service
666            continueSearch(connId, 0);
667        }
668    }
669
670    void onGetIncludedService(int connId, int status, int srvcType,
671            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, int inclSrvcType,
672            int inclSrvcInstId, long inclSrvcUuidLsb, long inclSrvcUuidMsb)
673            throws RemoteException {
674        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
675        UUID inclSrvcUuid = new UUID(inclSrvcUuidMsb, inclSrvcUuidLsb);
676        String address = mClientMap.addressByConnId(connId);
677
678        if (DBG) Log.d(TAG, "onGetIncludedService() - address=" + address
679            + ", status=" + status + ", uuid=" + srvcUuid
680            + ", inclUuid=" + inclSrvcUuid);
681
682        if (status == 0) {
683            ClientMap.App app = mClientMap.getByConnId(connId);
684            if (app != null) {
685                app.callback.onGetIncludedService(address,
686                    srvcType, srvcInstId, new ParcelUuid(srvcUuid),
687                    inclSrvcType, inclSrvcInstId, new ParcelUuid(inclSrvcUuid));
688            }
689
690            // Find additional included services
691            gattClientGetIncludedServiceNative(connId,
692                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
693                inclSrvcType, inclSrvcInstId, inclSrvcUuidLsb, inclSrvcUuidMsb);
694        } else {
695            // Discover descriptors now
696            continueSearch(connId, 0);
697        }
698    }
699
700    void onRegisterForNotifications(int connId, int status, int registered, int srvcType,
701            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
702            int charInstId, long charUuidLsb, long charUuidMsb) {
703        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
704        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
705        String address = mClientMap.addressByConnId(connId);
706
707        if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address
708            + ", status=" + status + ", registered=" + registered
709            + ", charUuid=" + charUuid);
710    }
711
712    void onNotify(int connId, String address, int srvcType,
713            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
714            int charInstId, long charUuidLsb, long charUuidMsb,
715            boolean isNotify, byte[] data) throws RemoteException {
716        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
717        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
718
719        if (DBG) Log.d(TAG, "onNotify() - address=" + address
720            + ", charUuid=" + charUuid + ", length=" + data.length);
721
722        ClientMap.App app = mClientMap.getByConnId(connId);
723        if (app != null) {
724            app.callback.onNotify(address, srvcType,
725                        srvcInstId, new ParcelUuid(srvcUuid),
726                        charInstId, new ParcelUuid(charUuid),
727                        data);
728        }
729    }
730
731    void onReadCharacteristic(int connId, int status, int srvcType,
732            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
733            int charInstId, long charUuidLsb, long charUuidMsb,
734            int charType, byte[] data) throws RemoteException {
735
736        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
737        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
738        String address = mClientMap.addressByConnId(connId);
739
740        if (DBG) Log.d(TAG, "onReadCharacteristic() - address=" + address
741            + ", status=" + status + ", length=" + data.length);
742
743        ClientMap.App app = mClientMap.getByConnId(connId);
744        if (app != null) {
745            app.callback.onCharacteristicRead(address, status, srvcType,
746                        srvcInstId, new ParcelUuid(srvcUuid),
747                        charInstId, new ParcelUuid(charUuid), data);
748        }
749    }
750
751    void onWriteCharacteristic(int connId, int status, int srvcType,
752            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
753            int charInstId, long charUuidLsb, long charUuidMsb)
754            throws RemoteException {
755
756        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
757        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
758        String address = mClientMap.addressByConnId(connId);
759
760        if (DBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address
761            + ", status=" + status);
762
763        ClientMap.App app = mClientMap.getByConnId(connId);
764        if (app != null) {
765            app.callback.onCharacteristicWrite(address, status, srvcType,
766                        srvcInstId, new ParcelUuid(srvcUuid),
767                        charInstId, new ParcelUuid(charUuid));
768        }
769    }
770
771    void onExecuteCompleted(int connId, int status) throws RemoteException {
772        String address = mClientMap.addressByConnId(connId);
773        if (DBG) Log.d(TAG, "onExecuteCompleted() - address=" + address
774            + ", status=" + status);
775
776        ClientMap.App app = mClientMap.getByConnId(connId);
777        if (app != null) {
778            app.callback.onExecuteWrite(address, status);
779        }
780    }
781
782    void onReadDescriptor(int connId, int status, int srvcType,
783            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
784            int charInstId, long charUuidLsb, long charUuidMsb,
785            int descrInstId, long descrUuidLsb, long descrUuidMsb,
786            int charType, byte[] data) throws RemoteException {
787
788        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
789        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
790        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
791        String address = mClientMap.addressByConnId(connId);
792
793        if (DBG) Log.d(TAG, "onReadDescriptor() - address=" + address
794            + ", status=" + status + ", length=" + data.length);
795
796        ClientMap.App app = mClientMap.getByConnId(connId);
797        if (app != null) {
798            app.callback.onDescriptorRead(address, status, srvcType,
799                        srvcInstId, new ParcelUuid(srvcUuid),
800                        charInstId, new ParcelUuid(charUuid),
801                        descrInstId, new ParcelUuid(descrUuid), data);
802        }
803    }
804
805    void onWriteDescriptor(int connId, int status, int srvcType,
806            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
807            int charInstId, long charUuidLsb, long charUuidMsb,
808            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
809
810        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
811        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
812        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
813        String address = mClientMap.addressByConnId(connId);
814
815        if (DBG) Log.d(TAG, "onWriteDescriptor() - address=" + address
816            + ", status=" + status);
817
818        ClientMap.App app = mClientMap.getByConnId(connId);
819        if (app != null) {
820            app.callback.onDescriptorWrite(address, status, srvcType,
821                        srvcInstId, new ParcelUuid(srvcUuid),
822                        charInstId, new ParcelUuid(charUuid),
823                        descrInstId, new ParcelUuid(descrUuid));
824        }
825    }
826
827    void onReadRemoteRssi(int clientIf, String address,
828                    int rssi, int status) throws RemoteException{
829        if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" +
830                     address + ", rssi=" + rssi + ", status=" + status);
831
832        ClientMap.App app = mClientMap.getById(clientIf);
833        if (app != null) {
834            app.callback.onReadRemoteRssi(address, rssi, status);
835        }
836    }
837
838    void onClientListen(int status, int clientIf)
839            throws RemoteException {
840        if (DBG) Log.d(TAG, "onClientListen() status=" + status);
841
842        ClientMap.App app = mClientMap.getById(clientIf);
843        if (app == null) return;
844
845        app.callback.onListen(status);
846    }
847
848    /**************************************************************************
849     * GATT Service functions - Shared CLIENT/SERVER
850     *************************************************************************/
851
852    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
853        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
854
855        final int DEVICE_TYPE_BREDR = 0x1;
856
857        Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice,
858                                                                 Integer>();
859
860        // Add paired LE devices
861
862        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
863        for (BluetoothDevice device : bondedDevices) {
864            if (getDeviceType(device) != DEVICE_TYPE_BREDR) {
865                deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
866            }
867        }
868
869        // Add connected deviceStates
870
871        Set<String> connectedDevices = new HashSet<String>();
872        connectedDevices.addAll(mClientMap.getConnectedDevices());
873        connectedDevices.addAll(mServerMap.getConnectedDevices());
874
875        for (String address : connectedDevices ) {
876            BluetoothDevice device = mAdapter.getRemoteDevice(address);
877            if (device != null) {
878                deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
879            }
880        }
881
882        // Create matching device sub-set
883
884        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
885
886        for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
887            for(int state : states) {
888                if (entry.getValue() == state) {
889                    deviceList.add(entry.getKey());
890                }
891            }
892        }
893
894        return deviceList;
895    }
896
897    void startScan(int appIf, boolean isServer) {
898        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
899
900        if (DBG) Log.d(TAG, "startScan() - queue=" + mScanQueue.size());
901
902        if (getScanClient(appIf, isServer) == null) {
903            if (DBG) Log.d(TAG, "startScan() - adding client=" + appIf);
904            mScanQueue.add(new ScanClient(appIf, isServer));
905        }
906
907        gattClientScanNative(appIf, true);
908    }
909
910    void startScanWithUuids(int appIf, boolean isServer, UUID[] uuids) {
911        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
912
913        if (DBG) Log.d(TAG, "startScanWithUuids() - queue=" + mScanQueue.size());
914
915        if (getScanClient(appIf, isServer) == null) {
916            if (DBG) Log.d(TAG, "startScanWithUuids() - adding client=" + appIf);
917            mScanQueue.add(new ScanClient(appIf, isServer, uuids));
918        }
919
920        gattClientScanNative(appIf, true);
921    }
922
923    void stopScan(int appIf, boolean isServer) {
924        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH_ADMIN permission");
925
926        if (DBG) Log.d(TAG, "stopScan() - queue=" + mScanQueue.size());
927        removeScanClient(appIf, isServer);
928
929        if (mScanQueue.isEmpty()) {
930            if (DBG) Log.d(TAG, "stopScan() - queue empty; stopping scan");
931            gattClientScanNative(appIf, false);
932        }
933    }
934
935    /**************************************************************************
936     * GATT Service functions - CLIENT
937     *************************************************************************/
938
939    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
940        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
941
942        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
943        mClientMap.add(uuid, callback);
944        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
945                                    uuid.getMostSignificantBits());
946    }
947
948    void unregisterClient(int clientIf) {
949        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
950
951        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
952        mClientMap.remove(clientIf);
953        gattClientUnregisterAppNative(clientIf);
954    }
955
956    void clientConnect(int clientIf, String address, boolean isDirect) {
957        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
958
959        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
960        gattClientConnectNative(clientIf, address, isDirect);
961    }
962
963    void clientDisconnect(int clientIf, String address) {
964        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
965
966        Integer connId = mClientMap.connIdByAddress(clientIf, address);
967        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
968
969        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
970    }
971
972    void clientListen(int clientIf, boolean start) {
973        if (DBG) Log.d(TAG, "clientListen() - start=" + start);
974        gattClientListenNative(clientIf, start);
975    }
976
977    List<String> getConnectedDevices() {
978        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
979
980        Set<String> connectedDevAddress = new HashSet<String>();
981        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
982        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
983        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
984        return connectedDeviceList;
985    }
986
987    void refreshDevice(int clientIf, String address) {
988        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
989
990        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
991        gattClientRefreshNative(clientIf, address);
992    }
993
994    void discoverServices(int clientIf, String address) {
995        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
996
997        Integer connId = mClientMap.connIdByAddress(clientIf, address);
998        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
999
1000        if (connId != null)
1001            gattClientSearchServiceNative(connId, true, 0, 0);
1002        else
1003            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1004    }
1005
1006    void readCharacteristic(int clientIf, String address, int srvcType,
1007                            int srvcInstanceId, UUID srvcUuid,
1008                            int charInstanceId, UUID charUuid, int authReq) {
1009        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1010
1011        if (DBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1012
1013        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1014        if (connId != null)
1015            gattClientReadCharacteristicNative(connId, srvcType,
1016                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1017                srvcUuid.getMostSignificantBits(), charInstanceId,
1018                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1019                authReq);
1020        else
1021            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1022    }
1023
1024    void writeCharacteristic(int clientIf, String address, int srvcType,
1025                             int srvcInstanceId, UUID srvcUuid,
1026                             int charInstanceId, UUID charUuid, int writeType,
1027                             int authReq, byte[] value) {
1028        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1029
1030        if (DBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1031
1032        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1033
1034        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1035        if (connId != null)
1036            gattClientWriteCharacteristicNative(connId, srvcType,
1037                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1038                srvcUuid.getMostSignificantBits(), charInstanceId,
1039                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1040                writeType, authReq, value);
1041        else
1042            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1043    }
1044
1045    void readDescriptor(int clientIf, String address, int srvcType,
1046                            int srvcInstanceId, UUID srvcUuid,
1047                            int charInstanceId, UUID charUuid,
1048                            int descrInstanceId, UUID descrUuid,
1049                            int authReq) {
1050        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1051
1052        if (DBG) Log.d(TAG, "readDescriptor() - address=" + address);
1053
1054        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1055        if (connId != null)
1056            gattClientReadDescriptorNative(connId, srvcType,
1057                srvcInstanceId,
1058                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1059                charInstanceId,
1060                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1061                descrInstanceId,
1062                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1063                authReq);
1064        else
1065            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1066    };
1067
1068    void writeDescriptor(int clientIf, String address, int srvcType,
1069                            int srvcInstanceId, UUID srvcUuid,
1070                            int charInstanceId, UUID charUuid,
1071                            int descrInstanceId, UUID descrUuid,
1072                            int writeType, int authReq, byte[] value) {
1073        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1074
1075        if (DBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1076
1077        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1078        if (connId != null)
1079            gattClientWriteDescriptorNative(connId, srvcType,
1080                srvcInstanceId,
1081                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1082                charInstanceId,
1083                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1084                descrInstanceId,
1085                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1086                writeType, authReq, value);
1087        else
1088            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1089    }
1090
1091    void beginReliableWrite(int clientIf, String address) {
1092        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1093
1094        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1095        mReliableQueue.add(address);
1096    }
1097
1098    void endReliableWrite(int clientIf, String address, boolean execute) {
1099        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1100
1101        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1102                                + " execute: " + execute);
1103        mReliableQueue.remove(address);
1104
1105        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1106        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1107    }
1108
1109    void registerForNotification(int clientIf, String address, int srvcType,
1110                int srvcInstanceId, UUID srvcUuid,
1111                int charInstanceId, UUID charUuid,
1112                boolean enable) {
1113        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1114
1115        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1116
1117        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1118        if (connId != null) {
1119            gattClientRegisterForNotificationsNative(clientIf, address,
1120                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1121                srvcUuid.getMostSignificantBits(), charInstanceId,
1122                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1123                enable);
1124        } else {
1125            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1126        }
1127    }
1128
1129    void readRemoteRssi(int clientIf, String address) {
1130        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1131
1132        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1133        gattClientReadRemoteRssiNative(clientIf, address);
1134    }
1135
1136    void setAdvData(int serverIf, boolean setScanRsp, boolean inclName,
1137                boolean inclTxPower, int minInterval, int maxInterval,
1138                int appearance, byte[] manufacturerData) {
1139        if (DBG) Log.d(TAG, "setAdvData() - setScanRsp=" + setScanRsp);
1140        if (minInterval == 0) maxInterval = 0;
1141        gattSetAdvDataNative(serverIf, setScanRsp, inclName, inclTxPower,
1142            minInterval, maxInterval, appearance, manufacturerData);
1143    }
1144
1145    /**************************************************************************
1146     * Callback functions - SERVER
1147     *************************************************************************/
1148
1149    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1150            throws RemoteException {
1151
1152        UUID uuid = new UUID(uuidMsb, uuidLsb);
1153        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1154        ServerMap.App app = mServerMap.getByUuid(uuid);
1155        if (app != null) {
1156            app.id = serverIf;
1157            app.linkToDeath(new ServerDeathRecipient(serverIf));
1158            app.callback.onServerRegistered(status, serverIf);
1159        }
1160    }
1161
1162    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1163                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1164                        throws RemoteException {
1165        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1166        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1167            + ", handle=" + srvcHandle);
1168        if (status == 0)
1169            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId);
1170        continueServiceDeclaration(serverIf, status, srvcHandle);
1171    }
1172
1173    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1174                                int includedSrvcHandle) throws RemoteException {
1175        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1176            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1177        continueServiceDeclaration(serverIf, status, srvcHandle);
1178    }
1179
1180    void onCharacteristicAdded(int status, int serverIf,
1181                               long charUuidLsb, long charUuidMsb,
1182                               int srvcHandle, int charHandle)
1183                               throws RemoteException {
1184            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1185        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1186            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1187        if (status == 0)
1188            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1189        continueServiceDeclaration(serverIf, status, srvcHandle);
1190    }
1191
1192    void onDescriptorAdded(int status, int serverIf,
1193                           long descrUuidLsb, long descrUuidMsb,
1194                           int srvcHandle, int descrHandle)
1195                           throws RemoteException {
1196            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1197        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1198            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1199        if (status == 0)
1200            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1201        continueServiceDeclaration(serverIf, status, srvcHandle);
1202    }
1203
1204    void onServiceStarted(int status, int serverIf, int srvcHandle)
1205            throws RemoteException {
1206        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1207            + ", status=" + status);
1208        if (status == 0)
1209            mHandleMap.setStarted(serverIf, srvcHandle, true);
1210    }
1211
1212    void onServiceStopped(int status, int serverIf, int srvcHandle)
1213            throws RemoteException {
1214        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1215            + ", status=" + status);
1216        if (status == 0)
1217            mHandleMap.setStarted(serverIf, srvcHandle, false);
1218        stopNextService(serverIf, status);
1219    }
1220
1221    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1222        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1223            + ", status=" + status);
1224        mHandleMap.deleteService(serverIf, srvcHandle);
1225    }
1226
1227    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1228            throws RemoteException {
1229
1230        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1231            + ", address=" + address + ", connected=" + connected);
1232
1233        ServerMap.App app = mServerMap.getById(serverIf);
1234        if (app == null) return;
1235
1236        if (connected) {
1237            mServerMap.addConnection(serverIf, connId, address);
1238        } else {
1239            mServerMap.removeConnection(serverIf, connId);
1240        }
1241
1242        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1243    }
1244
1245    void onAttributeRead(String address, int connId, int transId,
1246                            int attrHandle, int offset, boolean isLong)
1247                            throws RemoteException {
1248        if (DBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1249            + ", address=" + address + ", handle=" + attrHandle
1250            + ", requestId=" + transId + ", offset=" + offset);
1251
1252        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1253        if (entry == null) return;
1254
1255        if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid
1256            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1257
1258        mHandleMap.addRequest(transId, attrHandle);
1259
1260        ServerMap.App app = mServerMap.getById(entry.serverIf);
1261        if (app == null) return;
1262
1263        switch(entry.type) {
1264            case HandleMap.TYPE_CHARACTERISTIC:
1265            {
1266                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1267                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1268                    serviceEntry.serviceType, serviceEntry.instance,
1269                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1270                    new ParcelUuid(entry.uuid));
1271                break;
1272            }
1273
1274            case HandleMap.TYPE_DESCRIPTOR:
1275            {
1276                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1277                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1278                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1279                    serviceEntry.serviceType, serviceEntry.instance,
1280                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1281                    new ParcelUuid(charEntry.uuid),
1282                    new ParcelUuid(entry.uuid));
1283                break;
1284            }
1285
1286            default:
1287                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1288                break;
1289        }
1290    }
1291
1292    void onAttributeWrite(String address, int connId, int transId,
1293                            int attrHandle, int offset, int length,
1294                            boolean needRsp, boolean isPrep,
1295                            byte[] data)
1296                            throws RemoteException {
1297        if (DBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1298            + ", address=" + address + ", handle=" + attrHandle
1299            + ", requestId=" + transId + ", isPrep=" + isPrep
1300            + ", offset=" + offset);
1301
1302        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1303        if (entry == null) return;
1304
1305        if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid
1306            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1307
1308        mHandleMap.addRequest(transId, attrHandle);
1309
1310        ServerMap.App app = mServerMap.getById(entry.serverIf);
1311        if (app == null) return;
1312
1313        switch(entry.type) {
1314            case HandleMap.TYPE_CHARACTERISTIC:
1315            {
1316                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1317                app.callback.onCharacteristicWriteRequest(address, transId,
1318                            offset, length, isPrep, needRsp,
1319                            serviceEntry.serviceType, serviceEntry.instance,
1320                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1321                            new ParcelUuid(entry.uuid), data);
1322                break;
1323            }
1324
1325            case HandleMap.TYPE_DESCRIPTOR:
1326            {
1327                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1328                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1329                app.callback.onDescriptorWriteRequest(address, transId,
1330                            offset, length, isPrep, needRsp,
1331                            serviceEntry.serviceType, serviceEntry.instance,
1332                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1333                            new ParcelUuid(charEntry.uuid),
1334                            new ParcelUuid(entry.uuid), data);
1335                break;
1336            }
1337
1338            default:
1339                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1340                break;
1341        }
1342    }
1343
1344    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1345            throws RemoteException {
1346        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1347            + ", address=" + address + ", transId=" + transId);
1348
1349        ServerMap.App app = mServerMap.getByConnId(connId);
1350        if (app == null) return;
1351
1352        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1353    }
1354
1355    void onResponseSendCompleted(int status, int attrHandle) {
1356        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1357    }
1358
1359    /**************************************************************************
1360     * GATT Service functions - SERVER
1361     *************************************************************************/
1362
1363    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1364        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1365
1366        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1367        mServerMap.add(uuid, callback);
1368        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1369                                    uuid.getMostSignificantBits());
1370    }
1371
1372    void unregisterServer(int serverIf) {
1373        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1374
1375        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1376
1377        deleteServices(serverIf);
1378
1379        mServerMap.remove(serverIf);
1380        gattServerUnregisterAppNative(serverIf);
1381    }
1382
1383    void serverConnect(int serverIf, String address, boolean isDirect) {
1384        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1385
1386        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1387        gattServerConnectNative(serverIf, address, isDirect);
1388    }
1389
1390    void serverDisconnect(int serverIf, String address) {
1391        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1392
1393        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1394        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1395
1396        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1397    }
1398
1399    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1400                                 int minHandles, UUID srvcUuid) {
1401        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1402
1403        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1404        ServiceDeclaration serviceDeclaration = addDeclaration();
1405        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles);
1406    }
1407
1408    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1409                            UUID srvcUuid) {
1410        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1411
1412        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1413        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1414    }
1415
1416    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1417                           int permissions) {
1418        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1419
1420        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1421        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1422    }
1423
1424    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1425        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1426
1427        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1428        getActiveDeclaration().addDescriptor(descUuid, permissions);
1429    }
1430
1431    void endServiceDeclaration(int serverIf) {
1432        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1433
1434        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1435
1436        if (getActiveDeclaration() == getPendingDeclaration()) {
1437            try {
1438                continueServiceDeclaration(serverIf, (byte)0, 0);
1439            } catch (RemoteException e) {
1440                Log.e(TAG,""+e);
1441            }
1442        }
1443    }
1444
1445    void removeService(int serverIf, int srvcType,
1446                  int srvcInstanceId, UUID srvcUuid) {
1447        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1448
1449        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
1450
1451        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1452        if (srvcHandle == 0) return;
1453        gattServerDeleteServiceNative(serverIf, srvcHandle);
1454    }
1455
1456    void clearServices(int serverIf) {
1457        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1458
1459        if (DBG) Log.d(TAG, "clearServices()");
1460        deleteServices(serverIf);
1461    }
1462
1463    void sendResponse(int serverIf, String address, int requestId,
1464                      int status, int offset, byte[] value) {
1465        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1466
1467        if (DBG) Log.d(TAG, "sendResponse() - address=" + address);
1468
1469        int handle = 0;
1470        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
1471        if (entry != null) handle = entry.handle;
1472
1473        int connId = mServerMap.connIdByAddress(serverIf, address);
1474        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
1475                                     handle, offset, value, (byte)0);
1476        mHandleMap.deleteRequest(requestId);
1477    }
1478
1479    void sendNotification(int serverIf, String address, int srvcType,
1480                                 int srvcInstanceId, UUID srvcUuid,
1481                                 int charInstanceId, UUID charUuid,
1482                                 boolean confirm, byte[] value) {
1483        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1484
1485        if (DBG) Log.d(TAG, "sendNotification() - address=" + address);
1486
1487        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1488        if (srvcHandle == 0) return;
1489
1490        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
1491        if (charHandle == 0) return;
1492
1493        int connId = mServerMap.connIdByAddress(serverIf, address);
1494        if (connId == 0) return;
1495
1496        if (confirm) {
1497            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
1498        } else {
1499            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
1500        }
1501    }
1502
1503    /**************************************************************************
1504     * Private functions
1505     *************************************************************************/
1506
1507    private int getDeviceType(BluetoothDevice device) {
1508        int type = gattClientGetDeviceTypeNative(device.getAddress());
1509        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
1510            + ", type=" + type);
1511        return type;
1512    }
1513
1514    private void continueSearch(int connId, int status) throws RemoteException {
1515        if (status == 0 && !mSearchQueue.isEmpty()) {
1516            SearchQueue.Entry svc = mSearchQueue.pop();
1517
1518            if (svc.charUuidLsb == 0) {
1519                // Characteristic is up next
1520                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
1521                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
1522            } else {
1523                // Descriptor is up next
1524                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
1525                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
1526                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
1527            }
1528        } else {
1529            ClientMap.App app = mClientMap.getByConnId(connId);
1530            if (app != null) {
1531                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
1532            }
1533        }
1534    }
1535
1536    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
1537        if (mServiceDeclarations.size() == 0) return;
1538        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
1539
1540        boolean finished = false;
1541
1542        ServiceDeclaration.Entry entry = null;
1543        if (status == 0)
1544            entry = getPendingDeclaration().getNext();
1545
1546        if (entry != null) {
1547            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
1548                + entry.type);
1549            switch(entry.type) {
1550                case ServiceDeclaration.TYPE_SERVICE:
1551                    gattServerAddServiceNative(serverIf, entry.serviceType,
1552                        entry.instance,
1553                        entry.uuid.getLeastSignificantBits(),
1554                        entry.uuid.getMostSignificantBits(),
1555                        getPendingDeclaration().getNumHandles());
1556                    break;
1557
1558                case ServiceDeclaration.TYPE_CHARACTERISTIC:
1559                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
1560                        entry.uuid.getLeastSignificantBits(),
1561                        entry.uuid.getMostSignificantBits(),
1562                        entry.properties, entry.permissions);
1563                    break;
1564
1565                case ServiceDeclaration.TYPE_DESCRIPTOR:
1566                    gattServerAddDescriptorNative(serverIf, srvcHandle,
1567                        entry.uuid.getLeastSignificantBits(),
1568                        entry.uuid.getMostSignificantBits(),
1569                        entry.permissions);
1570                    break;
1571
1572                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
1573                {
1574                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
1575                                            entry.serviceType, entry.instance);
1576                    if (inclSrvc != 0) {
1577                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
1578                                                           inclSrvc);
1579                    } else {
1580                        finished = true;
1581                    }
1582                    break;
1583                }
1584            }
1585        } else {
1586            gattServerStartServiceNative(serverIf, srvcHandle, (byte)2 /*BREDR/LE*/);
1587            finished = true;
1588        }
1589
1590        if (finished) {
1591            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
1592            ServerMap.App app = mServerMap.getById(serverIf);
1593            if (app != null) {
1594                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
1595                if (serviceEntry != null) {
1596                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
1597                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
1598                } else {
1599                    app.callback.onServiceAdded(status, 0, 0, null);
1600                }
1601            }
1602            removePendingDeclaration();
1603
1604            if (getPendingDeclaration() != null) {
1605                continueServiceDeclaration(serverIf, (byte)0, 0);
1606            }
1607        }
1608    }
1609
1610    private void stopNextService(int serverIf, int status) throws RemoteException {
1611        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
1612            + ", status=" + status);
1613
1614        if (status == 0) {
1615            List<HandleMap.Entry> entries = mHandleMap.getEntries();
1616            for(HandleMap.Entry entry : entries) {
1617                if (entry.type != HandleMap.TYPE_SERVICE ||
1618                    entry.serverIf != serverIf ||
1619                    entry.started == false)
1620                        continue;
1621
1622                gattServerStopServiceNative(serverIf, entry.handle);
1623                return;
1624            }
1625        }
1626    }
1627
1628    private void deleteServices(int serverIf) {
1629        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
1630
1631        /*
1632         * Figure out which handles to delete.
1633         * The handles are copied into a new list to avoid race conditions.
1634         */
1635        List<Integer> handleList = new ArrayList<Integer>();
1636        List<HandleMap.Entry> entries = mHandleMap.getEntries();
1637        for(HandleMap.Entry entry : entries) {
1638            if (entry.type != HandleMap.TYPE_SERVICE ||
1639                entry.serverIf != serverIf)
1640                    continue;
1641            handleList.add(entry.handle);
1642        }
1643
1644        /* Now actually delete the services.... */
1645        for(Integer handle : handleList) {
1646            gattServerDeleteServiceNative(serverIf, handle);
1647        }
1648    }
1649
1650    private List<UUID> parseUuids(byte[] adv_data) {
1651        List<UUID> uuids = new ArrayList<UUID>();
1652
1653        int offset = 0;
1654        while(offset < (adv_data.length-2)) {
1655            int len = adv_data[offset++];
1656            if (len == 0) break;
1657
1658            int type = adv_data[offset++];
1659            switch (type) {
1660                case 0x02: // Partial list of 16-bit UUIDs
1661                case 0x03: // Complete list of 16-bit UUIDs
1662                    while (len > 1) {
1663                        int uuid16 = adv_data[offset++];
1664                        uuid16 += (adv_data[offset++] << 8);
1665                        len -= 2;
1666                        uuids.add(UUID.fromString(String.format(
1667                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
1668                    }
1669                    break;
1670
1671                default:
1672                    offset += (len - 1);
1673                    break;
1674            }
1675        }
1676
1677        return uuids;
1678    }
1679
1680    /**************************************************************************
1681     * GATT Test functions
1682     *************************************************************************/
1683
1684    void gattTestCommand(int command, UUID uuid1, String bda1,
1685                         int p1, int p2, int p3, int p4, int p5) {
1686        if (bda1 == null) bda1 = "00:00:00:00:00:00";
1687        if (uuid1 != null)
1688            gattTestNative(command, uuid1.getLeastSignificantBits(),
1689                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
1690        else
1691            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
1692    }
1693
1694    private native void gattTestNative(int command,
1695                                    long uuid1_lsb, long uuid1_msb, String bda1,
1696                                    int p1, int p2, int p3, int p4, int p5);
1697
1698    /**************************************************************************
1699     * Native functions prototypes
1700     *************************************************************************/
1701
1702    private native static void classInitNative();
1703    private native void initializeNative();
1704    private native void cleanupNative();
1705
1706    private native int gattClientGetDeviceTypeNative(String address);
1707
1708    private native void gattClientRegisterAppNative(long app_uuid_lsb,
1709                                                    long app_uuid_msb);
1710
1711    private native void gattClientUnregisterAppNative(int clientIf);
1712
1713    private native void gattClientScanNative(int clientIf, boolean start);
1714
1715    private native void gattClientConnectNative(int clientIf, String address,
1716            boolean isDirect);
1717
1718    private native void gattClientDisconnectNative(int clientIf, String address,
1719            int conn_id);
1720
1721    private native void gattClientRefreshNative(int clientIf, String address);
1722
1723    private native void gattClientSearchServiceNative(int conn_id,
1724            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
1725
1726    private native void gattClientGetCharacteristicNative(int conn_id,
1727            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
1728            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
1729            long char_id_uuid_msb);
1730
1731    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
1732            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
1733            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
1734            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
1735
1736    private native void gattClientGetIncludedServiceNative(int conn_id,
1737            int service_type, int service_id_inst_id,
1738            long service_id_uuid_lsb, long service_id_uuid_msb,
1739            int incl_service_id_inst_id, int incl_service_type,
1740            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
1741
1742    private native void gattClientReadCharacteristicNative(int conn_id,
1743            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
1744            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
1745            long char_id_uuid_msb, int authReq);
1746
1747    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
1748            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
1749            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
1750            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
1751            int authReq);
1752
1753    private native void gattClientWriteCharacteristicNative(int conn_id,
1754            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
1755            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
1756            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
1757
1758    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
1759            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
1760            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
1761            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
1762            int write_type, int auth_req, byte[] value);
1763
1764    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
1765
1766    private native void gattClientRegisterForNotificationsNative(int clientIf,
1767            String address, int service_type, int service_id_inst_id,
1768            long service_id_uuid_lsb, long service_id_uuid_msb,
1769            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
1770            boolean enable);
1771
1772    private native void gattClientReadRemoteRssiNative(int clientIf,
1773            String address);
1774
1775    private native void gattClientListenNative(int client_if, boolean start);
1776
1777    private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
1778            boolean inclTxPower, int minInterval, int maxInterval,
1779            int appearance, byte[] manufacturerData);
1780
1781    private native void gattServerRegisterAppNative(long app_uuid_lsb,
1782                                                    long app_uuid_msb);
1783
1784    private native void gattServerUnregisterAppNative(int serverIf);
1785
1786    private native void gattServerConnectNative(int server_if, String address,
1787                                             boolean is_direct);
1788
1789    private native void gattServerDisconnectNative(int serverIf, String address,
1790                                              int conn_id);
1791
1792    private native void gattServerAddServiceNative (int server_if,
1793            int service_type, int service_id_inst_id,
1794            long service_id_uuid_lsb, long service_id_uuid_msb,
1795            int num_handles);
1796
1797    private native void gattServerAddIncludedServiceNative (int server_if,
1798            int svc_handle, int included_svc_handle);
1799
1800    private native void gattServerAddCharacteristicNative (int server_if,
1801            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
1802            int properties, int permissions);
1803
1804    private native void gattServerAddDescriptorNative (int server_if,
1805            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
1806            int permissions);
1807
1808    private native void gattServerStartServiceNative (int server_if,
1809            int svc_handle, int transport );
1810
1811    private native void gattServerStopServiceNative (int server_if,
1812                                                     int svc_handle);
1813
1814    private native void gattServerDeleteServiceNative (int server_if,
1815                                                       int svc_handle);
1816
1817    private native void gattServerSendIndicationNative (int server_if,
1818            int attr_handle, int conn_id, byte[] val);
1819
1820    private native void gattServerSendNotificationNative (int server_if,
1821            int attr_handle, int conn_id, byte[] val);
1822
1823    private native void gattServerSendResponseNative (int server_if,
1824            int conn_id, int trans_id, int status, int handle, int offset,
1825            byte[] val, int auth_req);
1826}
1827