GattService.java revision 6ef76fa25c1de11cbb5ae35d645c68584f680ac8
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        if (needsPrivilegedPermissionForScan(settings)) {
1278            enforcePrivilegedPermission();
1279        }
1280        mScanManager.startScan(new ScanClient(appIf, isServer, settings, filters, storages));
1281    }
1282
1283    void flushPendingBatchResults(int clientIf, boolean isServer) {
1284        if (DBG) Log.d(TAG, "flushPendingBatchResults - clientIf=" + clientIf +
1285                ", isServer=" + isServer);
1286        mScanManager.flushBatchScanResults(new ScanClient(clientIf, isServer));
1287    }
1288
1289    void stopScan(ScanClient client) {
1290        enforceAdminPermission();
1291        int scanQueueSize = mScanManager.getBatchScanQueue().size() +
1292                mScanManager.getRegularScanQueue().size();
1293        if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize);
1294        mScanManager.stopScan(client);
1295    }
1296
1297    /**************************************************************************
1298     * GATT Service functions - CLIENT
1299     *************************************************************************/
1300
1301    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
1302        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1303
1304        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1305        mClientMap.add(uuid, callback);
1306        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1307                                    uuid.getMostSignificantBits());
1308    }
1309
1310    void unregisterClient(int clientIf) {
1311        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1312
1313        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1314        mClientMap.remove(clientIf);
1315        gattClientUnregisterAppNative(clientIf);
1316    }
1317
1318    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1319        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1320
1321        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1322        gattClientConnectNative(clientIf, address, isDirect, transport);
1323    }
1324
1325    void clientDisconnect(int clientIf, String address) {
1326        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1327
1328        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1329        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1330
1331        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1332    }
1333
1334    void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,
1335            AdvertiseData scanResponse, AdvertiseSettings settings) {
1336        enforceAdminPermission();
1337        mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData,
1338                scanResponse));
1339    }
1340
1341    void stopMultiAdvertising(AdvertiseClient client) {
1342        enforceAdminPermission();
1343        mAdvertiseManager.stopAdvertising(client);
1344    }
1345
1346
1347    synchronized List<ParcelUuid> getRegisteredServiceUuids() {
1348        Utils.enforceAdminPermission(this);
1349        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1350        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1351            serviceUuids.add(new ParcelUuid(entry.uuid));
1352        }
1353        return serviceUuids;
1354    }
1355
1356    List<String> getConnectedDevices() {
1357        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1358
1359        Set<String> connectedDevAddress = new HashSet<String>();
1360        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1361        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1362        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1363        return connectedDeviceList;
1364    }
1365
1366    void refreshDevice(int clientIf, String address) {
1367        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1368
1369        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1370        gattClientRefreshNative(clientIf, address);
1371    }
1372
1373    void discoverServices(int clientIf, String address) {
1374        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1375
1376        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1377        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1378
1379        if (connId != null)
1380            gattClientSearchServiceNative(connId, true, 0, 0);
1381        else
1382            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1383    }
1384
1385    void readCharacteristic(int clientIf, String address, int srvcType,
1386                            int srvcInstanceId, UUID srvcUuid,
1387                            int charInstanceId, UUID charUuid, int authReq) {
1388        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1389
1390        if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1391
1392        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1393        if (connId != null)
1394            gattClientReadCharacteristicNative(connId, srvcType,
1395                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1396                srvcUuid.getMostSignificantBits(), charInstanceId,
1397                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1398                authReq);
1399        else
1400            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1401    }
1402
1403    void writeCharacteristic(int clientIf, String address, int srvcType,
1404                             int srvcInstanceId, UUID srvcUuid,
1405                             int charInstanceId, UUID charUuid, int writeType,
1406                             int authReq, byte[] value) {
1407        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1408
1409        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1410
1411        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1412
1413        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1414        if (connId != null)
1415            gattClientWriteCharacteristicNative(connId, srvcType,
1416                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1417                srvcUuid.getMostSignificantBits(), charInstanceId,
1418                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1419                writeType, authReq, value);
1420        else
1421            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1422    }
1423
1424    void readDescriptor(int clientIf, String address, int srvcType,
1425                            int srvcInstanceId, UUID srvcUuid,
1426                            int charInstanceId, UUID charUuid,
1427                            int descrInstanceId, UUID descrUuid,
1428                            int authReq) {
1429        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1430
1431        if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address);
1432
1433        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1434        if (connId != null)
1435            gattClientReadDescriptorNative(connId, srvcType,
1436                srvcInstanceId,
1437                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1438                charInstanceId,
1439                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1440                descrInstanceId,
1441                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1442                authReq);
1443        else
1444            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1445    };
1446
1447    void writeDescriptor(int clientIf, String address, int srvcType,
1448                            int srvcInstanceId, UUID srvcUuid,
1449                            int charInstanceId, UUID charUuid,
1450                            int descrInstanceId, UUID descrUuid,
1451                            int writeType, int authReq, byte[] value) {
1452        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1453
1454        if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1455
1456        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1457        if (connId != null)
1458            gattClientWriteDescriptorNative(connId, srvcType,
1459                srvcInstanceId,
1460                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1461                charInstanceId,
1462                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1463                descrInstanceId,
1464                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1465                writeType, authReq, value);
1466        else
1467            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1468    }
1469
1470    void beginReliableWrite(int clientIf, String address) {
1471        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1472
1473        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1474        mReliableQueue.add(address);
1475    }
1476
1477    void endReliableWrite(int clientIf, String address, boolean execute) {
1478        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1479
1480        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1481                                + " execute: " + execute);
1482        mReliableQueue.remove(address);
1483
1484        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1485        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1486    }
1487
1488    void registerForNotification(int clientIf, String address, int srvcType,
1489                int srvcInstanceId, UUID srvcUuid,
1490                int charInstanceId, UUID charUuid,
1491                boolean enable) {
1492        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1493
1494        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1495
1496        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1497        if (connId != null) {
1498            gattClientRegisterForNotificationsNative(clientIf, address,
1499                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1500                srvcUuid.getMostSignificantBits(), charInstanceId,
1501                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1502                enable);
1503        } else {
1504            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1505        }
1506    }
1507
1508    void readRemoteRssi(int clientIf, String address) {
1509        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1510
1511        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1512        gattClientReadRemoteRssiNative(clientIf, address);
1513    }
1514
1515    void configureMTU(int clientIf, String address, int mtu) {
1516        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1517
1518        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1519        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1520        if (connId != null) {
1521            gattClientConfigureMTUNative(connId, mtu);
1522        } else {
1523            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1524        }
1525    }
1526
1527    void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
1528        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1529
1530        // Default spec recommended interval is 30->50 ms
1531        int minInterval = 24; // 24 * 1.25ms = 30ms
1532        int maxInterval = 40; // 40 * 1.25ms = 50ms
1533
1534        // Slave latency
1535        int latency = 0;
1536
1537        // Link supervision timeout is measured in N * 10ms
1538        int timeout = 2000; // 20s
1539
1540        switch (connectionPriority)
1541        {
1542            case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
1543                minInterval = 6; // 7.5ms
1544                maxInterval = 8; // 10ms
1545                break;
1546
1547            case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
1548                minInterval = 80; // 100ms
1549                maxInterval = 100; // 125ms
1550                latency = 2;
1551                break;
1552        }
1553
1554        if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address
1555            + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
1556        gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
1557                                            latency, timeout);
1558    }
1559
1560    /**************************************************************************
1561     * Callback functions - SERVER
1562     *************************************************************************/
1563
1564    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1565            throws RemoteException {
1566
1567        UUID uuid = new UUID(uuidMsb, uuidLsb);
1568        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1569        ServerMap.App app = mServerMap.getByUuid(uuid);
1570        if (app != null) {
1571            app.id = serverIf;
1572            app.linkToDeath(new ServerDeathRecipient(serverIf));
1573            app.callback.onServerRegistered(status, serverIf);
1574        }
1575    }
1576
1577    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1578                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1579                        throws RemoteException {
1580        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1581        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1582            + ", handle=" + srvcHandle);
1583        if (status == 0) {
1584            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1585                mAdvertisingServiceUuids.remove(uuid));
1586        }
1587
1588        continueServiceDeclaration(serverIf, status, srvcHandle);
1589    }
1590
1591    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1592                                int includedSrvcHandle) throws RemoteException {
1593        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1594            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1595        continueServiceDeclaration(serverIf, status, srvcHandle);
1596    }
1597
1598    void onCharacteristicAdded(int status, int serverIf,
1599                               long charUuidLsb, long charUuidMsb,
1600                               int srvcHandle, int charHandle)
1601                               throws RemoteException {
1602            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1603        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1604            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1605        if (status == 0)
1606            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1607        continueServiceDeclaration(serverIf, status, srvcHandle);
1608    }
1609
1610    void onDescriptorAdded(int status, int serverIf,
1611                           long descrUuidLsb, long descrUuidMsb,
1612                           int srvcHandle, int descrHandle)
1613                           throws RemoteException {
1614            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1615        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1616            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1617        if (status == 0)
1618            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1619        continueServiceDeclaration(serverIf, status, srvcHandle);
1620    }
1621
1622    void onServiceStarted(int status, int serverIf, int srvcHandle)
1623            throws RemoteException {
1624        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1625            + ", status=" + status);
1626        if (status == 0)
1627            mHandleMap.setStarted(serverIf, srvcHandle, true);
1628    }
1629
1630    void onServiceStopped(int status, int serverIf, int srvcHandle)
1631            throws RemoteException {
1632        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1633            + ", status=" + status);
1634        if (status == 0)
1635            mHandleMap.setStarted(serverIf, srvcHandle, false);
1636        stopNextService(serverIf, status);
1637    }
1638
1639    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1640        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1641            + ", status=" + status);
1642        mHandleMap.deleteService(serverIf, srvcHandle);
1643    }
1644
1645    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1646            throws RemoteException {
1647
1648        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1649            + ", address=" + address + ", connected=" + connected);
1650
1651        ServerMap.App app = mServerMap.getById(serverIf);
1652        if (app == null) return;
1653
1654        if (connected) {
1655            mServerMap.addConnection(serverIf, connId, address);
1656        } else {
1657            mServerMap.removeConnection(serverIf, connId);
1658        }
1659
1660        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1661    }
1662
1663    void onAttributeRead(String address, int connId, int transId,
1664                            int attrHandle, int offset, boolean isLong)
1665                            throws RemoteException {
1666        if (VDBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1667            + ", address=" + address + ", handle=" + attrHandle
1668            + ", requestId=" + transId + ", offset=" + offset);
1669
1670        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1671        if (entry == null) return;
1672
1673        if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid
1674            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1675
1676        mHandleMap.addRequest(transId, attrHandle);
1677
1678        ServerMap.App app = mServerMap.getById(entry.serverIf);
1679        if (app == null) return;
1680
1681        switch(entry.type) {
1682            case HandleMap.TYPE_CHARACTERISTIC:
1683            {
1684                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1685                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1686                    serviceEntry.serviceType, serviceEntry.instance,
1687                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1688                    new ParcelUuid(entry.uuid));
1689                break;
1690            }
1691
1692            case HandleMap.TYPE_DESCRIPTOR:
1693            {
1694                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1695                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1696                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1697                    serviceEntry.serviceType, serviceEntry.instance,
1698                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1699                    new ParcelUuid(charEntry.uuid),
1700                    new ParcelUuid(entry.uuid));
1701                break;
1702            }
1703
1704            default:
1705                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1706                break;
1707        }
1708    }
1709
1710    void onAttributeWrite(String address, int connId, int transId,
1711                            int attrHandle, int offset, int length,
1712                            boolean needRsp, boolean isPrep,
1713                            byte[] data)
1714                            throws RemoteException {
1715        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1716            + ", address=" + address + ", handle=" + attrHandle
1717            + ", requestId=" + transId + ", isPrep=" + isPrep
1718            + ", offset=" + offset);
1719
1720        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1721        if (entry == null) return;
1722
1723        if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid
1724            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1725
1726        mHandleMap.addRequest(transId, attrHandle);
1727
1728        ServerMap.App app = mServerMap.getById(entry.serverIf);
1729        if (app == null) return;
1730
1731        switch(entry.type) {
1732            case HandleMap.TYPE_CHARACTERISTIC:
1733            {
1734                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1735                app.callback.onCharacteristicWriteRequest(address, transId,
1736                            offset, length, isPrep, needRsp,
1737                            serviceEntry.serviceType, serviceEntry.instance,
1738                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1739                            new ParcelUuid(entry.uuid), data);
1740                break;
1741            }
1742
1743            case HandleMap.TYPE_DESCRIPTOR:
1744            {
1745                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1746                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1747                app.callback.onDescriptorWriteRequest(address, transId,
1748                            offset, length, isPrep, needRsp,
1749                            serviceEntry.serviceType, serviceEntry.instance,
1750                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1751                            new ParcelUuid(charEntry.uuid),
1752                            new ParcelUuid(entry.uuid), data);
1753                break;
1754            }
1755
1756            default:
1757                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1758                break;
1759        }
1760    }
1761
1762    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1763            throws RemoteException {
1764        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1765            + ", address=" + address + ", transId=" + transId);
1766
1767        ServerMap.App app = mServerMap.getByConnId(connId);
1768        if (app == null) return;
1769
1770        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1771    }
1772
1773    void onResponseSendCompleted(int status, int attrHandle) {
1774        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1775    }
1776
1777    void onNotificationSent(int connId, int status) throws RemoteException {
1778        if (DBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
1779
1780        String address = mServerMap.addressByConnId(connId);
1781        if (address == null) return;
1782
1783        ServerMap.App app = mServerMap.getByConnId(connId);
1784        if (app == null) return;
1785
1786        app.callback.onNotificationSent(address, status);
1787    }
1788
1789    void onServerCongestion(int connId, boolean congested) throws RemoteException {
1790        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
1791
1792        ServerMap.App app = mServerMap.getByConnId(connId);
1793        if (app != null) {
1794            app.callback.onConnectionCongested(mServerMap.addressByConnId(connId), congested);
1795        }
1796    }
1797
1798    /**************************************************************************
1799     * GATT Service functions - SERVER
1800     *************************************************************************/
1801
1802    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1803        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1804
1805        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1806        mServerMap.add(uuid, callback);
1807        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1808                                    uuid.getMostSignificantBits());
1809    }
1810
1811    void unregisterServer(int serverIf) {
1812        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1813
1814        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1815
1816        deleteServices(serverIf);
1817
1818        mServerMap.remove(serverIf);
1819        gattServerUnregisterAppNative(serverIf);
1820    }
1821
1822    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1823        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1824
1825        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1826        gattServerConnectNative(serverIf, address, isDirect,transport);
1827    }
1828
1829    void serverDisconnect(int serverIf, String address) {
1830        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1831
1832        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1833        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1834
1835        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1836    }
1837
1838    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1839                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1840        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1841
1842        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1843        ServiceDeclaration serviceDeclaration = addDeclaration();
1844        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1845            advertisePreferred);
1846    }
1847
1848    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1849                            UUID srvcUuid) {
1850        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1851
1852        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1853        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1854    }
1855
1856    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1857                           int permissions) {
1858        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1859
1860        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1861        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1862    }
1863
1864    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1865        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1866
1867        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1868        getActiveDeclaration().addDescriptor(descUuid, permissions);
1869    }
1870
1871    void endServiceDeclaration(int serverIf) {
1872        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1873
1874        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1875
1876        if (getActiveDeclaration() == getPendingDeclaration()) {
1877            try {
1878                continueServiceDeclaration(serverIf, (byte)0, 0);
1879            } catch (RemoteException e) {
1880                Log.e(TAG,""+e);
1881            }
1882        }
1883    }
1884
1885    void removeService(int serverIf, int srvcType,
1886                  int srvcInstanceId, UUID srvcUuid) {
1887        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1888
1889        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
1890
1891        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1892        if (srvcHandle == 0) return;
1893        gattServerDeleteServiceNative(serverIf, srvcHandle);
1894    }
1895
1896    void clearServices(int serverIf) {
1897        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1898
1899        if (DBG) Log.d(TAG, "clearServices()");
1900        deleteServices(serverIf);
1901    }
1902
1903    void sendResponse(int serverIf, String address, int requestId,
1904                      int status, int offset, byte[] value) {
1905        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1906
1907        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
1908
1909        int handle = 0;
1910        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
1911        if (entry != null) handle = entry.handle;
1912
1913        int connId = mServerMap.connIdByAddress(serverIf, address);
1914        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
1915                                     handle, offset, value, (byte)0);
1916        mHandleMap.deleteRequest(requestId);
1917    }
1918
1919    void sendNotification(int serverIf, String address, int srvcType,
1920                                 int srvcInstanceId, UUID srvcUuid,
1921                                 int charInstanceId, UUID charUuid,
1922                                 boolean confirm, byte[] value) {
1923        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1924
1925        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address);
1926
1927        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1928        if (srvcHandle == 0) return;
1929
1930        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
1931        if (charHandle == 0) return;
1932
1933        int connId = mServerMap.connIdByAddress(serverIf, address);
1934        if (connId == 0) return;
1935
1936        if (confirm) {
1937            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
1938        } else {
1939            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
1940        }
1941    }
1942
1943
1944    /**************************************************************************
1945     * Private functions
1946     *************************************************************************/
1947
1948    private int getDeviceType(BluetoothDevice device) {
1949        int type = gattClientGetDeviceTypeNative(device.getAddress());
1950        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
1951            + ", type=" + type);
1952        return type;
1953    }
1954
1955    private void enforceAdminPermission() {
1956        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1957    }
1958
1959    private boolean needsPrivilegedPermissionForScan(ScanSettings settings) {
1960        // Regular scan, no special permission.
1961        if (settings == null) {
1962            return false;
1963        }
1964        // Hidden API for onLost/onFound
1965        if (settings.getScanMode() != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
1966            return true;
1967        }
1968        // Regular scan, no special permission.
1969        if (settings.getReportDelayMillis() == 0) {
1970            return false;
1971        }
1972        // Batch scan, truncated mode needs permission.
1973        return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED;
1974    }
1975
1976    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
1977    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
1978    private void enforcePrivilegedPermission() {
1979        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
1980            "Need BLUETOOTH_PRIVILEGED permission");
1981    }
1982
1983    private void continueSearch(int connId, int status) throws RemoteException {
1984        if (status == 0 && !mSearchQueue.isEmpty()) {
1985            SearchQueue.Entry svc = mSearchQueue.pop();
1986
1987            if (svc.charUuidLsb == 0) {
1988                // Characteristic is up next
1989                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
1990                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
1991            } else {
1992                // Descriptor is up next
1993                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
1994                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
1995                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
1996            }
1997        } else {
1998            ClientMap.App app = mClientMap.getByConnId(connId);
1999            if (app != null) {
2000                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
2001            }
2002        }
2003    }
2004
2005    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
2006        if (mServiceDeclarations.size() == 0) return;
2007        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
2008
2009        boolean finished = false;
2010
2011        ServiceDeclaration.Entry entry = null;
2012        if (status == 0)
2013            entry = getPendingDeclaration().getNext();
2014
2015        if (entry != null) {
2016            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
2017                + entry.type);
2018            switch(entry.type) {
2019                case ServiceDeclaration.TYPE_SERVICE:
2020                    if (entry.advertisePreferred) {
2021                        mAdvertisingServiceUuids.add(entry.uuid);
2022                    }
2023                    gattServerAddServiceNative(serverIf, entry.serviceType,
2024                        entry.instance,
2025                        entry.uuid.getLeastSignificantBits(),
2026                        entry.uuid.getMostSignificantBits(),
2027                        getPendingDeclaration().getNumHandles());
2028                    break;
2029
2030                case ServiceDeclaration.TYPE_CHARACTERISTIC:
2031                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
2032                        entry.uuid.getLeastSignificantBits(),
2033                        entry.uuid.getMostSignificantBits(),
2034                        entry.properties, entry.permissions);
2035                    break;
2036
2037                case ServiceDeclaration.TYPE_DESCRIPTOR:
2038                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2039                        entry.uuid.getLeastSignificantBits(),
2040                        entry.uuid.getMostSignificantBits(),
2041                        entry.permissions);
2042                    break;
2043
2044                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2045                {
2046                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2047                                            entry.serviceType, entry.instance);
2048                    if (inclSrvc != 0) {
2049                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2050                                                           inclSrvc);
2051                    } else {
2052                        finished = true;
2053                    }
2054                    break;
2055                }
2056            }
2057        } else {
2058            gattServerStartServiceNative(serverIf, srvcHandle,
2059                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2060            finished = true;
2061        }
2062
2063        if (finished) {
2064            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2065            ServerMap.App app = mServerMap.getById(serverIf);
2066            if (app != null) {
2067                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2068
2069                if (serviceEntry != null) {
2070                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2071                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2072                } else {
2073                    app.callback.onServiceAdded(status, 0, 0, null);
2074                }
2075            }
2076            removePendingDeclaration();
2077
2078            if (getPendingDeclaration() != null) {
2079                continueServiceDeclaration(serverIf, (byte)0, 0);
2080            }
2081        }
2082    }
2083
2084    private void stopNextService(int serverIf, int status) throws RemoteException {
2085        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2086            + ", status=" + status);
2087
2088        if (status == 0) {
2089            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2090            for(HandleMap.Entry entry : entries) {
2091                if (entry.type != HandleMap.TYPE_SERVICE ||
2092                    entry.serverIf != serverIf ||
2093                    entry.started == false)
2094                        continue;
2095
2096                gattServerStopServiceNative(serverIf, entry.handle);
2097                return;
2098            }
2099        }
2100    }
2101
2102    private void deleteServices(int serverIf) {
2103        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2104
2105        /*
2106         * Figure out which handles to delete.
2107         * The handles are copied into a new list to avoid race conditions.
2108         */
2109        List<Integer> handleList = new ArrayList<Integer>();
2110        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2111        for(HandleMap.Entry entry : entries) {
2112            if (entry.type != HandleMap.TYPE_SERVICE ||
2113                entry.serverIf != serverIf)
2114                    continue;
2115            handleList.add(entry.handle);
2116        }
2117
2118        /* Now actually delete the services.... */
2119        for(Integer handle : handleList) {
2120            gattServerDeleteServiceNative(serverIf, handle);
2121        }
2122    }
2123
2124    private List<UUID> parseUuids(byte[] adv_data) {
2125        List<UUID> uuids = new ArrayList<UUID>();
2126
2127        int offset = 0;
2128        while(offset < (adv_data.length-2)) {
2129            int len = adv_data[offset++];
2130            if (len == 0) break;
2131
2132            int type = adv_data[offset++];
2133            switch (type) {
2134                case 0x02: // Partial list of 16-bit UUIDs
2135                case 0x03: // Complete list of 16-bit UUIDs
2136                    while (len > 1) {
2137                        int uuid16 = adv_data[offset++];
2138                        uuid16 += (adv_data[offset++] << 8);
2139                        len -= 2;
2140                        uuids.add(UUID.fromString(String.format(
2141                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2142                    }
2143                    break;
2144
2145                default:
2146                    offset += (len - 1);
2147                    break;
2148            }
2149        }
2150
2151        return uuids;
2152    }
2153
2154    /**************************************************************************
2155     * GATT Test functions
2156     *************************************************************************/
2157
2158    void gattTestCommand(int command, UUID uuid1, String bda1,
2159                         int p1, int p2, int p3, int p4, int p5) {
2160        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2161        if (uuid1 != null)
2162            gattTestNative(command, uuid1.getLeastSignificantBits(),
2163                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2164        else
2165            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2166    }
2167
2168    private native void gattTestNative(int command,
2169                                    long uuid1_lsb, long uuid1_msb, String bda1,
2170                                    int p1, int p2, int p3, int p4, int p5);
2171
2172    /**************************************************************************
2173     * Native functions prototypes
2174     *************************************************************************/
2175
2176    private native static void classInitNative();
2177    private native void initializeNative();
2178    private native void cleanupNative();
2179
2180    private native int gattClientGetDeviceTypeNative(String address);
2181
2182    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2183                                                    long app_uuid_msb);
2184
2185    private native void gattClientUnregisterAppNative(int clientIf);
2186
2187    private native void gattClientConnectNative(int clientIf, String address,
2188            boolean isDirect, int transport);
2189
2190    private native void gattClientDisconnectNative(int clientIf, String address,
2191            int conn_id);
2192
2193    private native void gattClientRefreshNative(int clientIf, String address);
2194
2195    private native void gattClientSearchServiceNative(int conn_id,
2196            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2197
2198    private native void gattClientGetCharacteristicNative(int conn_id,
2199            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2200            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2201            long char_id_uuid_msb);
2202
2203    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2204            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2205            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2206            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2207
2208    private native void gattClientGetIncludedServiceNative(int conn_id,
2209            int service_type, int service_id_inst_id,
2210            long service_id_uuid_lsb, long service_id_uuid_msb,
2211            int incl_service_id_inst_id, int incl_service_type,
2212            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2213
2214    private native void gattClientReadCharacteristicNative(int conn_id,
2215            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2216            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2217            long char_id_uuid_msb, int authReq);
2218
2219    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2220            int service_id_inst_id, 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            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2223            int authReq);
2224
2225    private native void gattClientWriteCharacteristicNative(int conn_id,
2226            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2227            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2228            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2229
2230    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2231            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2232            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2233            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2234            int write_type, int auth_req, byte[] value);
2235
2236    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2237
2238    private native void gattClientRegisterForNotificationsNative(int clientIf,
2239            String address, int service_type, int service_id_inst_id,
2240            long service_id_uuid_lsb, long service_id_uuid_msb,
2241            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2242            boolean enable);
2243
2244    private native void gattClientReadRemoteRssiNative(int clientIf,
2245            String address);
2246
2247    private native void gattAdvertiseNative(int client_if, boolean start);
2248
2249    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2250
2251    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2252            int minInterval, int maxInterval, int latency, int timeout);
2253
2254    private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
2255            boolean inclTxPower, int minInterval, int maxInterval,
2256            int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
2257
2258    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2259                                                    long app_uuid_msb);
2260
2261    private native void gattServerUnregisterAppNative(int serverIf);
2262
2263    private native void gattServerConnectNative(int server_if, String address,
2264                                             boolean is_direct, int transport);
2265
2266    private native void gattServerDisconnectNative(int serverIf, String address,
2267                                              int conn_id);
2268
2269    private native void gattServerAddServiceNative (int server_if,
2270            int service_type, int service_id_inst_id,
2271            long service_id_uuid_lsb, long service_id_uuid_msb,
2272            int num_handles);
2273
2274    private native void gattServerAddIncludedServiceNative (int server_if,
2275            int svc_handle, int included_svc_handle);
2276
2277    private native void gattServerAddCharacteristicNative (int server_if,
2278            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2279            int properties, int permissions);
2280
2281    private native void gattServerAddDescriptorNative (int server_if,
2282            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2283            int permissions);
2284
2285    private native void gattServerStartServiceNative (int server_if,
2286            int svc_handle, int transport );
2287
2288    private native void gattServerStopServiceNative (int server_if,
2289                                                     int svc_handle);
2290
2291    private native void gattServerDeleteServiceNative (int server_if,
2292                                                       int svc_handle);
2293
2294    private native void gattServerSendIndicationNative (int server_if,
2295            int attr_handle, int conn_id, byte[] val);
2296
2297    private native void gattServerSendNotificationNative (int server_if,
2298            int attr_handle, int conn_id, byte[] val);
2299
2300    private native void gattServerSendResponseNative (int server_if,
2301            int conn_id, int trans_id, int status, int handle, int offset,
2302            byte[] val, int auth_req);
2303}
2304