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