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