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