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