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