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