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