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