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