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