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