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