GattService.java revision e632e4bb8c873f102cac7d6f39585ea06f34c082
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        mHandleMap.addRequest(transId, attrHandle);
1692
1693        ServerMap.App app = mServerMap.getById(entry.serverIf);
1694        if (app == null) return;
1695
1696        switch(entry.type) {
1697            case HandleMap.TYPE_CHARACTERISTIC:
1698            {
1699                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1700                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1701                    serviceEntry.serviceType, serviceEntry.instance,
1702                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1703                    new ParcelUuid(entry.uuid));
1704                break;
1705            }
1706
1707            case HandleMap.TYPE_DESCRIPTOR:
1708            {
1709                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1710                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1711                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1712                    serviceEntry.serviceType, serviceEntry.instance,
1713                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1714                    new ParcelUuid(charEntry.uuid),
1715                    new ParcelUuid(entry.uuid));
1716                break;
1717            }
1718
1719            default:
1720                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1721                break;
1722        }
1723    }
1724
1725    void onAttributeWrite(String address, int connId, int transId,
1726                            int attrHandle, int offset, int length,
1727                            boolean needRsp, boolean isPrep,
1728                            byte[] data)
1729                            throws RemoteException {
1730        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1731            + ", address=" + address + ", handle=" + attrHandle
1732            + ", requestId=" + transId + ", isPrep=" + isPrep
1733            + ", offset=" + offset);
1734
1735        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1736        if (entry == null) return;
1737
1738        mHandleMap.addRequest(transId, attrHandle);
1739
1740        ServerMap.App app = mServerMap.getById(entry.serverIf);
1741        if (app == null) return;
1742
1743        switch(entry.type) {
1744            case HandleMap.TYPE_CHARACTERISTIC:
1745            {
1746                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1747                app.callback.onCharacteristicWriteRequest(address, transId,
1748                            offset, length, isPrep, needRsp,
1749                            serviceEntry.serviceType, serviceEntry.instance,
1750                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1751                            new ParcelUuid(entry.uuid), data);
1752                break;
1753            }
1754
1755            case HandleMap.TYPE_DESCRIPTOR:
1756            {
1757                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1758                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1759                app.callback.onDescriptorWriteRequest(address, transId,
1760                            offset, length, isPrep, needRsp,
1761                            serviceEntry.serviceType, serviceEntry.instance,
1762                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1763                            new ParcelUuid(charEntry.uuid),
1764                            new ParcelUuid(entry.uuid), data);
1765                break;
1766            }
1767
1768            default:
1769                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1770                break;
1771        }
1772    }
1773
1774    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1775            throws RemoteException {
1776        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1777            + ", address=" + address + ", transId=" + transId);
1778
1779        ServerMap.App app = mServerMap.getByConnId(connId);
1780        if (app == null) return;
1781
1782        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1783    }
1784
1785    void onResponseSendCompleted(int status, int attrHandle) {
1786        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1787    }
1788
1789    void onNotificationSent(int connId, int status) throws RemoteException {
1790        if (VDBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
1791
1792        String address = mServerMap.addressByConnId(connId);
1793        if (address == null) return;
1794
1795        ServerMap.App app = mServerMap.getByConnId(connId);
1796        if (app == null) return;
1797
1798        if (!app.isCongested) {
1799            app.callback.onNotificationSent(address, status);
1800        } else {
1801            if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
1802                status = BluetoothGatt.GATT_SUCCESS;
1803            }
1804            app.queueCallback(new CallbackInfo(address, status));
1805        }
1806    }
1807
1808    void onServerCongestion(int connId, boolean congested) throws RemoteException {
1809        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
1810
1811        ServerMap.App app = mServerMap.getByConnId(connId);
1812        if (app == null) return;
1813
1814        app.isCongested = congested;
1815        while(!app.isCongested) {
1816            CallbackInfo callbackInfo = app.popQueuedCallback();
1817            if (callbackInfo == null) return;
1818            app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status);
1819        }
1820    }
1821
1822    void onMtuChanged(int connId, int mtu) throws RemoteException {
1823        if (DBG) Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu);
1824
1825        String address = mServerMap.addressByConnId(connId);
1826        if (address == null) return;
1827
1828        ServerMap.App app = mServerMap.getByConnId(connId);
1829        if (app == null) return;
1830
1831        app.callback.onMtuChanged(address, mtu);
1832    }
1833
1834    /**************************************************************************
1835     * GATT Service functions - SERVER
1836     *************************************************************************/
1837
1838    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1839        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1840
1841        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1842        mServerMap.add(uuid, callback);
1843        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1844                                    uuid.getMostSignificantBits());
1845    }
1846
1847    void unregisterServer(int serverIf) {
1848        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1849
1850        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1851
1852        deleteServices(serverIf);
1853
1854        mServerMap.remove(serverIf);
1855        gattServerUnregisterAppNative(serverIf);
1856    }
1857
1858    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1859        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1860
1861        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1862        gattServerConnectNative(serverIf, address, isDirect,transport);
1863    }
1864
1865    void serverDisconnect(int serverIf, String address) {
1866        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1867
1868        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1869        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1870
1871        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1872    }
1873
1874    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1875                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1876        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1877
1878        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1879        ServiceDeclaration serviceDeclaration = addDeclaration();
1880        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1881            advertisePreferred);
1882    }
1883
1884    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1885                            UUID srvcUuid) {
1886        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1887
1888        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1889        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1890    }
1891
1892    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1893                           int permissions) {
1894        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1895
1896        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1897        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1898    }
1899
1900    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1901        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1902
1903        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1904        getActiveDeclaration().addDescriptor(descUuid, permissions);
1905    }
1906
1907    void endServiceDeclaration(int serverIf) {
1908        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1909
1910        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1911
1912        if (getActiveDeclaration() == getPendingDeclaration()) {
1913            try {
1914                continueServiceDeclaration(serverIf, (byte)0, 0);
1915            } catch (RemoteException e) {
1916                Log.e(TAG,""+e);
1917            }
1918        }
1919    }
1920
1921    void removeService(int serverIf, int srvcType,
1922                  int srvcInstanceId, UUID srvcUuid) {
1923        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1924
1925        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
1926
1927        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1928        if (srvcHandle == 0) return;
1929        gattServerDeleteServiceNative(serverIf, srvcHandle);
1930    }
1931
1932    void clearServices(int serverIf) {
1933        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1934
1935        if (DBG) Log.d(TAG, "clearServices()");
1936        deleteServices(serverIf);
1937    }
1938
1939    void sendResponse(int serverIf, String address, int requestId,
1940                      int status, int offset, byte[] value) {
1941        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1942
1943        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
1944
1945        int handle = 0;
1946        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
1947        if (entry != null) handle = entry.handle;
1948
1949        int connId = mServerMap.connIdByAddress(serverIf, address);
1950        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
1951                                     handle, offset, value, (byte)0);
1952        mHandleMap.deleteRequest(requestId);
1953    }
1954
1955    void sendNotification(int serverIf, String address, int srvcType,
1956                                 int srvcInstanceId, UUID srvcUuid,
1957                                 int charInstanceId, UUID charUuid,
1958                                 boolean confirm, byte[] value) {
1959        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1960
1961        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address);
1962
1963        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1964        if (srvcHandle == 0) return;
1965
1966        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
1967        if (charHandle == 0) return;
1968
1969        int connId = mServerMap.connIdByAddress(serverIf, address);
1970        if (connId == 0) return;
1971
1972        if (confirm) {
1973            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
1974        } else {
1975            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
1976        }
1977    }
1978
1979
1980    /**************************************************************************
1981     * Private functions
1982     *************************************************************************/
1983
1984    private int getDeviceType(BluetoothDevice device) {
1985        int type = gattClientGetDeviceTypeNative(device.getAddress());
1986        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
1987            + ", type=" + type);
1988        return type;
1989    }
1990
1991    private void enforceAdminPermission() {
1992        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1993    }
1994
1995    private boolean needsPrivilegedPermissionForScan(ScanSettings settings) {
1996        // Regular scan, no special permission.
1997        if (settings == null) {
1998            return false;
1999        }
2000        // Hidden API for onLost/onFound
2001        if (settings.getCallbackType() != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
2002            return true;
2003        }
2004        // Regular scan, no special permission.
2005        if (settings.getReportDelayMillis() == 0) {
2006            return false;
2007        }
2008        // Batch scan, truncated mode needs permission.
2009        return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED;
2010    }
2011
2012    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
2013    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
2014    private void enforcePrivilegedPermission() {
2015        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
2016            "Need BLUETOOTH_PRIVILEGED permission");
2017    }
2018
2019    private void continueSearch(int connId, int status) throws RemoteException {
2020        if (status == 0 && !mSearchQueue.isEmpty()) {
2021            SearchQueue.Entry svc = mSearchQueue.pop();
2022
2023            if (svc.charUuidLsb == 0) {
2024                // Characteristic is up next
2025                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
2026                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
2027            } else {
2028                // Descriptor is up next
2029                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
2030                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
2031                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
2032            }
2033        } else {
2034            ClientMap.App app = mClientMap.getByConnId(connId);
2035            if (app != null) {
2036                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
2037            }
2038        }
2039    }
2040
2041    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
2042        if (mServiceDeclarations.size() == 0) return;
2043        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
2044
2045        boolean finished = false;
2046
2047        ServiceDeclaration.Entry entry = null;
2048        if (status == 0)
2049            entry = getPendingDeclaration().getNext();
2050
2051        if (entry != null) {
2052            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
2053                + entry.type);
2054            switch(entry.type) {
2055                case ServiceDeclaration.TYPE_SERVICE:
2056                    if (entry.advertisePreferred) {
2057                        mAdvertisingServiceUuids.add(entry.uuid);
2058                    }
2059                    gattServerAddServiceNative(serverIf, entry.serviceType,
2060                        entry.instance,
2061                        entry.uuid.getLeastSignificantBits(),
2062                        entry.uuid.getMostSignificantBits(),
2063                        getPendingDeclaration().getNumHandles());
2064                    break;
2065
2066                case ServiceDeclaration.TYPE_CHARACTERISTIC:
2067                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
2068                        entry.uuid.getLeastSignificantBits(),
2069                        entry.uuid.getMostSignificantBits(),
2070                        entry.properties, entry.permissions);
2071                    break;
2072
2073                case ServiceDeclaration.TYPE_DESCRIPTOR:
2074                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2075                        entry.uuid.getLeastSignificantBits(),
2076                        entry.uuid.getMostSignificantBits(),
2077                        entry.permissions);
2078                    break;
2079
2080                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2081                {
2082                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2083                                            entry.serviceType, entry.instance);
2084                    if (inclSrvc != 0) {
2085                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2086                                                           inclSrvc);
2087                    } else {
2088                        finished = true;
2089                    }
2090                    break;
2091                }
2092            }
2093        } else {
2094            gattServerStartServiceNative(serverIf, srvcHandle,
2095                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2096            finished = true;
2097        }
2098
2099        if (finished) {
2100            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2101            ServerMap.App app = mServerMap.getById(serverIf);
2102            if (app != null) {
2103                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2104
2105                if (serviceEntry != null) {
2106                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2107                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2108                } else {
2109                    app.callback.onServiceAdded(status, 0, 0, null);
2110                }
2111            }
2112            removePendingDeclaration();
2113
2114            if (getPendingDeclaration() != null) {
2115                continueServiceDeclaration(serverIf, (byte)0, 0);
2116            }
2117        }
2118    }
2119
2120    private void stopNextService(int serverIf, int status) throws RemoteException {
2121        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2122            + ", status=" + status);
2123
2124        if (status == 0) {
2125            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2126            for(HandleMap.Entry entry : entries) {
2127                if (entry.type != HandleMap.TYPE_SERVICE ||
2128                    entry.serverIf != serverIf ||
2129                    entry.started == false)
2130                        continue;
2131
2132                gattServerStopServiceNative(serverIf, entry.handle);
2133                return;
2134            }
2135        }
2136    }
2137
2138    private void deleteServices(int serverIf) {
2139        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2140
2141        /*
2142         * Figure out which handles to delete.
2143         * The handles are copied into a new list to avoid race conditions.
2144         */
2145        List<Integer> handleList = new ArrayList<Integer>();
2146        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2147        for(HandleMap.Entry entry : entries) {
2148            if (entry.type != HandleMap.TYPE_SERVICE ||
2149                entry.serverIf != serverIf)
2150                    continue;
2151            handleList.add(entry.handle);
2152        }
2153
2154        /* Now actually delete the services.... */
2155        for(Integer handle : handleList) {
2156            gattServerDeleteServiceNative(serverIf, handle);
2157        }
2158    }
2159
2160    private List<UUID> parseUuids(byte[] adv_data) {
2161        List<UUID> uuids = new ArrayList<UUID>();
2162
2163        int offset = 0;
2164        while(offset < (adv_data.length-2)) {
2165            int len = adv_data[offset++];
2166            if (len == 0) break;
2167
2168            int type = adv_data[offset++];
2169            switch (type) {
2170                case 0x02: // Partial list of 16-bit UUIDs
2171                case 0x03: // Complete list of 16-bit UUIDs
2172                    while (len > 1) {
2173                        int uuid16 = adv_data[offset++];
2174                        uuid16 += (adv_data[offset++] << 8);
2175                        len -= 2;
2176                        uuids.add(UUID.fromString(String.format(
2177                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2178                    }
2179                    break;
2180
2181                default:
2182                    offset += (len - 1);
2183                    break;
2184            }
2185        }
2186
2187        return uuids;
2188    }
2189
2190    @Override
2191    public void dump(StringBuilder sb) {
2192        super.dump(sb);
2193        println(sb, "mAdvertisingServiceUuids:");
2194        for (UUID uuid : mAdvertisingServiceUuids) {
2195            println(sb, "  " + uuid);
2196        }
2197        println(sb, "mOnFoundResults:");
2198        for (ScanResult result : mOnFoundResults.values()) {
2199            println(sb, "  " + result);
2200        }
2201        println(sb, "mOnFoundResults:");
2202        for (ServiceDeclaration declaration : mServiceDeclarations) {
2203            println(sb, "  " + declaration);
2204        }
2205        println(sb, "mMaxScanFilters: " + mMaxScanFilters);
2206    }
2207
2208    /**************************************************************************
2209     * GATT Test functions
2210     *************************************************************************/
2211
2212    void gattTestCommand(int command, UUID uuid1, String bda1,
2213                         int p1, int p2, int p3, int p4, int p5) {
2214        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2215        if (uuid1 != null)
2216            gattTestNative(command, uuid1.getLeastSignificantBits(),
2217                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2218        else
2219            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2220    }
2221
2222    private native void gattTestNative(int command,
2223                                    long uuid1_lsb, long uuid1_msb, String bda1,
2224                                    int p1, int p2, int p3, int p4, int p5);
2225
2226    /**************************************************************************
2227     * Native functions prototypes
2228     *************************************************************************/
2229
2230    private native static void classInitNative();
2231    private native void initializeNative();
2232    private native void cleanupNative();
2233
2234    private native int gattClientGetDeviceTypeNative(String address);
2235
2236    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2237                                                    long app_uuid_msb);
2238
2239    private native void gattClientUnregisterAppNative(int clientIf);
2240
2241    private native void gattClientConnectNative(int clientIf, String address,
2242            boolean isDirect, int transport);
2243
2244    private native void gattClientDisconnectNative(int clientIf, String address,
2245            int conn_id);
2246
2247    private native void gattClientRefreshNative(int clientIf, String address);
2248
2249    private native void gattClientSearchServiceNative(int conn_id,
2250            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2251
2252    private native void gattClientGetCharacteristicNative(int conn_id,
2253            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2254            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2255            long char_id_uuid_msb);
2256
2257    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2258            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2259            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2260            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2261
2262    private native void gattClientGetIncludedServiceNative(int conn_id,
2263            int service_type, int service_id_inst_id,
2264            long service_id_uuid_lsb, long service_id_uuid_msb,
2265            int incl_service_id_inst_id, int incl_service_type,
2266            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2267
2268    private native void gattClientReadCharacteristicNative(int conn_id,
2269            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2270            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2271            long char_id_uuid_msb, int authReq);
2272
2273    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2274            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2275            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2276            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2277            int authReq);
2278
2279    private native void gattClientWriteCharacteristicNative(int conn_id,
2280            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2281            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2282            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2283
2284    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2285            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2286            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2287            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2288            int write_type, int auth_req, byte[] value);
2289
2290    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2291
2292    private native void gattClientRegisterForNotificationsNative(int clientIf,
2293            String address, int service_type, int service_id_inst_id,
2294            long service_id_uuid_lsb, long service_id_uuid_msb,
2295            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2296            boolean enable);
2297
2298    private native void gattClientReadRemoteRssiNative(int clientIf,
2299            String address);
2300
2301    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2302
2303    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2304            int minInterval, int maxInterval, int latency, int timeout);
2305
2306    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2307                                                    long app_uuid_msb);
2308
2309    private native void gattServerUnregisterAppNative(int serverIf);
2310
2311    private native void gattServerConnectNative(int server_if, String address,
2312                                             boolean is_direct, int transport);
2313
2314    private native void gattServerDisconnectNative(int serverIf, String address,
2315                                              int conn_id);
2316
2317    private native void gattServerAddServiceNative (int server_if,
2318            int service_type, int service_id_inst_id,
2319            long service_id_uuid_lsb, long service_id_uuid_msb,
2320            int num_handles);
2321
2322    private native void gattServerAddIncludedServiceNative (int server_if,
2323            int svc_handle, int included_svc_handle);
2324
2325    private native void gattServerAddCharacteristicNative (int server_if,
2326            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2327            int properties, int permissions);
2328
2329    private native void gattServerAddDescriptorNative (int server_if,
2330            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2331            int permissions);
2332
2333    private native void gattServerStartServiceNative (int server_if,
2334            int svc_handle, int transport );
2335
2336    private native void gattServerStopServiceNative (int server_if,
2337                                                     int svc_handle);
2338
2339    private native void gattServerDeleteServiceNative (int server_if,
2340                                                       int svc_handle);
2341
2342    private native void gattServerSendIndicationNative (int server_if,
2343            int attr_handle, int conn_id, byte[] val);
2344
2345    private native void gattServerSendNotificationNative (int server_if,
2346            int attr_handle, int conn_id, byte[] val);
2347
2348    private native void gattServerSendResponseNative (int server_if,
2349            int conn_id, int trans_id, int status, int handle, int offset,
2350            byte[] val, int auth_req);
2351}
2352