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