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