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