GattService.java revision a1feac750a78ef35ff83e381ca421d9c68c49673
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(address, rssi, adv_data);
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) throws RemoteException {
1075        ClientMap.App app = mClientMap.getById(clientIf);
1076        if (app == null || app.callback == null) {
1077            Log.e(TAG, "Advertise app or callback is null");
1078            return;
1079        }
1080        app.callback.onMultiAdvertiseCallback(status);
1081    }
1082
1083    void onConfigureMTU(int connId, int status, int mtu) throws RemoteException {
1084        String address = mClientMap.addressByConnId(connId);
1085
1086        if (DBG) Log.d(TAG, "onConfigureMTU() address=" + address + ", status="
1087            + status + ", mtu=" + mtu);
1088
1089        ClientMap.App app = mClientMap.getByConnId(connId);
1090        if (app != null) {
1091            app.callback.onConfigureMTU(address, mtu, status);
1092        }
1093    }
1094
1095    // Callback for standard advertising instance.
1096    void onAdvertiseCallback(int status, int clientIf) {
1097        if (DBG) Log.d(TAG, "onAdvertiseCallback,- clientIf=" + clientIf + ", status=" + status);
1098    }
1099
1100    // Followings are callbacks for Bluetooth LE Advertise operations.
1101    // Start advertising flow is
1102    //     enable advertising instance -> onAdvertiseInstaceEnabled
1103    // ->  set advertise data          -> onAdvertiseDataSet
1104    // ->  set scan response           -> onAdvertiseDataSet
1105
1106    // Callback when advertise instance is enabled.
1107    void onAdvertiseInstanceEnabled(int status, int clientIf) {
1108        if (DBG) Log.d(TAG, "onAdvertiseInstanceEnabled() - "
1109                + "clientIf=" + clientIf + ", status=" + status);
1110        mAdvertiseManager.callbackDone(clientIf, status);
1111    }
1112
1113    // Not really used.
1114    void onAdvertiseDataUpdated(int status, int client_if) {
1115        if (DBG) Log.d(TAG, "onAdvertiseDataUpdated() - client_if=" + client_if
1116            + ", status=" + status);
1117    }
1118
1119    // Callback when advertise data or scan response is set.
1120    void onAdvertiseDataSet(int status, int clientIf) {
1121        if (DBG) Log.d(TAG, "onAdvertiseDataSet() - clientIf=" + clientIf
1122            + ", status=" + status);
1123        mAdvertiseManager.callbackDone(clientIf, status);
1124    }
1125
1126    // Callback when advertise instance is disabled
1127    void onAdvertiseInstanceDisabled(int status, int clientIf) throws RemoteException {
1128        if (DBG) Log.d(TAG, "onAdvertiseInstanceEnabled() - clientIf=" + clientIf
1129            + ", status=" + status);
1130        ClientMap.App app = mClientMap.getById(clientIf);
1131        if (app != null) {
1132            Log.d(TAG, "Client app is not null!");
1133            if (status == 0) {
1134                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.ADVERTISE_SUCCESS);
1135            } else {
1136                app.callback.onMultiAdvertiseCallback(
1137                        AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
1138            }
1139        }
1140    }
1141
1142    void onClientCongestion(int connId, boolean congested) throws RemoteException {
1143        if (DBG) Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested);
1144
1145        ClientMap.App app = mClientMap.getByConnId(connId);
1146        if (app != null) {
1147            app.callback.onConnectionCongested(mClientMap.addressByConnId(connId), congested);
1148        }
1149    }
1150
1151    /**************************************************************************
1152     * GATT Service functions - Shared CLIENT/SERVER
1153     *************************************************************************/
1154
1155    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
1156        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1157
1158        final int DEVICE_TYPE_BREDR = 0x1;
1159
1160        Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice,
1161                                                                 Integer>();
1162
1163        // Add paired LE devices
1164
1165        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
1166        for (BluetoothDevice device : bondedDevices) {
1167            if (getDeviceType(device) != DEVICE_TYPE_BREDR) {
1168                deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
1169            }
1170        }
1171
1172        // Add connected deviceStates
1173
1174        Set<String> connectedDevices = new HashSet<String>();
1175        connectedDevices.addAll(mClientMap.getConnectedDevices());
1176        connectedDevices.addAll(mServerMap.getConnectedDevices());
1177
1178        for (String address : connectedDevices ) {
1179            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1180            if (device != null) {
1181                deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
1182            }
1183        }
1184
1185        // Create matching device sub-set
1186
1187        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
1188
1189        for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
1190            for(int state : states) {
1191                if (entry.getValue() == state) {
1192                    deviceList.add(entry.getKey());
1193                }
1194            }
1195        }
1196
1197        return deviceList;
1198    }
1199
1200    void startScan(int appIf, boolean isServer, ScanSettings settings,
1201            List<ScanFilter> filters) {
1202        if (DBG) Log.d(TAG, "start scan with filters ");
1203        enforceAdminPermission();
1204        mScanManager.startScan(new ScanClient(appIf, isServer, settings, filters));
1205    }
1206
1207    void flushPendingBatchResults(int clientIf, boolean isServer) {
1208        if (DBG) Log.d(TAG, "flushPendingBatchResults - clientIf=" + clientIf +
1209                ", isServer=" + isServer);
1210        mScanManager.flushBatchScanResults(new ScanClient(clientIf, isServer));
1211    }
1212
1213    void stopScan(int appIf, boolean isServer) {
1214        enforceAdminPermission();
1215        if (DBG) Log.d(TAG, "stopScan() - queue=" + mScanManager.scanQueue().size());
1216        mScanManager.stopScan(new ScanClient(appIf, isServer));
1217    }
1218
1219    /**************************************************************************
1220     * GATT Service functions - CLIENT
1221     *************************************************************************/
1222
1223    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
1224        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1225
1226        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1227        mClientMap.add(uuid, callback);
1228        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1229                                    uuid.getMostSignificantBits());
1230    }
1231
1232    void unregisterClient(int clientIf) {
1233        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1234
1235        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1236        mClientMap.remove(clientIf);
1237        gattClientUnregisterAppNative(clientIf);
1238    }
1239
1240    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1241        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1242
1243        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1244        gattClientConnectNative(clientIf, address, isDirect, transport);
1245    }
1246
1247    void clientDisconnect(int clientIf, String address) {
1248        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1249
1250        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1251        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1252
1253        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1254    }
1255
1256    void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,
1257            AdvertiseData scanResponse, AdvertiseSettings settings) {
1258        enforceAdminPermission();
1259        mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData,
1260                scanResponse));
1261    }
1262
1263    void stopMultiAdvertising(int clientIf) {
1264        enforceAdminPermission();
1265        mAdvertiseManager.stopAdvertising(new AdvertiseClient(clientIf));
1266    }
1267
1268
1269    synchronized List<ParcelUuid> getRegisteredServiceUuids() {
1270        Utils.enforceAdminPermission(this);
1271        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1272        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1273            serviceUuids.add(new ParcelUuid(entry.uuid));
1274        }
1275        return serviceUuids;
1276    }
1277
1278    List<String> getConnectedDevices() {
1279        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1280
1281        Set<String> connectedDevAddress = new HashSet<String>();
1282        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1283        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1284        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1285        return connectedDeviceList;
1286    }
1287
1288    void refreshDevice(int clientIf, String address) {
1289        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1290
1291        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1292        gattClientRefreshNative(clientIf, address);
1293    }
1294
1295    void discoverServices(int clientIf, String address) {
1296        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1297
1298        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1299        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1300
1301        if (connId != null)
1302            gattClientSearchServiceNative(connId, true, 0, 0);
1303        else
1304            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1305    }
1306
1307    void readCharacteristic(int clientIf, String address, int srvcType,
1308                            int srvcInstanceId, UUID srvcUuid,
1309                            int charInstanceId, UUID charUuid, int authReq) {
1310        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1311
1312        if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1313
1314        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1315        if (connId != null)
1316            gattClientReadCharacteristicNative(connId, srvcType,
1317                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1318                srvcUuid.getMostSignificantBits(), charInstanceId,
1319                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1320                authReq);
1321        else
1322            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1323    }
1324
1325    void writeCharacteristic(int clientIf, String address, int srvcType,
1326                             int srvcInstanceId, UUID srvcUuid,
1327                             int charInstanceId, UUID charUuid, int writeType,
1328                             int authReq, byte[] value) {
1329        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1330
1331        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1332
1333        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1334
1335        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1336        if (connId != null)
1337            gattClientWriteCharacteristicNative(connId, srvcType,
1338                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1339                srvcUuid.getMostSignificantBits(), charInstanceId,
1340                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1341                writeType, authReq, value);
1342        else
1343            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1344    }
1345
1346    void readDescriptor(int clientIf, String address, int srvcType,
1347                            int srvcInstanceId, UUID srvcUuid,
1348                            int charInstanceId, UUID charUuid,
1349                            int descrInstanceId, UUID descrUuid,
1350                            int authReq) {
1351        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1352
1353        if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address);
1354
1355        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1356        if (connId != null)
1357            gattClientReadDescriptorNative(connId, srvcType,
1358                srvcInstanceId,
1359                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1360                charInstanceId,
1361                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1362                descrInstanceId,
1363                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1364                authReq);
1365        else
1366            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1367    };
1368
1369    void writeDescriptor(int clientIf, String address, int srvcType,
1370                            int srvcInstanceId, UUID srvcUuid,
1371                            int charInstanceId, UUID charUuid,
1372                            int descrInstanceId, UUID descrUuid,
1373                            int writeType, int authReq, byte[] value) {
1374        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1375
1376        if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1377
1378        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1379        if (connId != null)
1380            gattClientWriteDescriptorNative(connId, srvcType,
1381                srvcInstanceId,
1382                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1383                charInstanceId,
1384                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1385                descrInstanceId,
1386                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1387                writeType, authReq, value);
1388        else
1389            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1390    }
1391
1392    void beginReliableWrite(int clientIf, String address) {
1393        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1394
1395        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1396        mReliableQueue.add(address);
1397    }
1398
1399    void endReliableWrite(int clientIf, String address, boolean execute) {
1400        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1401
1402        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1403                                + " execute: " + execute);
1404        mReliableQueue.remove(address);
1405
1406        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1407        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1408    }
1409
1410    void registerForNotification(int clientIf, String address, int srvcType,
1411                int srvcInstanceId, UUID srvcUuid,
1412                int charInstanceId, UUID charUuid,
1413                boolean enable) {
1414        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1415
1416        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1417
1418        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1419        if (connId != null) {
1420            gattClientRegisterForNotificationsNative(clientIf, address,
1421                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1422                srvcUuid.getMostSignificantBits(), charInstanceId,
1423                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1424                enable);
1425        } else {
1426            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1427        }
1428    }
1429
1430    void readRemoteRssi(int clientIf, String address) {
1431        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1432
1433        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1434        gattClientReadRemoteRssiNative(clientIf, address);
1435    }
1436
1437    void configureMTU(int clientIf, String address, int mtu) {
1438        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1439
1440        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1441        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1442        if (connId != null) {
1443            gattClientConfigureMTUNative(connId, mtu);
1444        } else {
1445            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1446        }
1447    }
1448
1449    void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
1450        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1451
1452        // Default spec recommended interval is 30->50 ms
1453        int minInterval = 24; // 24 * 1.25ms = 30ms
1454        int maxInterval = 40; // 40 * 1.25ms = 50ms
1455
1456        // Slave latency
1457        int latency = 0;
1458
1459        // Link supervision timeout is measured in N * 10ms
1460        int timeout = 2000; // 20s
1461
1462        switch (connectionPriority)
1463        {
1464            case BluetoothGatt.GATT_CONNECTION_HIGH_PRIORITY:
1465                minInterval = 6; // 7.5ms
1466                maxInterval = 8; // 10ms
1467                break;
1468
1469            case BluetoothGatt.GATT_CONNECTION_LOW_POWER:
1470                minInterval = 80; // 100ms
1471                maxInterval = 100; // 125ms
1472                latency = 2;
1473                break;
1474        }
1475
1476        if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address
1477            + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
1478        gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
1479                                            latency, timeout);
1480    }
1481
1482    /**************************************************************************
1483     * Callback functions - SERVER
1484     *************************************************************************/
1485
1486    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1487            throws RemoteException {
1488
1489        UUID uuid = new UUID(uuidMsb, uuidLsb);
1490        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1491        ServerMap.App app = mServerMap.getByUuid(uuid);
1492        if (app != null) {
1493            app.id = serverIf;
1494            app.linkToDeath(new ServerDeathRecipient(serverIf));
1495            app.callback.onServerRegistered(status, serverIf);
1496        }
1497    }
1498
1499    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1500                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1501                        throws RemoteException {
1502        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1503        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1504            + ", handle=" + srvcHandle);
1505        if (status == 0) {
1506            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1507                mAdvertisingServiceUuids.remove(uuid));
1508        }
1509
1510        continueServiceDeclaration(serverIf, status, srvcHandle);
1511    }
1512
1513    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1514                                int includedSrvcHandle) throws RemoteException {
1515        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1516            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1517        continueServiceDeclaration(serverIf, status, srvcHandle);
1518    }
1519
1520    void onCharacteristicAdded(int status, int serverIf,
1521                               long charUuidLsb, long charUuidMsb,
1522                               int srvcHandle, int charHandle)
1523                               throws RemoteException {
1524            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1525        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1526            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1527        if (status == 0)
1528            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1529        continueServiceDeclaration(serverIf, status, srvcHandle);
1530    }
1531
1532    void onDescriptorAdded(int status, int serverIf,
1533                           long descrUuidLsb, long descrUuidMsb,
1534                           int srvcHandle, int descrHandle)
1535                           throws RemoteException {
1536            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1537        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1538            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1539        if (status == 0)
1540            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1541        continueServiceDeclaration(serverIf, status, srvcHandle);
1542    }
1543
1544    void onServiceStarted(int status, int serverIf, int srvcHandle)
1545            throws RemoteException {
1546        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1547            + ", status=" + status);
1548        if (status == 0)
1549            mHandleMap.setStarted(serverIf, srvcHandle, true);
1550    }
1551
1552    void onServiceStopped(int status, int serverIf, int srvcHandle)
1553            throws RemoteException {
1554        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1555            + ", status=" + status);
1556        if (status == 0)
1557            mHandleMap.setStarted(serverIf, srvcHandle, false);
1558        stopNextService(serverIf, status);
1559    }
1560
1561    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1562        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1563            + ", status=" + status);
1564        mHandleMap.deleteService(serverIf, srvcHandle);
1565    }
1566
1567    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1568            throws RemoteException {
1569
1570        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1571            + ", address=" + address + ", connected=" + connected);
1572
1573        ServerMap.App app = mServerMap.getById(serverIf);
1574        if (app == null) return;
1575
1576        if (connected) {
1577            mServerMap.addConnection(serverIf, connId, address);
1578        } else {
1579            mServerMap.removeConnection(serverIf, connId);
1580        }
1581
1582        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1583    }
1584
1585    void onAttributeRead(String address, int connId, int transId,
1586                            int attrHandle, int offset, boolean isLong)
1587                            throws RemoteException {
1588        if (VDBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1589            + ", address=" + address + ", handle=" + attrHandle
1590            + ", requestId=" + transId + ", offset=" + offset);
1591
1592        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1593        if (entry == null) return;
1594
1595        if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid
1596            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1597
1598        mHandleMap.addRequest(transId, attrHandle);
1599
1600        ServerMap.App app = mServerMap.getById(entry.serverIf);
1601        if (app == null) return;
1602
1603        switch(entry.type) {
1604            case HandleMap.TYPE_CHARACTERISTIC:
1605            {
1606                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1607                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1608                    serviceEntry.serviceType, serviceEntry.instance,
1609                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1610                    new ParcelUuid(entry.uuid));
1611                break;
1612            }
1613
1614            case HandleMap.TYPE_DESCRIPTOR:
1615            {
1616                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1617                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1618                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1619                    serviceEntry.serviceType, serviceEntry.instance,
1620                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1621                    new ParcelUuid(charEntry.uuid),
1622                    new ParcelUuid(entry.uuid));
1623                break;
1624            }
1625
1626            default:
1627                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1628                break;
1629        }
1630    }
1631
1632    void onAttributeWrite(String address, int connId, int transId,
1633                            int attrHandle, int offset, int length,
1634                            boolean needRsp, boolean isPrep,
1635                            byte[] data)
1636                            throws RemoteException {
1637        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1638            + ", address=" + address + ", handle=" + attrHandle
1639            + ", requestId=" + transId + ", isPrep=" + isPrep
1640            + ", offset=" + offset);
1641
1642        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1643        if (entry == null) return;
1644
1645        if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid
1646            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1647
1648        mHandleMap.addRequest(transId, attrHandle);
1649
1650        ServerMap.App app = mServerMap.getById(entry.serverIf);
1651        if (app == null) return;
1652
1653        switch(entry.type) {
1654            case HandleMap.TYPE_CHARACTERISTIC:
1655            {
1656                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1657                app.callback.onCharacteristicWriteRequest(address, transId,
1658                            offset, length, isPrep, needRsp,
1659                            serviceEntry.serviceType, serviceEntry.instance,
1660                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1661                            new ParcelUuid(entry.uuid), data);
1662                break;
1663            }
1664
1665            case HandleMap.TYPE_DESCRIPTOR:
1666            {
1667                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1668                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1669                app.callback.onDescriptorWriteRequest(address, transId,
1670                            offset, length, isPrep, needRsp,
1671                            serviceEntry.serviceType, serviceEntry.instance,
1672                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1673                            new ParcelUuid(charEntry.uuid),
1674                            new ParcelUuid(entry.uuid), data);
1675                break;
1676            }
1677
1678            default:
1679                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1680                break;
1681        }
1682    }
1683
1684    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1685            throws RemoteException {
1686        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1687            + ", address=" + address + ", transId=" + transId);
1688
1689        ServerMap.App app = mServerMap.getByConnId(connId);
1690        if (app == null) return;
1691
1692        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1693    }
1694
1695    void onResponseSendCompleted(int status, int attrHandle) {
1696        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1697    }
1698
1699    void onNotificationSent(int connId, int status) throws RemoteException {
1700        if (DBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
1701
1702        String address = mServerMap.addressByConnId(connId);
1703        if (address == null) return;
1704
1705        ServerMap.App app = mServerMap.getByConnId(connId);
1706        if (app == null) return;
1707
1708        app.callback.onNotificationSent(address, status);
1709    }
1710
1711    void onServerCongestion(int connId, boolean congested) throws RemoteException {
1712        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
1713
1714        ServerMap.App app = mServerMap.getByConnId(connId);
1715        if (app != null) {
1716            app.callback.onConnectionCongested(mServerMap.addressByConnId(connId), congested);
1717        }
1718    }
1719
1720    /**************************************************************************
1721     * GATT Service functions - SERVER
1722     *************************************************************************/
1723
1724    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1725        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1726
1727        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1728        mServerMap.add(uuid, callback);
1729        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1730                                    uuid.getMostSignificantBits());
1731    }
1732
1733    void unregisterServer(int serverIf) {
1734        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1735
1736        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1737
1738        deleteServices(serverIf);
1739
1740        mServerMap.remove(serverIf);
1741        gattServerUnregisterAppNative(serverIf);
1742    }
1743
1744    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1745        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1746
1747        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1748        gattServerConnectNative(serverIf, address, isDirect,transport);
1749    }
1750
1751    void serverDisconnect(int serverIf, String address) {
1752        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1753
1754        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1755        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1756
1757        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1758    }
1759
1760    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1761                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1762        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1763
1764        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1765        ServiceDeclaration serviceDeclaration = addDeclaration();
1766        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1767            advertisePreferred);
1768    }
1769
1770    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1771                            UUID srvcUuid) {
1772        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1773
1774        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1775        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1776    }
1777
1778    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1779                           int permissions) {
1780        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1781
1782        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1783        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1784    }
1785
1786    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1787        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1788
1789        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1790        getActiveDeclaration().addDescriptor(descUuid, permissions);
1791    }
1792
1793    void endServiceDeclaration(int serverIf) {
1794        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1795
1796        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1797
1798        if (getActiveDeclaration() == getPendingDeclaration()) {
1799            try {
1800                continueServiceDeclaration(serverIf, (byte)0, 0);
1801            } catch (RemoteException e) {
1802                Log.e(TAG,""+e);
1803            }
1804        }
1805    }
1806
1807    void removeService(int serverIf, int srvcType,
1808                  int srvcInstanceId, UUID srvcUuid) {
1809        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1810
1811        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
1812
1813        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1814        if (srvcHandle == 0) return;
1815        gattServerDeleteServiceNative(serverIf, srvcHandle);
1816    }
1817
1818    void clearServices(int serverIf) {
1819        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1820
1821        if (DBG) Log.d(TAG, "clearServices()");
1822        deleteServices(serverIf);
1823    }
1824
1825    void sendResponse(int serverIf, String address, int requestId,
1826                      int status, int offset, byte[] value) {
1827        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1828
1829        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
1830
1831        int handle = 0;
1832        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
1833        if (entry != null) handle = entry.handle;
1834
1835        int connId = mServerMap.connIdByAddress(serverIf, address);
1836        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
1837                                     handle, offset, value, (byte)0);
1838        mHandleMap.deleteRequest(requestId);
1839    }
1840
1841    void sendNotification(int serverIf, String address, int srvcType,
1842                                 int srvcInstanceId, UUID srvcUuid,
1843                                 int charInstanceId, UUID charUuid,
1844                                 boolean confirm, byte[] value) {
1845        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1846
1847        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address);
1848
1849        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1850        if (srvcHandle == 0) return;
1851
1852        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
1853        if (charHandle == 0) return;
1854
1855        int connId = mServerMap.connIdByAddress(serverIf, address);
1856        if (connId == 0) return;
1857
1858        if (confirm) {
1859            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
1860        } else {
1861            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
1862        }
1863    }
1864
1865
1866    /**************************************************************************
1867     * Private functions
1868     *************************************************************************/
1869
1870    private int getDeviceType(BluetoothDevice device) {
1871        int type = gattClientGetDeviceTypeNative(device.getAddress());
1872        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
1873            + ", type=" + type);
1874        return type;
1875    }
1876
1877    private void enforceAdminPermission() {
1878        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1879    }
1880
1881    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
1882    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
1883    private void enforcePrivilegedPermission() {
1884        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
1885            "Need BLUETOOTH_PRIVILEGED permission");
1886    }
1887
1888    private void continueSearch(int connId, int status) throws RemoteException {
1889        if (status == 0 && !mSearchQueue.isEmpty()) {
1890            SearchQueue.Entry svc = mSearchQueue.pop();
1891
1892            if (svc.charUuidLsb == 0) {
1893                // Characteristic is up next
1894                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
1895                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
1896            } else {
1897                // Descriptor is up next
1898                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
1899                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
1900                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
1901            }
1902        } else {
1903            ClientMap.App app = mClientMap.getByConnId(connId);
1904            if (app != null) {
1905                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
1906            }
1907        }
1908    }
1909
1910    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
1911        if (mServiceDeclarations.size() == 0) return;
1912        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
1913
1914        boolean finished = false;
1915
1916        ServiceDeclaration.Entry entry = null;
1917        if (status == 0)
1918            entry = getPendingDeclaration().getNext();
1919
1920        if (entry != null) {
1921            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
1922                + entry.type);
1923            switch(entry.type) {
1924                case ServiceDeclaration.TYPE_SERVICE:
1925                    if (entry.advertisePreferred) {
1926                        mAdvertisingServiceUuids.add(entry.uuid);
1927                    }
1928                    gattServerAddServiceNative(serverIf, entry.serviceType,
1929                        entry.instance,
1930                        entry.uuid.getLeastSignificantBits(),
1931                        entry.uuid.getMostSignificantBits(),
1932                        getPendingDeclaration().getNumHandles());
1933                    break;
1934
1935                case ServiceDeclaration.TYPE_CHARACTERISTIC:
1936                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
1937                        entry.uuid.getLeastSignificantBits(),
1938                        entry.uuid.getMostSignificantBits(),
1939                        entry.properties, entry.permissions);
1940                    break;
1941
1942                case ServiceDeclaration.TYPE_DESCRIPTOR:
1943                    gattServerAddDescriptorNative(serverIf, srvcHandle,
1944                        entry.uuid.getLeastSignificantBits(),
1945                        entry.uuid.getMostSignificantBits(),
1946                        entry.permissions);
1947                    break;
1948
1949                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
1950                {
1951                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
1952                                            entry.serviceType, entry.instance);
1953                    if (inclSrvc != 0) {
1954                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
1955                                                           inclSrvc);
1956                    } else {
1957                        finished = true;
1958                    }
1959                    break;
1960                }
1961            }
1962        } else {
1963            gattServerStartServiceNative(serverIf, srvcHandle,
1964                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
1965            finished = true;
1966        }
1967
1968        if (finished) {
1969            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
1970            ServerMap.App app = mServerMap.getById(serverIf);
1971            if (app != null) {
1972                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
1973
1974                if (serviceEntry != null) {
1975                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
1976                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
1977                } else {
1978                    app.callback.onServiceAdded(status, 0, 0, null);
1979                }
1980            }
1981            removePendingDeclaration();
1982
1983            if (getPendingDeclaration() != null) {
1984                continueServiceDeclaration(serverIf, (byte)0, 0);
1985            }
1986        }
1987    }
1988
1989    private void stopNextService(int serverIf, int status) throws RemoteException {
1990        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
1991            + ", status=" + status);
1992
1993        if (status == 0) {
1994            List<HandleMap.Entry> entries = mHandleMap.getEntries();
1995            for(HandleMap.Entry entry : entries) {
1996                if (entry.type != HandleMap.TYPE_SERVICE ||
1997                    entry.serverIf != serverIf ||
1998                    entry.started == false)
1999                        continue;
2000
2001                gattServerStopServiceNative(serverIf, entry.handle);
2002                return;
2003            }
2004        }
2005    }
2006
2007    private void deleteServices(int serverIf) {
2008        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2009
2010        /*
2011         * Figure out which handles to delete.
2012         * The handles are copied into a new list to avoid race conditions.
2013         */
2014        List<Integer> handleList = new ArrayList<Integer>();
2015        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2016        for(HandleMap.Entry entry : entries) {
2017            if (entry.type != HandleMap.TYPE_SERVICE ||
2018                entry.serverIf != serverIf)
2019                    continue;
2020            handleList.add(entry.handle);
2021        }
2022
2023        /* Now actually delete the services.... */
2024        for(Integer handle : handleList) {
2025            gattServerDeleteServiceNative(serverIf, handle);
2026        }
2027    }
2028
2029    private List<UUID> parseUuids(byte[] adv_data) {
2030        List<UUID> uuids = new ArrayList<UUID>();
2031
2032        int offset = 0;
2033        while(offset < (adv_data.length-2)) {
2034            int len = adv_data[offset++];
2035            if (len == 0) break;
2036
2037            int type = adv_data[offset++];
2038            switch (type) {
2039                case 0x02: // Partial list of 16-bit UUIDs
2040                case 0x03: // Complete list of 16-bit UUIDs
2041                    while (len > 1) {
2042                        int uuid16 = adv_data[offset++];
2043                        uuid16 += (adv_data[offset++] << 8);
2044                        len -= 2;
2045                        uuids.add(UUID.fromString(String.format(
2046                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2047                    }
2048                    break;
2049
2050                default:
2051                    offset += (len - 1);
2052                    break;
2053            }
2054        }
2055
2056        return uuids;
2057    }
2058
2059    /**************************************************************************
2060     * GATT Test functions
2061     *************************************************************************/
2062
2063    void gattTestCommand(int command, UUID uuid1, String bda1,
2064                         int p1, int p2, int p3, int p4, int p5) {
2065        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2066        if (uuid1 != null)
2067            gattTestNative(command, uuid1.getLeastSignificantBits(),
2068                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2069        else
2070            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2071    }
2072
2073    private native void gattTestNative(int command,
2074                                    long uuid1_lsb, long uuid1_msb, String bda1,
2075                                    int p1, int p2, int p3, int p4, int p5);
2076
2077    /**************************************************************************
2078     * Native functions prototypes
2079     *************************************************************************/
2080
2081    private native static void classInitNative();
2082    private native void initializeNative();
2083    private native void cleanupNative();
2084
2085    private native int gattClientGetDeviceTypeNative(String address);
2086
2087    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2088                                                    long app_uuid_msb);
2089
2090    private native void gattClientUnregisterAppNative(int clientIf);
2091
2092    private native void gattClientConnectNative(int clientIf, String address,
2093            boolean isDirect, int transport);
2094
2095    private native void gattClientDisconnectNative(int clientIf, String address,
2096            int conn_id);
2097
2098    private native void gattClientRefreshNative(int clientIf, String address);
2099
2100    private native void gattClientSearchServiceNative(int conn_id,
2101            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2102
2103    private native void gattClientGetCharacteristicNative(int conn_id,
2104            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2105            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2106            long char_id_uuid_msb);
2107
2108    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2109            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2110            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2111            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2112
2113    private native void gattClientGetIncludedServiceNative(int conn_id,
2114            int service_type, int service_id_inst_id,
2115            long service_id_uuid_lsb, long service_id_uuid_msb,
2116            int incl_service_id_inst_id, int incl_service_type,
2117            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2118
2119    private native void gattClientReadCharacteristicNative(int conn_id,
2120            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2121            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2122            long char_id_uuid_msb, int authReq);
2123
2124    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2125            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2126            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2127            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2128            int authReq);
2129
2130    private native void gattClientWriteCharacteristicNative(int conn_id,
2131            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2132            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2133            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2134
2135    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2136            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2137            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2138            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2139            int write_type, int auth_req, byte[] value);
2140
2141    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2142
2143    private native void gattClientRegisterForNotificationsNative(int clientIf,
2144            String address, int service_type, int service_id_inst_id,
2145            long service_id_uuid_lsb, long service_id_uuid_msb,
2146            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2147            boolean enable);
2148
2149    private native void gattClientReadRemoteRssiNative(int clientIf,
2150            String address);
2151
2152    private native void gattAdvertiseNative(int client_if, boolean start);
2153
2154    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2155
2156    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2157            int minInterval, int maxInterval, int latency, int timeout);
2158
2159    private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
2160            boolean inclTxPower, int minInterval, int maxInterval,
2161            int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
2162
2163    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2164                                                    long app_uuid_msb);
2165
2166    private native void gattServerUnregisterAppNative(int serverIf);
2167
2168    private native void gattServerConnectNative(int server_if, String address,
2169                                             boolean is_direct, int transport);
2170
2171    private native void gattServerDisconnectNative(int serverIf, String address,
2172                                              int conn_id);
2173
2174    private native void gattServerAddServiceNative (int server_if,
2175            int service_type, int service_id_inst_id,
2176            long service_id_uuid_lsb, long service_id_uuid_msb,
2177            int num_handles);
2178
2179    private native void gattServerAddIncludedServiceNative (int server_if,
2180            int svc_handle, int included_svc_handle);
2181
2182    private native void gattServerAddCharacteristicNative (int server_if,
2183            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2184            int properties, int permissions);
2185
2186    private native void gattServerAddDescriptorNative (int server_if,
2187            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2188            int permissions);
2189
2190    private native void gattServerStartServiceNative (int server_if,
2191            int svc_handle, int transport );
2192
2193    private native void gattServerStopServiceNative (int server_if,
2194                                                     int svc_handle);
2195
2196    private native void gattServerDeleteServiceNative (int server_if,
2197                                                       int svc_handle);
2198
2199    private native void gattServerSendIndicationNative (int server_if,
2200            int attr_handle, int conn_id, byte[] val);
2201
2202    private native void gattServerSendNotificationNative (int server_if,
2203            int attr_handle, int conn_id, byte[] val);
2204
2205    private native void gattServerSendResponseNative (int server_if,
2206            int conn_id, int trans_id, int status, int handle, int offset,
2207            byte[] val, int auth_req);
2208}
2209