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