GattService.java revision a6ebe46992bcdf60bfc40cbb78974425b8901449
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        mScanManager.startScan(scanClient);
1393    }
1394
1395    void flushPendingBatchResults(int clientIf, boolean isServer) {
1396        if (DBG) Log.d(TAG, "flushPendingBatchResults - clientIf=" + clientIf +
1397                ", isServer=" + isServer);
1398        mScanManager.flushBatchScanResults(new ScanClient(clientIf, isServer));
1399    }
1400
1401    void stopScan(ScanClient client) {
1402        enforceAdminPermission();
1403        int scanQueueSize = mScanManager.getBatchScanQueue().size() +
1404                mScanManager.getRegularScanQueue().size();
1405        if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize);
1406        mScanManager.stopScan(client);
1407    }
1408
1409    void disconnectAll() {
1410        if (DBG) Log.d(TAG, "disconnectAll()");
1411        Map<Integer, String> connMap = mClientMap.getConnectedMap();
1412        for(Map.Entry<Integer, String> entry:connMap.entrySet()){
1413            if (DBG) Log.d(TAG, "disconnecting addr:" + entry.getValue());
1414            clientDisconnect(entry.getKey(), entry.getValue());
1415            //clientDisconnect(int clientIf, String address)
1416        }
1417    }
1418
1419    void unregAll() {
1420        for(ClientMap.App app:mClientMap.mApps){
1421            if (DBG) Log.d(TAG, "unreg:" + app.id);
1422            unregisterClient(app.id);
1423        }
1424    }
1425
1426    /**************************************************************************
1427     * GATT Service functions - CLIENT
1428     *************************************************************************/
1429
1430    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
1431        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1432
1433        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1434        mClientMap.add(uuid, callback);
1435        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1436                                    uuid.getMostSignificantBits());
1437    }
1438
1439    void unregisterClient(int clientIf) {
1440        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1441
1442        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1443        mClientMap.remove(clientIf);
1444        gattClientUnregisterAppNative(clientIf);
1445    }
1446
1447    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1448        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1449
1450        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1451        gattClientConnectNative(clientIf, address, isDirect, transport);
1452    }
1453
1454    void clientDisconnect(int clientIf, String address) {
1455        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1456
1457        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1458        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1459
1460        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1461    }
1462
1463    void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,
1464            AdvertiseData scanResponse, AdvertiseSettings settings) {
1465        enforceAdminPermission();
1466        mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData,
1467                scanResponse));
1468    }
1469
1470    void stopMultiAdvertising(AdvertiseClient client) {
1471        enforceAdminPermission();
1472        mAdvertiseManager.stopAdvertising(client);
1473    }
1474
1475    int numHwTrackFiltersAvailable() {
1476        return (AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements()
1477                    - mScanManager.getCurrentUsedTrackingAdvertisement());
1478    }
1479
1480    synchronized List<ParcelUuid> getRegisteredServiceUuids() {
1481        Utils.enforceAdminPermission(this);
1482        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1483        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1484            serviceUuids.add(new ParcelUuid(entry.uuid));
1485        }
1486        return serviceUuids;
1487    }
1488
1489    List<String> getConnectedDevices() {
1490        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1491
1492        Set<String> connectedDevAddress = new HashSet<String>();
1493        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1494        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1495        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1496        return connectedDeviceList;
1497    }
1498
1499    void refreshDevice(int clientIf, String address) {
1500        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1501
1502        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1503        gattClientRefreshNative(clientIf, address);
1504    }
1505
1506    void discoverServices(int clientIf, String address) {
1507        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1508
1509        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1510        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1511
1512        if (connId != null)
1513            gattClientSearchServiceNative(connId, true, 0, 0);
1514        else
1515            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1516    }
1517
1518    void readCharacteristic(int clientIf, String address, int srvcType,
1519                            int srvcInstanceId, UUID srvcUuid,
1520                            int charInstanceId, UUID charUuid, int authReq) {
1521        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1522        if (isRestrictedCharUuid(charUuid) || isRestrictedSrvcUuid(srvcUuid)) {
1523            enforcePrivilegedPermission();
1524        }
1525
1526        if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1527
1528        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1529        if (connId != null)
1530            gattClientReadCharacteristicNative(connId, srvcType,
1531                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1532                srvcUuid.getMostSignificantBits(), charInstanceId,
1533                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1534                authReq);
1535        else
1536            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1537    }
1538
1539    void writeCharacteristic(int clientIf, String address, int srvcType,
1540                             int srvcInstanceId, UUID srvcUuid,
1541                             int charInstanceId, UUID charUuid, int writeType,
1542                             int authReq, byte[] value) {
1543        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1544        if (isRestrictedCharUuid(charUuid) || isRestrictedSrvcUuid(srvcUuid)) {
1545            enforcePrivilegedPermission();
1546        }
1547
1548        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1549
1550        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1551
1552        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1553        if (connId != null)
1554            gattClientWriteCharacteristicNative(connId, srvcType,
1555                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1556                srvcUuid.getMostSignificantBits(), charInstanceId,
1557                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1558                writeType, authReq, value);
1559        else
1560            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1561    }
1562
1563    void readDescriptor(int clientIf, String address, int srvcType,
1564                            int srvcInstanceId, UUID srvcUuid,
1565                            int charInstanceId, UUID charUuid,
1566                            int descrInstanceId, UUID descrUuid,
1567                            int authReq) {
1568        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1569        if (isRestrictedCharUuid(charUuid) || isRestrictedSrvcUuid(srvcUuid)) {
1570            enforcePrivilegedPermission();
1571        }
1572
1573        if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address);
1574
1575        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1576        if (connId != null)
1577            gattClientReadDescriptorNative(connId, srvcType,
1578                srvcInstanceId,
1579                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1580                charInstanceId,
1581                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1582                descrInstanceId,
1583                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1584                authReq);
1585        else
1586            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1587    };
1588
1589    void writeDescriptor(int clientIf, String address, int srvcType,
1590                            int srvcInstanceId, UUID srvcUuid,
1591                            int charInstanceId, UUID charUuid,
1592                            int descrInstanceId, UUID descrUuid,
1593                            int writeType, int authReq, byte[] value) {
1594        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1595        if (isRestrictedCharUuid(charUuid) || isRestrictedSrvcUuid(srvcUuid)) {
1596            enforcePrivilegedPermission();
1597        }
1598
1599        if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1600
1601        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1602        if (connId != null)
1603            gattClientWriteDescriptorNative(connId, srvcType,
1604                srvcInstanceId,
1605                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1606                charInstanceId,
1607                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1608                descrInstanceId,
1609                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1610                writeType, authReq, value);
1611        else
1612            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1613    }
1614
1615    void beginReliableWrite(int clientIf, String address) {
1616        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1617
1618        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1619        mReliableQueue.add(address);
1620    }
1621
1622    void endReliableWrite(int clientIf, String address, boolean execute) {
1623        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1624
1625        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1626                                + " execute: " + execute);
1627        mReliableQueue.remove(address);
1628
1629        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1630        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1631    }
1632
1633    void registerForNotification(int clientIf, String address, int srvcType,
1634                int srvcInstanceId, UUID srvcUuid,
1635                int charInstanceId, UUID charUuid,
1636                boolean enable) {
1637        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1638        if (isRestrictedCharUuid(charUuid) || isRestrictedSrvcUuid(srvcUuid)) {
1639            enforcePrivilegedPermission();
1640        }
1641
1642        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1643
1644        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1645        if (connId != null) {
1646            gattClientRegisterForNotificationsNative(clientIf, address,
1647                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1648                srvcUuid.getMostSignificantBits(), charInstanceId,
1649                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1650                enable);
1651        } else {
1652            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1653        }
1654    }
1655
1656    void readRemoteRssi(int clientIf, String address) {
1657        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1658
1659        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1660        gattClientReadRemoteRssiNative(clientIf, address);
1661    }
1662
1663    void configureMTU(int clientIf, String address, int mtu) {
1664        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1665
1666        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1667        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1668        if (connId != null) {
1669            gattClientConfigureMTUNative(connId, mtu);
1670        } else {
1671            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1672        }
1673    }
1674
1675    void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
1676        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1677
1678        // Default spec recommended interval is 30->50 ms
1679        int minInterval = 24; // 24 * 1.25ms = 30ms
1680        int maxInterval = 40; // 40 * 1.25ms = 50ms
1681
1682        // Slave latency
1683        int latency = 0;
1684
1685        // Link supervision timeout is measured in N * 10ms
1686        int timeout = 2000; // 20s
1687
1688        switch (connectionPriority)
1689        {
1690            case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
1691                minInterval = getResources().getInteger(R.integer.gatt_high_priority_min_interval);
1692                maxInterval = getResources().getInteger(R.integer.gatt_high_priority_max_interval);
1693                break;
1694
1695            case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
1696                minInterval = getResources().getInteger(R.integer.gatt_low_power_min_interval);
1697                maxInterval = getResources().getInteger(R.integer.gatt_low_power_max_interval);
1698                latency = 2;
1699                break;
1700        }
1701
1702        if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address
1703            + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
1704        gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
1705                                            latency, timeout);
1706    }
1707
1708    /**************************************************************************
1709     * Callback functions - SERVER
1710     *************************************************************************/
1711
1712    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1713            throws RemoteException {
1714
1715        UUID uuid = new UUID(uuidMsb, uuidLsb);
1716        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1717        ServerMap.App app = mServerMap.getByUuid(uuid);
1718        if (app != null) {
1719            app.id = serverIf;
1720            app.linkToDeath(new ServerDeathRecipient(serverIf));
1721            app.callback.onServerRegistered(status, serverIf);
1722        }
1723    }
1724
1725    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1726                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1727                        throws RemoteException {
1728        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1729        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1730            + ", handle=" + srvcHandle);
1731        if (status == 0) {
1732            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1733                mAdvertisingServiceUuids.remove(uuid));
1734        }
1735
1736        continueServiceDeclaration(serverIf, status, srvcHandle);
1737    }
1738
1739    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1740                                int includedSrvcHandle) throws RemoteException {
1741        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1742            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1743        continueServiceDeclaration(serverIf, status, srvcHandle);
1744    }
1745
1746    void onCharacteristicAdded(int status, int serverIf,
1747                               long charUuidLsb, long charUuidMsb,
1748                               int srvcHandle, int charHandle)
1749                               throws RemoteException {
1750            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1751        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1752            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1753        if (status == 0)
1754            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1755        continueServiceDeclaration(serverIf, status, srvcHandle);
1756    }
1757
1758    void onDescriptorAdded(int status, int serverIf,
1759                           long descrUuidLsb, long descrUuidMsb,
1760                           int srvcHandle, int descrHandle)
1761                           throws RemoteException {
1762            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1763        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1764            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1765        if (status == 0)
1766            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1767        continueServiceDeclaration(serverIf, status, srvcHandle);
1768    }
1769
1770    void onServiceStarted(int status, int serverIf, int srvcHandle)
1771            throws RemoteException {
1772        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1773            + ", status=" + status);
1774        if (status == 0)
1775            mHandleMap.setStarted(serverIf, srvcHandle, true);
1776    }
1777
1778    void onServiceStopped(int status, int serverIf, int srvcHandle)
1779            throws RemoteException {
1780        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1781            + ", status=" + status);
1782        if (status == 0)
1783            mHandleMap.setStarted(serverIf, srvcHandle, false);
1784        stopNextService(serverIf, status);
1785    }
1786
1787    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1788        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1789            + ", status=" + status);
1790        mHandleMap.deleteService(serverIf, srvcHandle);
1791    }
1792
1793    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1794            throws RemoteException {
1795
1796        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1797            + ", address=" + address + ", connected=" + connected);
1798
1799        ServerMap.App app = mServerMap.getById(serverIf);
1800        if (app == null) return;
1801
1802        if (connected) {
1803            mServerMap.addConnection(serverIf, connId, address);
1804        } else {
1805            mServerMap.removeConnection(serverIf, connId);
1806        }
1807
1808        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1809    }
1810
1811    void onAttributeRead(String address, int connId, int transId,
1812                            int attrHandle, int offset, boolean isLong)
1813                            throws RemoteException {
1814        if (VDBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1815            + ", address=" + address + ", handle=" + attrHandle
1816            + ", requestId=" + transId + ", offset=" + offset);
1817
1818        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1819        if (entry == null) return;
1820
1821        mHandleMap.addRequest(transId, attrHandle);
1822
1823        ServerMap.App app = mServerMap.getById(entry.serverIf);
1824        if (app == null) return;
1825
1826        switch(entry.type) {
1827            case HandleMap.TYPE_CHARACTERISTIC:
1828            {
1829                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1830                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1831                    serviceEntry.serviceType, serviceEntry.instance,
1832                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1833                    new ParcelUuid(entry.uuid));
1834                break;
1835            }
1836
1837            case HandleMap.TYPE_DESCRIPTOR:
1838            {
1839                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1840                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1841                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1842                    serviceEntry.serviceType, serviceEntry.instance,
1843                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1844                    new ParcelUuid(charEntry.uuid),
1845                    new ParcelUuid(entry.uuid));
1846                break;
1847            }
1848
1849            default:
1850                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1851                break;
1852        }
1853    }
1854
1855    void onAttributeWrite(String address, int connId, int transId,
1856                            int attrHandle, int offset, int length,
1857                            boolean needRsp, boolean isPrep,
1858                            byte[] data)
1859                            throws RemoteException {
1860        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1861            + ", address=" + address + ", handle=" + attrHandle
1862            + ", requestId=" + transId + ", isPrep=" + isPrep
1863            + ", offset=" + offset);
1864
1865        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1866        if (entry == null) return;
1867
1868        mHandleMap.addRequest(transId, attrHandle);
1869
1870        ServerMap.App app = mServerMap.getById(entry.serverIf);
1871        if (app == null) return;
1872
1873        switch(entry.type) {
1874            case HandleMap.TYPE_CHARACTERISTIC:
1875            {
1876                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1877                app.callback.onCharacteristicWriteRequest(address, transId,
1878                            offset, length, isPrep, needRsp,
1879                            serviceEntry.serviceType, serviceEntry.instance,
1880                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1881                            new ParcelUuid(entry.uuid), data);
1882                break;
1883            }
1884
1885            case HandleMap.TYPE_DESCRIPTOR:
1886            {
1887                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1888                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1889                app.callback.onDescriptorWriteRequest(address, transId,
1890                            offset, length, isPrep, needRsp,
1891                            serviceEntry.serviceType, serviceEntry.instance,
1892                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1893                            new ParcelUuid(charEntry.uuid),
1894                            new ParcelUuid(entry.uuid), data);
1895                break;
1896            }
1897
1898            default:
1899                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1900                break;
1901        }
1902    }
1903
1904    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1905            throws RemoteException {
1906        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1907            + ", address=" + address + ", transId=" + transId);
1908
1909        ServerMap.App app = mServerMap.getByConnId(connId);
1910        if (app == null) return;
1911
1912        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1913    }
1914
1915    void onResponseSendCompleted(int status, int attrHandle) {
1916        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1917    }
1918
1919    void onNotificationSent(int connId, int status) throws RemoteException {
1920        if (VDBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
1921
1922        String address = mServerMap.addressByConnId(connId);
1923        if (address == null) return;
1924
1925        ServerMap.App app = mServerMap.getByConnId(connId);
1926        if (app == null) return;
1927
1928        if (!app.isCongested) {
1929            app.callback.onNotificationSent(address, status);
1930        } else {
1931            if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
1932                status = BluetoothGatt.GATT_SUCCESS;
1933            }
1934            app.queueCallback(new CallbackInfo(address, status));
1935        }
1936    }
1937
1938    void onServerCongestion(int connId, boolean congested) throws RemoteException {
1939        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
1940
1941        ServerMap.App app = mServerMap.getByConnId(connId);
1942        if (app == null) return;
1943
1944        app.isCongested = congested;
1945        while(!app.isCongested) {
1946            CallbackInfo callbackInfo = app.popQueuedCallback();
1947            if (callbackInfo == null) return;
1948            app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status);
1949        }
1950    }
1951
1952    void onMtuChanged(int connId, int mtu) throws RemoteException {
1953        if (DBG) Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu);
1954
1955        String address = mServerMap.addressByConnId(connId);
1956        if (address == null) return;
1957
1958        ServerMap.App app = mServerMap.getByConnId(connId);
1959        if (app == null) return;
1960
1961        app.callback.onMtuChanged(address, mtu);
1962    }
1963
1964    /**************************************************************************
1965     * GATT Service functions - SERVER
1966     *************************************************************************/
1967
1968    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1969        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1970
1971        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1972        mServerMap.add(uuid, callback);
1973        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1974                                    uuid.getMostSignificantBits());
1975    }
1976
1977    void unregisterServer(int serverIf) {
1978        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1979
1980        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1981
1982        deleteServices(serverIf);
1983
1984        mServerMap.remove(serverIf);
1985        gattServerUnregisterAppNative(serverIf);
1986    }
1987
1988    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1989        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1990
1991        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1992        gattServerConnectNative(serverIf, address, isDirect,transport);
1993    }
1994
1995    void serverDisconnect(int serverIf, String address) {
1996        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1997
1998        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1999        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
2000
2001        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
2002    }
2003
2004    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
2005                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
2006        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2007
2008        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
2009        ServiceDeclaration serviceDeclaration = addDeclaration();
2010        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
2011            advertisePreferred);
2012    }
2013
2014    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
2015                            UUID srvcUuid) {
2016        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2017
2018        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
2019        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
2020    }
2021
2022    void addCharacteristic(int serverIf, UUID charUuid, int properties,
2023                           int permissions) {
2024        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2025
2026        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
2027        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
2028    }
2029
2030    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
2031        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2032
2033        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
2034        getActiveDeclaration().addDescriptor(descUuid, permissions);
2035    }
2036
2037    void endServiceDeclaration(int serverIf) {
2038        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2039
2040        if (DBG) Log.d(TAG, "endServiceDeclaration()");
2041
2042        if (getActiveDeclaration() == getPendingDeclaration()) {
2043            try {
2044                continueServiceDeclaration(serverIf, (byte)0, 0);
2045            } catch (RemoteException e) {
2046                Log.e(TAG,""+e);
2047            }
2048        }
2049    }
2050
2051    void removeService(int serverIf, int srvcType,
2052                  int srvcInstanceId, UUID srvcUuid) {
2053        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2054
2055        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
2056
2057        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
2058        if (srvcHandle == 0) return;
2059        gattServerDeleteServiceNative(serverIf, srvcHandle);
2060    }
2061
2062    void clearServices(int serverIf) {
2063        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2064
2065        if (DBG) Log.d(TAG, "clearServices()");
2066        deleteServices(serverIf);
2067    }
2068
2069    void sendResponse(int serverIf, String address, int requestId,
2070                      int status, int offset, byte[] value) {
2071        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2072
2073        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
2074
2075        int handle = 0;
2076        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
2077        if (entry != null) handle = entry.handle;
2078
2079        int connId = mServerMap.connIdByAddress(serverIf, address);
2080        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
2081                                     handle, offset, value, (byte)0);
2082        mHandleMap.deleteRequest(requestId);
2083    }
2084
2085    void sendNotification(int serverIf, String address, int srvcType,
2086                                 int srvcInstanceId, UUID srvcUuid,
2087                                 int charInstanceId, UUID charUuid,
2088                                 boolean confirm, byte[] value) {
2089        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2090
2091        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address);
2092
2093        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
2094        if (srvcHandle == 0) return;
2095
2096        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
2097        if (charHandle == 0) return;
2098
2099        int connId = mServerMap.connIdByAddress(serverIf, address);
2100        if (connId == 0) return;
2101
2102        if (confirm) {
2103            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
2104        } else {
2105            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
2106        }
2107    }
2108
2109
2110    /**************************************************************************
2111     * Private functions
2112     *************************************************************************/
2113
2114    private boolean isRestrictedCharUuid(final UUID charUuid) {
2115      return isHidUuid(charUuid);
2116    }
2117
2118    private boolean isRestrictedSrvcUuid(final UUID srvcUuid) {
2119      return isFidoUUID(srvcUuid);
2120    }
2121
2122    private boolean isHidUuid(final UUID uuid) {
2123        for (UUID hid_uuid : HID_UUIDS) {
2124            if (hid_uuid.equals(uuid)) return true;
2125        }
2126        return false;
2127    }
2128
2129    private boolean isFidoUUID(final UUID uuid) {
2130        for (UUID fido_uuid : FIDO_UUIDS) {
2131            if (fido_uuid.equals(uuid)) return true;
2132        }
2133        return false;
2134    }
2135
2136    private int getDeviceType(BluetoothDevice device) {
2137        int type = gattClientGetDeviceTypeNative(device.getAddress());
2138        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
2139            + ", type=" + type);
2140        return type;
2141    }
2142
2143    private void enforceAdminPermission() {
2144        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
2145    }
2146
2147    private boolean needsPrivilegedPermissionForScan(ScanSettings settings) {
2148        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2149        // BLE scan only mode needs special permission.
2150        if (adapter.getState() != BluetoothAdapter.STATE_ON) return true;
2151
2152        // Regular scan, no special permission.
2153        if (settings == null) return false;
2154
2155        // Regular scan, no special permission.
2156        if (settings.getReportDelayMillis() == 0) return false;
2157
2158        // Batch scan, truncated mode needs permission.
2159        return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED;
2160    }
2161
2162    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
2163    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
2164    private void enforcePrivilegedPermission() {
2165        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
2166            "Need BLUETOOTH_PRIVILEGED permission");
2167    }
2168
2169    private void continueSearch(int connId, int status) throws RemoteException {
2170
2171        // Search is complete when there was error, or nothing more to process
2172        if (status != 0 || mSearchQueue.isEmptyFor(connId)) {
2173            // In case we complete because of error, clean up
2174            // any remaining operations for this connection.
2175            mSearchQueue.removeConnId(connId);
2176
2177            ClientMap.App app = mClientMap.getByConnId(connId);
2178            if (app != null) {
2179                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
2180            }
2181        }
2182
2183        if (!mSearchQueue.isEmpty()) {
2184            SearchQueue.Entry svc = mSearchQueue.pop();
2185
2186            if (svc.charUuidLsb == 0) {
2187                // Characteristic is up next
2188                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
2189                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
2190            } else {
2191                // Descriptor is up next
2192                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
2193                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
2194                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
2195            }
2196        }
2197    }
2198
2199    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
2200        if (mServiceDeclarations.size() == 0) return;
2201        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
2202
2203        boolean finished = false;
2204
2205        ServiceDeclaration.Entry entry = null;
2206        if (status == 0)
2207            entry = getPendingDeclaration().getNext();
2208
2209        if (entry != null) {
2210            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
2211                + entry.type);
2212            switch(entry.type) {
2213                case ServiceDeclaration.TYPE_SERVICE:
2214                    if (entry.advertisePreferred) {
2215                        mAdvertisingServiceUuids.add(entry.uuid);
2216                    }
2217                    gattServerAddServiceNative(serverIf, entry.serviceType,
2218                        entry.instance,
2219                        entry.uuid.getLeastSignificantBits(),
2220                        entry.uuid.getMostSignificantBits(),
2221                        getPendingDeclaration().getNumHandles());
2222                    break;
2223
2224                case ServiceDeclaration.TYPE_CHARACTERISTIC:
2225                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
2226                        entry.uuid.getLeastSignificantBits(),
2227                        entry.uuid.getMostSignificantBits(),
2228                        entry.properties, entry.permissions);
2229                    break;
2230
2231                case ServiceDeclaration.TYPE_DESCRIPTOR:
2232                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2233                        entry.uuid.getLeastSignificantBits(),
2234                        entry.uuid.getMostSignificantBits(),
2235                        entry.permissions);
2236                    break;
2237
2238                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2239                {
2240                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2241                                            entry.serviceType, entry.instance);
2242                    if (inclSrvc != 0) {
2243                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2244                                                           inclSrvc);
2245                    } else {
2246                        finished = true;
2247                    }
2248                    break;
2249                }
2250            }
2251        } else {
2252            gattServerStartServiceNative(serverIf, srvcHandle,
2253                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2254            finished = true;
2255        }
2256
2257        if (finished) {
2258            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2259            ServerMap.App app = mServerMap.getById(serverIf);
2260            if (app != null) {
2261                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2262
2263                if (serviceEntry != null) {
2264                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2265                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2266                } else {
2267                    app.callback.onServiceAdded(status, 0, 0, null);
2268                }
2269            }
2270            removePendingDeclaration();
2271
2272            if (getPendingDeclaration() != null) {
2273                continueServiceDeclaration(serverIf, (byte)0, 0);
2274            }
2275        }
2276    }
2277
2278    private void stopNextService(int serverIf, int status) throws RemoteException {
2279        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2280            + ", status=" + status);
2281
2282        if (status == 0) {
2283            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2284            for(HandleMap.Entry entry : entries) {
2285                if (entry.type != HandleMap.TYPE_SERVICE ||
2286                    entry.serverIf != serverIf ||
2287                    entry.started == false)
2288                        continue;
2289
2290                gattServerStopServiceNative(serverIf, entry.handle);
2291                return;
2292            }
2293        }
2294    }
2295
2296    private void deleteServices(int serverIf) {
2297        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2298
2299        /*
2300         * Figure out which handles to delete.
2301         * The handles are copied into a new list to avoid race conditions.
2302         */
2303        List<Integer> handleList = new ArrayList<Integer>();
2304        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2305        for(HandleMap.Entry entry : entries) {
2306            if (entry.type != HandleMap.TYPE_SERVICE ||
2307                entry.serverIf != serverIf)
2308                    continue;
2309            handleList.add(entry.handle);
2310        }
2311
2312        /* Now actually delete the services.... */
2313        for(Integer handle : handleList) {
2314            gattServerDeleteServiceNative(serverIf, handle);
2315        }
2316    }
2317
2318    private List<UUID> parseUuids(byte[] adv_data) {
2319        List<UUID> uuids = new ArrayList<UUID>();
2320
2321        int offset = 0;
2322        while(offset < (adv_data.length-2)) {
2323            int len = adv_data[offset++];
2324            if (len == 0) break;
2325
2326            int type = adv_data[offset++];
2327            switch (type) {
2328                case 0x02: // Partial list of 16-bit UUIDs
2329                case 0x03: // Complete list of 16-bit UUIDs
2330                    while (len > 1) {
2331                        int uuid16 = adv_data[offset++];
2332                        uuid16 += (adv_data[offset++] << 8);
2333                        len -= 2;
2334                        uuids.add(UUID.fromString(String.format(
2335                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2336                    }
2337                    break;
2338
2339                default:
2340                    offset += (len - 1);
2341                    break;
2342            }
2343        }
2344
2345        return uuids;
2346    }
2347
2348    @Override
2349    public void dump(StringBuilder sb) {
2350        super.dump(sb);
2351        println(sb, "mAdvertisingServiceUuids:");
2352        for (UUID uuid : mAdvertisingServiceUuids) {
2353            println(sb, "  " + uuid);
2354        }
2355        for (ServiceDeclaration declaration : mServiceDeclarations) {
2356            println(sb, "  " + declaration);
2357        }
2358        println(sb, "mMaxScanFilters: " + mMaxScanFilters);
2359
2360        sb.append("\nGATT Client Map\n");
2361        mClientMap.dump(sb);
2362
2363        sb.append("\nGATT Server Map\n");
2364        mServerMap.dump(sb);
2365
2366        sb.append("\nGATT Handle Map\n");
2367        mHandleMap.dump(sb);
2368    }
2369
2370    /**************************************************************************
2371     * GATT Test functions
2372     *************************************************************************/
2373
2374    void gattTestCommand(int command, UUID uuid1, String bda1,
2375                         int p1, int p2, int p3, int p4, int p5) {
2376        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2377        if (uuid1 != null)
2378            gattTestNative(command, uuid1.getLeastSignificantBits(),
2379                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2380        else
2381            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2382    }
2383
2384    private native void gattTestNative(int command,
2385                                    long uuid1_lsb, long uuid1_msb, String bda1,
2386                                    int p1, int p2, int p3, int p4, int p5);
2387
2388    /**************************************************************************
2389     * Native functions prototypes
2390     *************************************************************************/
2391
2392    private native static void classInitNative();
2393    private native void initializeNative();
2394    private native void cleanupNative();
2395
2396    private native int gattClientGetDeviceTypeNative(String address);
2397
2398    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2399                                                    long app_uuid_msb);
2400
2401    private native void gattClientUnregisterAppNative(int clientIf);
2402
2403    private native void gattClientConnectNative(int clientIf, String address,
2404            boolean isDirect, int transport);
2405
2406    private native void gattClientDisconnectNative(int clientIf, String address,
2407            int conn_id);
2408
2409    private native void gattClientRefreshNative(int clientIf, String address);
2410
2411    private native void gattClientSearchServiceNative(int conn_id,
2412            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2413
2414    private native void gattClientGetCharacteristicNative(int conn_id,
2415            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2416            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2417            long char_id_uuid_msb);
2418
2419    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2420            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2421            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2422            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2423
2424    private native void gattClientGetIncludedServiceNative(int conn_id,
2425            int service_type, int service_id_inst_id,
2426            long service_id_uuid_lsb, long service_id_uuid_msb,
2427            int incl_service_id_inst_id, int incl_service_type,
2428            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2429
2430    private native void gattClientReadCharacteristicNative(int conn_id,
2431            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2432            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2433            long char_id_uuid_msb, int authReq);
2434
2435    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2436            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2437            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2438            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2439            int authReq);
2440
2441    private native void gattClientWriteCharacteristicNative(int conn_id,
2442            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2443            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2444            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2445
2446    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2447            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2448            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2449            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2450            int write_type, int auth_req, byte[] value);
2451
2452    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2453
2454    private native void gattClientRegisterForNotificationsNative(int clientIf,
2455            String address, int service_type, int service_id_inst_id,
2456            long service_id_uuid_lsb, long service_id_uuid_msb,
2457            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2458            boolean enable);
2459
2460    private native void gattClientReadRemoteRssiNative(int clientIf,
2461            String address);
2462
2463    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2464
2465    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2466            int minInterval, int maxInterval, int latency, int timeout);
2467
2468    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2469                                                    long app_uuid_msb);
2470
2471    private native void gattServerUnregisterAppNative(int serverIf);
2472
2473    private native void gattServerConnectNative(int server_if, String address,
2474                                             boolean is_direct, int transport);
2475
2476    private native void gattServerDisconnectNative(int serverIf, String address,
2477                                              int conn_id);
2478
2479    private native void gattServerAddServiceNative (int server_if,
2480            int service_type, int service_id_inst_id,
2481            long service_id_uuid_lsb, long service_id_uuid_msb,
2482            int num_handles);
2483
2484    private native void gattServerAddIncludedServiceNative (int server_if,
2485            int svc_handle, int included_svc_handle);
2486
2487    private native void gattServerAddCharacteristicNative (int server_if,
2488            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2489            int properties, int permissions);
2490
2491    private native void gattServerAddDescriptorNative (int server_if,
2492            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2493            int permissions);
2494
2495    private native void gattServerStartServiceNative (int server_if,
2496            int svc_handle, int transport );
2497
2498    private native void gattServerStopServiceNative (int server_if,
2499                                                     int svc_handle);
2500
2501    private native void gattServerDeleteServiceNative (int server_if,
2502                                                       int svc_handle);
2503
2504    private native void gattServerSendIndicationNative (int server_if,
2505            int attr_handle, int conn_id, byte[] val);
2506
2507    private native void gattServerSendNotificationNative (int server_if,
2508            int attr_handle, int conn_id, byte[] val);
2509
2510    private native void gattServerSendResponseNative (int server_if,
2511            int conn_id, int trans_id, int status, int handle, int offset,
2512            byte[] val, int auth_req);
2513}
2514