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