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