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