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