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