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