GattService.java revision 5ca43226937e098a2404d61de3f991af5c6a2689
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,
649                                (status==BluetoothGatt.GATT_SUCCESS), address);
650        }
651    }
652
653    void onDisconnected(int clientIf, int connId, int status, String address)
654            throws RemoteException {
655        if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf
656            + ", connId=" + connId + ", address=" + address);
657
658        mClientMap.removeConnection(clientIf, connId);
659        mSearchQueue.removeConnId(connId);
660        ClientMap.App app = mClientMap.getById(clientIf);
661        if (app != null) {
662            app.callback.onClientConnectionState(status, clientIf, false, address);
663        }
664    }
665
666    void onSearchCompleted(int connId, int status) throws RemoteException {
667        if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status);
668        // We got all services, now let's explore characteristics...
669        continueSearch(connId, status);
670    }
671
672    void onSearchResult(int connId, int srvcType,
673            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb)
674            throws RemoteException {
675        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
676        String address = mClientMap.addressByConnId(connId);
677
678        if (VDBG) Log.d(TAG, "onSearchResult() - address=" + address + ", uuid=" + uuid);
679
680        mSearchQueue.add(connId, srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb);
681
682        ClientMap.App app = mClientMap.getByConnId(connId);
683        if (app != null) {
684            app.callback.onGetService(address, srvcType, srvcInstId,
685                                        new ParcelUuid(uuid));
686        }
687    }
688
689    void onGetCharacteristic(int connId, int status, int srvcType,
690            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
691            int charInstId, long charUuidLsb, long charUuidMsb,
692            int charProp) throws RemoteException {
693
694        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
695        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
696        String address = mClientMap.addressByConnId(connId);
697
698        if (VDBG) Log.d(TAG, "onGetCharacteristic() - address=" + address
699            + ", status=" + status + ", charUuid=" + charUuid + ", prop=" + charProp);
700
701        if (status == 0) {
702            mSearchQueue.add(connId, srvcType,
703                            srvcInstId, srvcUuidLsb, srvcUuidMsb,
704                            charInstId, charUuidLsb, charUuidMsb);
705
706            ClientMap.App app = mClientMap.getByConnId(connId);
707            if (app != null) {
708                app.callback.onGetCharacteristic(address, srvcType,
709                            srvcInstId, new ParcelUuid(srvcUuid),
710                            charInstId, new ParcelUuid(charUuid), charProp);
711            }
712
713            // Get next characteristic in the current service
714            gattClientGetCharacteristicNative(connId, srvcType,
715                                        srvcInstId, srvcUuidLsb, srvcUuidMsb,
716                                        charInstId, charUuidLsb, charUuidMsb);
717        } else {
718            // Check for included services next
719            gattClientGetIncludedServiceNative(connId,
720                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
721                0,0,0,0);
722        }
723    }
724
725    void onGetDescriptor(int connId, int status, int srvcType,
726            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
727            int charInstId, long charUuidLsb, long charUuidMsb,
728            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
729
730        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
731        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
732        UUID descUuid = new UUID(descrUuidMsb, descrUuidLsb);
733        String address = mClientMap.addressByConnId(connId);
734
735        if (VDBG) Log.d(TAG, "onGetDescriptor() - address=" + address
736            + ", status=" + status + ", descUuid=" + descUuid);
737
738        if (status == 0) {
739            ClientMap.App app = mClientMap.getByConnId(connId);
740            if (app != null) {
741                app.callback.onGetDescriptor(address, srvcType,
742                            srvcInstId, new ParcelUuid(srvcUuid),
743                            charInstId, new ParcelUuid(charUuid),
744                            descrInstId, new ParcelUuid(descUuid));
745            }
746
747            // Get next descriptor for the current characteristic
748            gattClientGetDescriptorNative(connId, srvcType,
749                                    srvcInstId, srvcUuidLsb, srvcUuidMsb,
750                                    charInstId, charUuidLsb, charUuidMsb,
751                                    descrInstId, descrUuidLsb, descrUuidMsb);
752        } else {
753            // Explore the next service
754            continueSearch(connId, 0);
755        }
756    }
757
758    void onGetIncludedService(int connId, int status, int srvcType,
759            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, int inclSrvcType,
760            int inclSrvcInstId, long inclSrvcUuidLsb, long inclSrvcUuidMsb)
761            throws RemoteException {
762        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
763        UUID inclSrvcUuid = new UUID(inclSrvcUuidMsb, inclSrvcUuidLsb);
764        String address = mClientMap.addressByConnId(connId);
765
766        if (VDBG) Log.d(TAG, "onGetIncludedService() - address=" + address
767            + ", status=" + status + ", uuid=" + srvcUuid
768            + ", inclUuid=" + inclSrvcUuid);
769
770        if (status == 0) {
771            ClientMap.App app = mClientMap.getByConnId(connId);
772            if (app != null) {
773                app.callback.onGetIncludedService(address,
774                    srvcType, srvcInstId, new ParcelUuid(srvcUuid),
775                    inclSrvcType, inclSrvcInstId, new ParcelUuid(inclSrvcUuid));
776            }
777
778            // Find additional included services
779            gattClientGetIncludedServiceNative(connId,
780                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
781                inclSrvcType, inclSrvcInstId, inclSrvcUuidLsb, inclSrvcUuidMsb);
782        } else {
783            // Discover descriptors now
784            continueSearch(connId, 0);
785        }
786    }
787
788    void onRegisterForNotifications(int connId, int status, int registered, int srvcType,
789            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
790            int charInstId, long charUuidLsb, long charUuidMsb) {
791        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
792        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
793        String address = mClientMap.addressByConnId(connId);
794
795        if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address
796            + ", status=" + status + ", registered=" + registered
797            + ", charUuid=" + charUuid);
798    }
799
800    void onNotify(int connId, String address, int srvcType,
801            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
802            int charInstId, long charUuidLsb, long charUuidMsb,
803            boolean isNotify, byte[] data) throws RemoteException {
804        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
805        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
806
807        if (VDBG) Log.d(TAG, "onNotify() - address=" + address
808            + ", charUuid=" + charUuid + ", length=" + data.length);
809
810        ClientMap.App app = mClientMap.getByConnId(connId);
811        if (app != null) {
812            app.callback.onNotify(address, srvcType,
813                        srvcInstId, new ParcelUuid(srvcUuid),
814                        charInstId, new ParcelUuid(charUuid),
815                        data);
816        }
817    }
818
819    void onReadCharacteristic(int connId, int status, int srvcType,
820            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
821            int charInstId, long charUuidLsb, long charUuidMsb,
822            int charType, byte[] data) throws RemoteException {
823
824        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
825        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
826        String address = mClientMap.addressByConnId(connId);
827
828        if (VDBG) Log.d(TAG, "onReadCharacteristic() - address=" + address
829            + ", status=" + status + ", length=" + data.length);
830
831        ClientMap.App app = mClientMap.getByConnId(connId);
832        if (app != null) {
833            app.callback.onCharacteristicRead(address, status, srvcType,
834                        srvcInstId, new ParcelUuid(srvcUuid),
835                        charInstId, new ParcelUuid(charUuid), data);
836        }
837    }
838
839    void onWriteCharacteristic(int connId, int status, int srvcType,
840            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
841            int charInstId, long charUuidLsb, long charUuidMsb)
842            throws RemoteException {
843
844        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
845        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
846        String address = mClientMap.addressByConnId(connId);
847
848        if (VDBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address
849            + ", status=" + status);
850
851        ClientMap.App app = mClientMap.getByConnId(connId);
852        if (app != null) {
853            app.callback.onCharacteristicWrite(address, status, srvcType,
854                        srvcInstId, new ParcelUuid(srvcUuid),
855                        charInstId, new ParcelUuid(charUuid));
856        }
857    }
858
859    void onExecuteCompleted(int connId, int status) throws RemoteException {
860        String address = mClientMap.addressByConnId(connId);
861        if (VDBG) Log.d(TAG, "onExecuteCompleted() - address=" + address
862            + ", status=" + status);
863
864        ClientMap.App app = mClientMap.getByConnId(connId);
865        if (app != null) {
866            app.callback.onExecuteWrite(address, status);
867        }
868    }
869
870    void onReadDescriptor(int connId, int status, int srvcType,
871            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
872            int charInstId, long charUuidLsb, long charUuidMsb,
873            int descrInstId, long descrUuidLsb, long descrUuidMsb,
874            int charType, byte[] data) throws RemoteException {
875
876        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
877        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
878        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
879        String address = mClientMap.addressByConnId(connId);
880
881        if (VDBG) Log.d(TAG, "onReadDescriptor() - address=" + address
882            + ", status=" + status + ", length=" + data.length);
883
884        ClientMap.App app = mClientMap.getByConnId(connId);
885        if (app != null) {
886            app.callback.onDescriptorRead(address, status, srvcType,
887                        srvcInstId, new ParcelUuid(srvcUuid),
888                        charInstId, new ParcelUuid(charUuid),
889                        descrInstId, new ParcelUuid(descrUuid), data);
890        }
891    }
892
893    void onWriteDescriptor(int connId, int status, int srvcType,
894            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
895            int charInstId, long charUuidLsb, long charUuidMsb,
896            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
897
898        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
899        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
900        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
901        String address = mClientMap.addressByConnId(connId);
902
903        if (VDBG) Log.d(TAG, "onWriteDescriptor() - address=" + address
904            + ", status=" + status);
905
906        ClientMap.App app = mClientMap.getByConnId(connId);
907        if (app != null) {
908            app.callback.onDescriptorWrite(address, status, srvcType,
909                        srvcInstId, new ParcelUuid(srvcUuid),
910                        charInstId, new ParcelUuid(charUuid),
911                        descrInstId, new ParcelUuid(descrUuid));
912        }
913    }
914
915    void onReadRemoteRssi(int clientIf, String address,
916                    int rssi, int status) throws RemoteException{
917        if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" +
918                     address + ", rssi=" + rssi + ", status=" + status);
919
920        ClientMap.App app = mClientMap.getById(clientIf);
921        if (app != null) {
922            app.callback.onReadRemoteRssi(address, rssi, status);
923        }
924    }
925
926    void onScanFilterEnableDisabled(int action, int status, int clientIf) {
927        if (DBG) {
928            Log.d(TAG, "onScanFilterEnableDisabled() - clientIf=" + clientIf + ", status=" + status
929                    + ", action=" + action);
930        }
931        mScanManager.callbackDone(clientIf, status);
932    }
933
934    void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) {
935        if (DBG) {
936            Log.d(TAG, "onScanFilterParamsConfigured() - clientIf=" + clientIf
937                    + ", status=" + status + ", action=" + action
938                    + ", availableSpace=" + availableSpace);
939        }
940        mScanManager.callbackDone(clientIf, status);
941    }
942
943    void onScanFilterConfig(int action, int status, int clientIf, int filterType,
944            int availableSpace) {
945        if (DBG) {
946            Log.d(TAG, "onScanFilterConfig() - clientIf=" + clientIf + ", action = " + action
947                    + " status = " + status + ", filterType=" + filterType
948                    + ", availableSpace=" + availableSpace);
949        }
950
951        mScanManager.callbackDone(clientIf, status);
952    }
953
954    void onBatchScanStorageConfigured(int status, int clientIf) {
955        if (DBG) {
956            Log.d(TAG, "onBatchScanStorageConfigured() - clientIf="+ clientIf + ", status=" + status);
957        }
958        mScanManager.callbackDone(clientIf, status);
959    }
960
961    // TODO: split into two different callbacks : onBatchScanStarted and onBatchScanStopped.
962    void onBatchScanStartStopped(int startStopAction, int status, int clientIf) {
963        if (DBG) {
964            Log.d(TAG, "onBatchScanStartStopped() - clientIf=" + clientIf
965                    + ", status=" + status + ", startStopAction=" + startStopAction);
966        }
967        mScanManager.callbackDone(clientIf, status);
968    }
969
970    void onBatchScanReports(int status, int clientIf, int reportType, int numRecords,
971            byte[] recordData) throws RemoteException {
972        if (DBG) {
973            Log.d(TAG, "onBatchScanReports() - clientIf=" + clientIf + ", status=" + status
974                    + ", reportType=" + reportType + ", numRecords=" + numRecords);
975        }
976        mScanManager.callbackDone(clientIf, status);
977        Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData);
978        if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
979            // We only support single client for truncated mode.
980            ClientMap.App app = mClientMap.getById(clientIf);
981            if (app == null) return;
982            app.callback.onBatchScanResults(new ArrayList<ScanResult>(results));
983        } else {
984            for (ScanClient client : mScanManager.getFullBatchScanQueue()) {
985                // Deliver results for each client.
986                deliverBatchScan(client, results);
987            }
988        }
989    }
990
991    // Check and deliver scan results for different scan clients.
992    private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults) throws
993            RemoteException {
994        ClientMap.App app = mClientMap.getById(client.clientIf);
995        if (app == null) return;
996        if (client.filters == null || client.filters.isEmpty()) {
997            app.callback.onBatchScanResults(new ArrayList<ScanResult>(allResults));
998        }
999        // Reconstruct the scan results.
1000        List<ScanResult> results = new ArrayList<ScanResult>();
1001        for (ScanResult scanResult : allResults) {
1002            if (matchesFilters(client, scanResult)) {
1003                results.add(scanResult);
1004            }
1005        }
1006        app.callback.onBatchScanResults(results);
1007    }
1008
1009    private Set<ScanResult> parseBatchScanResults(int numRecords, int reportType,
1010            byte[] batchRecord) {
1011        if (numRecords == 0) {
1012            return Collections.emptySet();
1013        }
1014        if (DBG) Log.d(TAG, "current time is " + SystemClock.elapsedRealtimeNanos());
1015        if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
1016            return parseTruncatedResults(numRecords, batchRecord);
1017        } else {
1018            return parseFullResults(numRecords, batchRecord);
1019        }
1020    }
1021
1022    private Set<ScanResult> parseTruncatedResults(int numRecords, byte[] batchRecord) {
1023        if (DBG) Log.d(TAG, "batch record " + Arrays.toString(batchRecord));
1024        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
1025        for (int i = 0; i < numRecords; ++i) {
1026            byte[] record = extractBytes(batchRecord, i * TRUNCATED_RESULT_SIZE,
1027                    TRUNCATED_RESULT_SIZE);
1028            byte[] address = extractBytes(record, 0, 6);
1029            // TODO: remove temp hack.
1030            reverse(address);
1031            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1032            int rssi = record[8];
1033            // Timestamp is in every 50 ms.
1034            long timestampNanos = parseTimestampNanos(extractBytes(record, 9, 2));
1035            results.add(new ScanResult(device, ScanRecord.parseFromBytes(new byte[0]),
1036                    rssi, timestampNanos));
1037        }
1038        return results;
1039    }
1040
1041    private long parseTimestampNanos(byte[] data) {
1042        long timestampUnit = data[1] & 0xFF << 8 + data[0];
1043        long timestampNanos = SystemClock.elapsedRealtimeNanos() -
1044                TimeUnit.MILLISECONDS.toNanos(timestampUnit * 50);
1045        return timestampNanos;
1046    }
1047
1048    private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) {
1049        Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord));
1050        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
1051        int position = 0;
1052        while (position < batchRecord.length) {
1053            byte[] address = extractBytes(batchRecord, position, 6);
1054            // TODO: remove temp hack.
1055            reverse(address);
1056            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1057            position += 6;
1058            // Skip address type.
1059            position++;
1060            // Skip tx power level.
1061            position++;
1062            int rssi = batchRecord[position++];
1063            long timestampNanos = parseTimestampNanos(extractBytes(batchRecord, position, 2));
1064            position += 2;
1065
1066            // Combine advertise packet and scan response packet.
1067            int advertisePacketLen = batchRecord[position++];
1068            byte[] advertiseBytes = extractBytes(batchRecord, position, advertisePacketLen);
1069            position += advertisePacketLen;
1070            int scanResponsePacketLen = batchRecord[position++];
1071            byte[] scanResponseBytes = extractBytes(batchRecord, position, scanResponsePacketLen);
1072            position += scanResponsePacketLen;
1073            byte[] scanRecord = new byte[advertisePacketLen + scanResponsePacketLen];
1074            System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen);
1075            System.arraycopy(scanResponseBytes, 0, scanRecord,
1076                    advertisePacketLen, scanResponsePacketLen);
1077            Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord));
1078            results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord),
1079                    rssi, timestampNanos));
1080        }
1081        return results;
1082    }
1083
1084    // Reverse byte array.
1085    private void reverse(byte[] address) {
1086        int len = address.length;
1087        for (int i = 0; i < len / 2; ++i) {
1088            byte b = address[i];
1089            address[i] = address[len - 1 - i];
1090            address[len - 1 - i] = b;
1091        }
1092    }
1093
1094    // Helper method to extract bytes from byte array.
1095    private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
1096        byte[] bytes = new byte[length];
1097        System.arraycopy(scanRecord, start, bytes, 0, length);
1098        return bytes;
1099    }
1100
1101    void onBatchScanThresholdCrossed(int clientIf) {
1102        if (DBG) {
1103            Log.d(TAG, "onBatchScanThresholdCrossed() - clientIf=" + clientIf);
1104        }
1105        boolean isServer = false;
1106        flushPendingBatchResults(clientIf, isServer);
1107    }
1108
1109    void onTrackAdvFoundLost(int filterIndex, int addrType, String address, int advState,
1110            int clientIf) throws RemoteException {
1111        if (DBG) Log.d(TAG, "onClientAdvertiserFoundLost() - clientIf="
1112                + clientIf + "address = " + address + "adv_state = "
1113                + advState + "client_if = " + clientIf);
1114        ClientMap.App app = mClientMap.getById(clientIf);
1115        if (app == null || app.callback == null) {
1116            Log.e(TAG, "app or callback is null");
1117            return;
1118        }
1119
1120        // use hw signal for only onlost reporting
1121        if (advState != ADVT_STATE_ONLOST) {
1122            return;
1123        }
1124
1125        for (ScanClient client : mScanManager.getRegularScanQueue()) {
1126            if (client.clientIf == clientIf) {
1127                ScanSettings settings = client.settings;
1128                if ((settings.getCallbackType() &
1129                            ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
1130
1131                    while (!mOnFoundResults.isEmpty()) {
1132                        ScanResult result = mOnFoundResults.get(client);
1133                        app.callback.onFoundOrLost(false, result);
1134                        synchronized (mOnFoundResults) {
1135                            mOnFoundResults.remove(client);
1136                        }
1137                    }
1138                }
1139            }
1140        }
1141    }
1142
1143    // callback from AdvertiseManager for advertise status dispatch.
1144    void onMultipleAdvertiseCallback(int clientIf, int status, boolean isStart,
1145            AdvertiseSettings settings) throws RemoteException {
1146        ClientMap.App app = mClientMap.getById(clientIf);
1147        if (app == null || app.callback == null) {
1148            Log.e(TAG, "Advertise app or callback is null");
1149            return;
1150        }
1151        app.callback.onMultiAdvertiseCallback(status, isStart, settings);
1152    }
1153
1154    void onConfigureMTU(int connId, int status, int mtu) throws RemoteException {
1155        String address = mClientMap.addressByConnId(connId);
1156
1157        if (DBG) Log.d(TAG, "onConfigureMTU() address=" + address + ", status="
1158            + status + ", mtu=" + mtu);
1159
1160        ClientMap.App app = mClientMap.getByConnId(connId);
1161        if (app != null) {
1162            app.callback.onConfigureMTU(address, mtu, status);
1163        }
1164    }
1165
1166    // Callback for standard advertising instance.
1167    void onAdvertiseCallback(int status, int clientIf) {
1168        if (DBG) Log.d(TAG, "onAdvertiseCallback,- clientIf=" + clientIf + ", status=" + status);
1169    }
1170
1171    // Followings are callbacks for Bluetooth LE Advertise operations.
1172    // Start advertising flow is
1173    //     enable advertising instance -> onAdvertiseInstaceEnabled
1174    // ->  set advertise data          -> onAdvertiseDataSet
1175    // ->  set scan response           -> onAdvertiseDataSet
1176
1177    // Callback when advertise instance is enabled.
1178    void onAdvertiseInstanceEnabled(int status, int clientIf) {
1179        if (DBG) Log.d(TAG, "onAdvertiseInstanceEnabled() - "
1180                + "clientIf=" + clientIf + ", status=" + status);
1181        mAdvertiseManager.callbackDone(clientIf, status);
1182    }
1183
1184    // Not really used.
1185    void onAdvertiseDataUpdated(int status, int client_if) {
1186        if (DBG) Log.d(TAG, "onAdvertiseDataUpdated() - client_if=" + client_if
1187            + ", status=" + status);
1188    }
1189
1190    // Callback when advertise data or scan response is set.
1191    void onAdvertiseDataSet(int status, int clientIf) {
1192        if (DBG) Log.d(TAG, "onAdvertiseDataSet() - clientIf=" + clientIf
1193            + ", status=" + status);
1194        mAdvertiseManager.callbackDone(clientIf, status);
1195    }
1196
1197    // Callback when advertise instance is disabled
1198    void onAdvertiseInstanceDisabled(int status, int clientIf) throws RemoteException {
1199        if (DBG) Log.d(TAG, "onAdvertiseInstanceDisabled() - clientIf=" + clientIf
1200            + ", status=" + status);
1201        ClientMap.App app = mClientMap.getById(clientIf);
1202        if (app != null) {
1203            Log.d(TAG, "Client app is not null!");
1204            boolean isStart = false;
1205            if (status == 0) {
1206                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.ADVERTISE_SUCCESS,
1207                        isStart, null);
1208            } else {
1209                app.callback.onMultiAdvertiseCallback(
1210                        AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR, isStart, null);
1211            }
1212        }
1213    }
1214
1215    void onClientCongestion(int connId, boolean congested) throws RemoteException {
1216        if (DBG) Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested);
1217
1218        ClientMap.App app = mClientMap.getByConnId(connId);
1219        if (app != null) {
1220            app.callback.onConnectionCongested(mClientMap.addressByConnId(connId), congested);
1221        }
1222    }
1223
1224    /**************************************************************************
1225     * GATT Service functions - Shared CLIENT/SERVER
1226     *************************************************************************/
1227
1228    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
1229        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1230
1231        final int DEVICE_TYPE_BREDR = 0x1;
1232
1233        Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice,
1234                                                                 Integer>();
1235
1236        // Add paired LE devices
1237
1238        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
1239        for (BluetoothDevice device : bondedDevices) {
1240            if (getDeviceType(device) != DEVICE_TYPE_BREDR) {
1241                deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
1242            }
1243        }
1244
1245        // Add connected deviceStates
1246
1247        Set<String> connectedDevices = new HashSet<String>();
1248        connectedDevices.addAll(mClientMap.getConnectedDevices());
1249        connectedDevices.addAll(mServerMap.getConnectedDevices());
1250
1251        for (String address : connectedDevices ) {
1252            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1253            if (device != null) {
1254                deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
1255            }
1256        }
1257
1258        // Create matching device sub-set
1259
1260        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
1261
1262        for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
1263            for(int state : states) {
1264                if (entry.getValue() == state) {
1265                    deviceList.add(entry.getKey());
1266                }
1267            }
1268        }
1269
1270        return deviceList;
1271    }
1272
1273    void startScan(int appIf, boolean isServer, ScanSettings settings,
1274            List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages) {
1275        if (DBG) Log.d(TAG, "start scan with filters");
1276        enforceAdminPermission();
1277        mScanManager.startScan(new ScanClient(appIf, isServer, settings, filters, storages));
1278    }
1279
1280    void flushPendingBatchResults(int clientIf, boolean isServer) {
1281        if (DBG) Log.d(TAG, "flushPendingBatchResults - clientIf=" + clientIf +
1282                ", isServer=" + isServer);
1283        mScanManager.flushBatchScanResults(new ScanClient(clientIf, isServer));
1284    }
1285
1286    void stopScan(ScanClient client) {
1287        enforceAdminPermission();
1288        int scanQueueSize = mScanManager.getBatchScanQueue().size() +
1289                mScanManager.getRegularScanQueue().size();
1290        if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize);
1291        mScanManager.stopScan(client);
1292    }
1293
1294    /**************************************************************************
1295     * GATT Service functions - CLIENT
1296     *************************************************************************/
1297
1298    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
1299        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1300
1301        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1302        mClientMap.add(uuid, callback);
1303        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1304                                    uuid.getMostSignificantBits());
1305    }
1306
1307    void unregisterClient(int clientIf) {
1308        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1309
1310        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1311        mClientMap.remove(clientIf);
1312        gattClientUnregisterAppNative(clientIf);
1313    }
1314
1315    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1316        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1317
1318        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1319        gattClientConnectNative(clientIf, address, isDirect, transport);
1320    }
1321
1322    void clientDisconnect(int clientIf, String address) {
1323        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1324
1325        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1326        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1327
1328        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1329    }
1330
1331    void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,
1332            AdvertiseData scanResponse, AdvertiseSettings settings) {
1333        enforceAdminPermission();
1334        mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData,
1335                scanResponse));
1336    }
1337
1338    void stopMultiAdvertising(AdvertiseClient client) {
1339        enforceAdminPermission();
1340        mAdvertiseManager.stopAdvertising(client);
1341    }
1342
1343
1344    synchronized List<ParcelUuid> getRegisteredServiceUuids() {
1345        Utils.enforceAdminPermission(this);
1346        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1347        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1348            serviceUuids.add(new ParcelUuid(entry.uuid));
1349        }
1350        return serviceUuids;
1351    }
1352
1353    List<String> getConnectedDevices() {
1354        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1355
1356        Set<String> connectedDevAddress = new HashSet<String>();
1357        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1358        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1359        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1360        return connectedDeviceList;
1361    }
1362
1363    void refreshDevice(int clientIf, String address) {
1364        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1365
1366        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1367        gattClientRefreshNative(clientIf, address);
1368    }
1369
1370    void discoverServices(int clientIf, String address) {
1371        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1372
1373        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1374        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1375
1376        if (connId != null)
1377            gattClientSearchServiceNative(connId, true, 0, 0);
1378        else
1379            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1380    }
1381
1382    void readCharacteristic(int clientIf, String address, int srvcType,
1383                            int srvcInstanceId, UUID srvcUuid,
1384                            int charInstanceId, UUID charUuid, int authReq) {
1385        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1386
1387        if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1388
1389        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1390        if (connId != null)
1391            gattClientReadCharacteristicNative(connId, srvcType,
1392                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1393                srvcUuid.getMostSignificantBits(), charInstanceId,
1394                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1395                authReq);
1396        else
1397            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1398    }
1399
1400    void writeCharacteristic(int clientIf, String address, int srvcType,
1401                             int srvcInstanceId, UUID srvcUuid,
1402                             int charInstanceId, UUID charUuid, int writeType,
1403                             int authReq, byte[] value) {
1404        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1405
1406        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1407
1408        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1409
1410        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1411        if (connId != null)
1412            gattClientWriteCharacteristicNative(connId, srvcType,
1413                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1414                srvcUuid.getMostSignificantBits(), charInstanceId,
1415                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1416                writeType, authReq, value);
1417        else
1418            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1419    }
1420
1421    void readDescriptor(int clientIf, String address, int srvcType,
1422                            int srvcInstanceId, UUID srvcUuid,
1423                            int charInstanceId, UUID charUuid,
1424                            int descrInstanceId, UUID descrUuid,
1425                            int authReq) {
1426        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1427
1428        if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address);
1429
1430        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1431        if (connId != null)
1432            gattClientReadDescriptorNative(connId, srvcType,
1433                srvcInstanceId,
1434                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1435                charInstanceId,
1436                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1437                descrInstanceId,
1438                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1439                authReq);
1440        else
1441            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1442    };
1443
1444    void writeDescriptor(int clientIf, String address, int srvcType,
1445                            int srvcInstanceId, UUID srvcUuid,
1446                            int charInstanceId, UUID charUuid,
1447                            int descrInstanceId, UUID descrUuid,
1448                            int writeType, int authReq, byte[] value) {
1449        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1450
1451        if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1452
1453        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1454        if (connId != null)
1455            gattClientWriteDescriptorNative(connId, srvcType,
1456                srvcInstanceId,
1457                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1458                charInstanceId,
1459                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1460                descrInstanceId,
1461                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1462                writeType, authReq, value);
1463        else
1464            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1465    }
1466
1467    void beginReliableWrite(int clientIf, String address) {
1468        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1469
1470        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1471        mReliableQueue.add(address);
1472    }
1473
1474    void endReliableWrite(int clientIf, String address, boolean execute) {
1475        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1476
1477        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1478                                + " execute: " + execute);
1479        mReliableQueue.remove(address);
1480
1481        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1482        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1483    }
1484
1485    void registerForNotification(int clientIf, String address, int srvcType,
1486                int srvcInstanceId, UUID srvcUuid,
1487                int charInstanceId, UUID charUuid,
1488                boolean enable) {
1489        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1490
1491        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1492
1493        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1494        if (connId != null) {
1495            gattClientRegisterForNotificationsNative(clientIf, address,
1496                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1497                srvcUuid.getMostSignificantBits(), charInstanceId,
1498                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1499                enable);
1500        } else {
1501            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1502        }
1503    }
1504
1505    void readRemoteRssi(int clientIf, String address) {
1506        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1507
1508        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1509        gattClientReadRemoteRssiNative(clientIf, address);
1510    }
1511
1512    void configureMTU(int clientIf, String address, int mtu) {
1513        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1514
1515        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1516        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1517        if (connId != null) {
1518            gattClientConfigureMTUNative(connId, mtu);
1519        } else {
1520            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1521        }
1522    }
1523
1524    void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
1525        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1526
1527        // Default spec recommended interval is 30->50 ms
1528        int minInterval = 24; // 24 * 1.25ms = 30ms
1529        int maxInterval = 40; // 40 * 1.25ms = 50ms
1530
1531        // Slave latency
1532        int latency = 0;
1533
1534        // Link supervision timeout is measured in N * 10ms
1535        int timeout = 2000; // 20s
1536
1537        switch (connectionPriority)
1538        {
1539            case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
1540                minInterval = 6; // 7.5ms
1541                maxInterval = 8; // 10ms
1542                break;
1543
1544            case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
1545                minInterval = 80; // 100ms
1546                maxInterval = 100; // 125ms
1547                latency = 2;
1548                break;
1549        }
1550
1551        if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address
1552            + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
1553        gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
1554                                            latency, timeout);
1555    }
1556
1557    /**************************************************************************
1558     * Callback functions - SERVER
1559     *************************************************************************/
1560
1561    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1562            throws RemoteException {
1563
1564        UUID uuid = new UUID(uuidMsb, uuidLsb);
1565        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1566        ServerMap.App app = mServerMap.getByUuid(uuid);
1567        if (app != null) {
1568            app.id = serverIf;
1569            app.linkToDeath(new ServerDeathRecipient(serverIf));
1570            app.callback.onServerRegistered(status, serverIf);
1571        }
1572    }
1573
1574    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1575                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1576                        throws RemoteException {
1577        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1578        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1579            + ", handle=" + srvcHandle);
1580        if (status == 0) {
1581            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1582                mAdvertisingServiceUuids.remove(uuid));
1583        }
1584
1585        continueServiceDeclaration(serverIf, status, srvcHandle);
1586    }
1587
1588    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1589                                int includedSrvcHandle) throws RemoteException {
1590        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1591            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1592        continueServiceDeclaration(serverIf, status, srvcHandle);
1593    }
1594
1595    void onCharacteristicAdded(int status, int serverIf,
1596                               long charUuidLsb, long charUuidMsb,
1597                               int srvcHandle, int charHandle)
1598                               throws RemoteException {
1599            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1600        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1601            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1602        if (status == 0)
1603            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1604        continueServiceDeclaration(serverIf, status, srvcHandle);
1605    }
1606
1607    void onDescriptorAdded(int status, int serverIf,
1608                           long descrUuidLsb, long descrUuidMsb,
1609                           int srvcHandle, int descrHandle)
1610                           throws RemoteException {
1611            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1612        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1613            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1614        if (status == 0)
1615            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1616        continueServiceDeclaration(serverIf, status, srvcHandle);
1617    }
1618
1619    void onServiceStarted(int status, int serverIf, int srvcHandle)
1620            throws RemoteException {
1621        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1622            + ", status=" + status);
1623        if (status == 0)
1624            mHandleMap.setStarted(serverIf, srvcHandle, true);
1625    }
1626
1627    void onServiceStopped(int status, int serverIf, int srvcHandle)
1628            throws RemoteException {
1629        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1630            + ", status=" + status);
1631        if (status == 0)
1632            mHandleMap.setStarted(serverIf, srvcHandle, false);
1633        stopNextService(serverIf, status);
1634    }
1635
1636    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1637        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1638            + ", status=" + status);
1639        mHandleMap.deleteService(serverIf, srvcHandle);
1640    }
1641
1642    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1643            throws RemoteException {
1644
1645        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1646            + ", address=" + address + ", connected=" + connected);
1647
1648        ServerMap.App app = mServerMap.getById(serverIf);
1649        if (app == null) return;
1650
1651        if (connected) {
1652            mServerMap.addConnection(serverIf, connId, address);
1653        } else {
1654            mServerMap.removeConnection(serverIf, connId);
1655        }
1656
1657        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1658    }
1659
1660    void onAttributeRead(String address, int connId, int transId,
1661                            int attrHandle, int offset, boolean isLong)
1662                            throws RemoteException {
1663        if (VDBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1664            + ", address=" + address + ", handle=" + attrHandle
1665            + ", requestId=" + transId + ", offset=" + offset);
1666
1667        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1668        if (entry == null) return;
1669
1670        if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid
1671            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1672
1673        mHandleMap.addRequest(transId, attrHandle);
1674
1675        ServerMap.App app = mServerMap.getById(entry.serverIf);
1676        if (app == null) return;
1677
1678        switch(entry.type) {
1679            case HandleMap.TYPE_CHARACTERISTIC:
1680            {
1681                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1682                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1683                    serviceEntry.serviceType, serviceEntry.instance,
1684                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1685                    new ParcelUuid(entry.uuid));
1686                break;
1687            }
1688
1689            case HandleMap.TYPE_DESCRIPTOR:
1690            {
1691                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1692                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1693                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1694                    serviceEntry.serviceType, serviceEntry.instance,
1695                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1696                    new ParcelUuid(charEntry.uuid),
1697                    new ParcelUuid(entry.uuid));
1698                break;
1699            }
1700
1701            default:
1702                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1703                break;
1704        }
1705    }
1706
1707    void onAttributeWrite(String address, int connId, int transId,
1708                            int attrHandle, int offset, int length,
1709                            boolean needRsp, boolean isPrep,
1710                            byte[] data)
1711                            throws RemoteException {
1712        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1713            + ", address=" + address + ", handle=" + attrHandle
1714            + ", requestId=" + transId + ", isPrep=" + isPrep
1715            + ", offset=" + offset);
1716
1717        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1718        if (entry == null) return;
1719
1720        if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid
1721            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1722
1723        mHandleMap.addRequest(transId, attrHandle);
1724
1725        ServerMap.App app = mServerMap.getById(entry.serverIf);
1726        if (app == null) return;
1727
1728        switch(entry.type) {
1729            case HandleMap.TYPE_CHARACTERISTIC:
1730            {
1731                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1732                app.callback.onCharacteristicWriteRequest(address, transId,
1733                            offset, length, isPrep, needRsp,
1734                            serviceEntry.serviceType, serviceEntry.instance,
1735                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1736                            new ParcelUuid(entry.uuid), data);
1737                break;
1738            }
1739
1740            case HandleMap.TYPE_DESCRIPTOR:
1741            {
1742                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1743                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1744                app.callback.onDescriptorWriteRequest(address, transId,
1745                            offset, length, isPrep, needRsp,
1746                            serviceEntry.serviceType, serviceEntry.instance,
1747                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1748                            new ParcelUuid(charEntry.uuid),
1749                            new ParcelUuid(entry.uuid), data);
1750                break;
1751            }
1752
1753            default:
1754                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1755                break;
1756        }
1757    }
1758
1759    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1760            throws RemoteException {
1761        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1762            + ", address=" + address + ", transId=" + transId);
1763
1764        ServerMap.App app = mServerMap.getByConnId(connId);
1765        if (app == null) return;
1766
1767        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1768    }
1769
1770    void onResponseSendCompleted(int status, int attrHandle) {
1771        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1772    }
1773
1774    void onNotificationSent(int connId, int status) throws RemoteException {
1775        if (DBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
1776
1777        String address = mServerMap.addressByConnId(connId);
1778        if (address == null) return;
1779
1780        ServerMap.App app = mServerMap.getByConnId(connId);
1781        if (app == null) return;
1782
1783        app.callback.onNotificationSent(address, status);
1784    }
1785
1786    void onServerCongestion(int connId, boolean congested) throws RemoteException {
1787        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
1788
1789        ServerMap.App app = mServerMap.getByConnId(connId);
1790        if (app != null) {
1791            app.callback.onConnectionCongested(mServerMap.addressByConnId(connId), congested);
1792        }
1793    }
1794
1795    /**************************************************************************
1796     * GATT Service functions - SERVER
1797     *************************************************************************/
1798
1799    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1800        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1801
1802        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1803        mServerMap.add(uuid, callback);
1804        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1805                                    uuid.getMostSignificantBits());
1806    }
1807
1808    void unregisterServer(int serverIf) {
1809        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1810
1811        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1812
1813        deleteServices(serverIf);
1814
1815        mServerMap.remove(serverIf);
1816        gattServerUnregisterAppNative(serverIf);
1817    }
1818
1819    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1820        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1821
1822        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1823        gattServerConnectNative(serverIf, address, isDirect,transport);
1824    }
1825
1826    void serverDisconnect(int serverIf, String address) {
1827        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1828
1829        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1830        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1831
1832        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1833    }
1834
1835    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1836                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1837        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1838
1839        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1840        ServiceDeclaration serviceDeclaration = addDeclaration();
1841        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1842            advertisePreferred);
1843    }
1844
1845    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1846                            UUID srvcUuid) {
1847        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1848
1849        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1850        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1851    }
1852
1853    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1854                           int permissions) {
1855        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1856
1857        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1858        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1859    }
1860
1861    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1862        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1863
1864        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1865        getActiveDeclaration().addDescriptor(descUuid, permissions);
1866    }
1867
1868    void endServiceDeclaration(int serverIf) {
1869        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1870
1871        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1872
1873        if (getActiveDeclaration() == getPendingDeclaration()) {
1874            try {
1875                continueServiceDeclaration(serverIf, (byte)0, 0);
1876            } catch (RemoteException e) {
1877                Log.e(TAG,""+e);
1878            }
1879        }
1880    }
1881
1882    void removeService(int serverIf, int srvcType,
1883                  int srvcInstanceId, UUID srvcUuid) {
1884        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1885
1886        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
1887
1888        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1889        if (srvcHandle == 0) return;
1890        gattServerDeleteServiceNative(serverIf, srvcHandle);
1891    }
1892
1893    void clearServices(int serverIf) {
1894        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1895
1896        if (DBG) Log.d(TAG, "clearServices()");
1897        deleteServices(serverIf);
1898    }
1899
1900    void sendResponse(int serverIf, String address, int requestId,
1901                      int status, int offset, byte[] value) {
1902        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1903
1904        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
1905
1906        int handle = 0;
1907        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
1908        if (entry != null) handle = entry.handle;
1909
1910        int connId = mServerMap.connIdByAddress(serverIf, address);
1911        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
1912                                     handle, offset, value, (byte)0);
1913        mHandleMap.deleteRequest(requestId);
1914    }
1915
1916    void sendNotification(int serverIf, String address, int srvcType,
1917                                 int srvcInstanceId, UUID srvcUuid,
1918                                 int charInstanceId, UUID charUuid,
1919                                 boolean confirm, byte[] value) {
1920        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1921
1922        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address);
1923
1924        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1925        if (srvcHandle == 0) return;
1926
1927        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
1928        if (charHandle == 0) return;
1929
1930        int connId = mServerMap.connIdByAddress(serverIf, address);
1931        if (connId == 0) return;
1932
1933        if (confirm) {
1934            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
1935        } else {
1936            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
1937        }
1938    }
1939
1940
1941    /**************************************************************************
1942     * Private functions
1943     *************************************************************************/
1944
1945    private int getDeviceType(BluetoothDevice device) {
1946        int type = gattClientGetDeviceTypeNative(device.getAddress());
1947        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
1948            + ", type=" + type);
1949        return type;
1950    }
1951
1952    private void enforceAdminPermission() {
1953        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1954    }
1955
1956    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
1957    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
1958    private void enforcePrivilegedPermission() {
1959        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
1960            "Need BLUETOOTH_PRIVILEGED permission");
1961    }
1962
1963    private void continueSearch(int connId, int status) throws RemoteException {
1964        if (status == 0 && !mSearchQueue.isEmpty()) {
1965            SearchQueue.Entry svc = mSearchQueue.pop();
1966
1967            if (svc.charUuidLsb == 0) {
1968                // Characteristic is up next
1969                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
1970                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
1971            } else {
1972                // Descriptor is up next
1973                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
1974                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
1975                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
1976            }
1977        } else {
1978            ClientMap.App app = mClientMap.getByConnId(connId);
1979            if (app != null) {
1980                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
1981            }
1982        }
1983    }
1984
1985    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
1986        if (mServiceDeclarations.size() == 0) return;
1987        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
1988
1989        boolean finished = false;
1990
1991        ServiceDeclaration.Entry entry = null;
1992        if (status == 0)
1993            entry = getPendingDeclaration().getNext();
1994
1995        if (entry != null) {
1996            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
1997                + entry.type);
1998            switch(entry.type) {
1999                case ServiceDeclaration.TYPE_SERVICE:
2000                    if (entry.advertisePreferred) {
2001                        mAdvertisingServiceUuids.add(entry.uuid);
2002                    }
2003                    gattServerAddServiceNative(serverIf, entry.serviceType,
2004                        entry.instance,
2005                        entry.uuid.getLeastSignificantBits(),
2006                        entry.uuid.getMostSignificantBits(),
2007                        getPendingDeclaration().getNumHandles());
2008                    break;
2009
2010                case ServiceDeclaration.TYPE_CHARACTERISTIC:
2011                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
2012                        entry.uuid.getLeastSignificantBits(),
2013                        entry.uuid.getMostSignificantBits(),
2014                        entry.properties, entry.permissions);
2015                    break;
2016
2017                case ServiceDeclaration.TYPE_DESCRIPTOR:
2018                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2019                        entry.uuid.getLeastSignificantBits(),
2020                        entry.uuid.getMostSignificantBits(),
2021                        entry.permissions);
2022                    break;
2023
2024                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2025                {
2026                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2027                                            entry.serviceType, entry.instance);
2028                    if (inclSrvc != 0) {
2029                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2030                                                           inclSrvc);
2031                    } else {
2032                        finished = true;
2033                    }
2034                    break;
2035                }
2036            }
2037        } else {
2038            gattServerStartServiceNative(serverIf, srvcHandle,
2039                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2040            finished = true;
2041        }
2042
2043        if (finished) {
2044            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2045            ServerMap.App app = mServerMap.getById(serverIf);
2046            if (app != null) {
2047                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2048
2049                if (serviceEntry != null) {
2050                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2051                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2052                } else {
2053                    app.callback.onServiceAdded(status, 0, 0, null);
2054                }
2055            }
2056            removePendingDeclaration();
2057
2058            if (getPendingDeclaration() != null) {
2059                continueServiceDeclaration(serverIf, (byte)0, 0);
2060            }
2061        }
2062    }
2063
2064    private void stopNextService(int serverIf, int status) throws RemoteException {
2065        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2066            + ", status=" + status);
2067
2068        if (status == 0) {
2069            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2070            for(HandleMap.Entry entry : entries) {
2071                if (entry.type != HandleMap.TYPE_SERVICE ||
2072                    entry.serverIf != serverIf ||
2073                    entry.started == false)
2074                        continue;
2075
2076                gattServerStopServiceNative(serverIf, entry.handle);
2077                return;
2078            }
2079        }
2080    }
2081
2082    private void deleteServices(int serverIf) {
2083        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2084
2085        /*
2086         * Figure out which handles to delete.
2087         * The handles are copied into a new list to avoid race conditions.
2088         */
2089        List<Integer> handleList = new ArrayList<Integer>();
2090        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2091        for(HandleMap.Entry entry : entries) {
2092            if (entry.type != HandleMap.TYPE_SERVICE ||
2093                entry.serverIf != serverIf)
2094                    continue;
2095            handleList.add(entry.handle);
2096        }
2097
2098        /* Now actually delete the services.... */
2099        for(Integer handle : handleList) {
2100            gattServerDeleteServiceNative(serverIf, handle);
2101        }
2102    }
2103
2104    private List<UUID> parseUuids(byte[] adv_data) {
2105        List<UUID> uuids = new ArrayList<UUID>();
2106
2107        int offset = 0;
2108        while(offset < (adv_data.length-2)) {
2109            int len = adv_data[offset++];
2110            if (len == 0) break;
2111
2112            int type = adv_data[offset++];
2113            switch (type) {
2114                case 0x02: // Partial list of 16-bit UUIDs
2115                case 0x03: // Complete list of 16-bit UUIDs
2116                    while (len > 1) {
2117                        int uuid16 = adv_data[offset++];
2118                        uuid16 += (adv_data[offset++] << 8);
2119                        len -= 2;
2120                        uuids.add(UUID.fromString(String.format(
2121                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2122                    }
2123                    break;
2124
2125                default:
2126                    offset += (len - 1);
2127                    break;
2128            }
2129        }
2130
2131        return uuids;
2132    }
2133
2134    /**************************************************************************
2135     * GATT Test functions
2136     *************************************************************************/
2137
2138    void gattTestCommand(int command, UUID uuid1, String bda1,
2139                         int p1, int p2, int p3, int p4, int p5) {
2140        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2141        if (uuid1 != null)
2142            gattTestNative(command, uuid1.getLeastSignificantBits(),
2143                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2144        else
2145            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2146    }
2147
2148    private native void gattTestNative(int command,
2149                                    long uuid1_lsb, long uuid1_msb, String bda1,
2150                                    int p1, int p2, int p3, int p4, int p5);
2151
2152    /**************************************************************************
2153     * Native functions prototypes
2154     *************************************************************************/
2155
2156    private native static void classInitNative();
2157    private native void initializeNative();
2158    private native void cleanupNative();
2159
2160    private native int gattClientGetDeviceTypeNative(String address);
2161
2162    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2163                                                    long app_uuid_msb);
2164
2165    private native void gattClientUnregisterAppNative(int clientIf);
2166
2167    private native void gattClientConnectNative(int clientIf, String address,
2168            boolean isDirect, int transport);
2169
2170    private native void gattClientDisconnectNative(int clientIf, String address,
2171            int conn_id);
2172
2173    private native void gattClientRefreshNative(int clientIf, String address);
2174
2175    private native void gattClientSearchServiceNative(int conn_id,
2176            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2177
2178    private native void gattClientGetCharacteristicNative(int conn_id,
2179            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2180            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2181            long char_id_uuid_msb);
2182
2183    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2184            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2185            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2186            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2187
2188    private native void gattClientGetIncludedServiceNative(int conn_id,
2189            int service_type, int service_id_inst_id,
2190            long service_id_uuid_lsb, long service_id_uuid_msb,
2191            int incl_service_id_inst_id, int incl_service_type,
2192            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2193
2194    private native void gattClientReadCharacteristicNative(int conn_id,
2195            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2196            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2197            long char_id_uuid_msb, int authReq);
2198
2199    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2200            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2201            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2202            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2203            int authReq);
2204
2205    private native void gattClientWriteCharacteristicNative(int conn_id,
2206            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2207            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2208            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2209
2210    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2211            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2212            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2213            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2214            int write_type, int auth_req, byte[] value);
2215
2216    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2217
2218    private native void gattClientRegisterForNotificationsNative(int clientIf,
2219            String address, int service_type, int service_id_inst_id,
2220            long service_id_uuid_lsb, long service_id_uuid_msb,
2221            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2222            boolean enable);
2223
2224    private native void gattClientReadRemoteRssiNative(int clientIf,
2225            String address);
2226
2227    private native void gattAdvertiseNative(int client_if, boolean start);
2228
2229    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2230
2231    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2232            int minInterval, int maxInterval, int latency, int timeout);
2233
2234    private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
2235            boolean inclTxPower, int minInterval, int maxInterval,
2236            int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
2237
2238    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2239                                                    long app_uuid_msb);
2240
2241    private native void gattServerUnregisterAppNative(int serverIf);
2242
2243    private native void gattServerConnectNative(int server_if, String address,
2244                                             boolean is_direct, int transport);
2245
2246    private native void gattServerDisconnectNative(int serverIf, String address,
2247                                              int conn_id);
2248
2249    private native void gattServerAddServiceNative (int server_if,
2250            int service_type, int service_id_inst_id,
2251            long service_id_uuid_lsb, long service_id_uuid_msb,
2252            int num_handles);
2253
2254    private native void gattServerAddIncludedServiceNative (int server_if,
2255            int svc_handle, int included_svc_handle);
2256
2257    private native void gattServerAddCharacteristicNative (int server_if,
2258            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2259            int properties, int permissions);
2260
2261    private native void gattServerAddDescriptorNative (int server_if,
2262            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2263            int permissions);
2264
2265    private native void gattServerStartServiceNative (int server_if,
2266            int svc_handle, int transport );
2267
2268    private native void gattServerStopServiceNative (int server_if,
2269                                                     int svc_handle);
2270
2271    private native void gattServerDeleteServiceNative (int server_if,
2272                                                       int svc_handle);
2273
2274    private native void gattServerSendIndicationNative (int server_if,
2275            int attr_handle, int conn_id, byte[] val);
2276
2277    private native void gattServerSendNotificationNative (int server_if,
2278            int attr_handle, int conn_id, byte[] val);
2279
2280    private native void gattServerSendResponseNative (int server_if,
2281            int conn_id, int trans_id, int status, int handle, int offset,
2282            byte[] val, int auth_req);
2283}
2284