GattService.java revision 32088854fd6a8bb5e570a4a1df4eaf2eb19d7ae3
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    /**************************************************************************
1154     * GATT Service functions - Shared CLIENT/SERVER
1155     *************************************************************************/
1156
1157    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
1158        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1159
1160        final int DEVICE_TYPE_BREDR = 0x1;
1161
1162        Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice,
1163                                                                 Integer>();
1164
1165        // Add paired LE devices
1166
1167        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
1168        for (BluetoothDevice device : bondedDevices) {
1169            if (getDeviceType(device) != DEVICE_TYPE_BREDR) {
1170                deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
1171            }
1172        }
1173
1174        // Add connected deviceStates
1175
1176        Set<String> connectedDevices = new HashSet<String>();
1177        connectedDevices.addAll(mClientMap.getConnectedDevices());
1178        connectedDevices.addAll(mServerMap.getConnectedDevices());
1179
1180        for (String address : connectedDevices ) {
1181            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1182            if (device != null) {
1183                deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
1184            }
1185        }
1186
1187        // Create matching device sub-set
1188
1189        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
1190
1191        for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
1192            for(int state : states) {
1193                if (entry.getValue() == state) {
1194                    deviceList.add(entry.getKey());
1195                }
1196            }
1197        }
1198
1199        return deviceList;
1200    }
1201
1202    void startScan(int appIf, boolean isServer) {
1203        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1204
1205        if (DBG) Log.d(TAG, "startScan() - queue=" + mScanQueue.size());
1206
1207        if (getScanClient(appIf, isServer) == null) {
1208            if (DBG) Log.d(TAG, "startScan() - adding client=" + appIf);
1209            mScanQueue.add(new ScanClient(appIf, isServer));
1210        }
1211        configureScanParams();
1212    }
1213
1214
1215    void startScanWithUuids(int appIf, boolean isServer, UUID[] uuids) {
1216        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1217
1218        if (DBG) Log.d(TAG, "startScanWithUuids() - queue=" + mScanQueue.size());
1219
1220        if (getScanClient(appIf, isServer) == null) {
1221            if (DBG) Log.d(TAG, "startScanWithUuids() - adding client=" + appIf);
1222            mScanQueue.add(new ScanClient(appIf, isServer, uuids));
1223        }
1224        configureScanParams();
1225    }
1226
1227    void startScanWithFilters(int appIf, boolean isServer, ScanSettings settings,
1228            List<ScanFilter> filters) {
1229        if (DBG) Log.d(TAG, "start scan with filters " + filters.size());
1230        enforceAdminPermission();
1231        // TODO: use settings to configure scan params.
1232        // TODO: move logic to state machine to avoid locking.
1233        synchronized(mScanQueue) {
1234            boolean isScaning = (!mScanQueue.isEmpty());
1235            if (getScanClient(appIf, isServer) == null) {
1236                if (DBG) Log.d(TAG, "startScan() - adding client=" + appIf);
1237                mScanQueue.add(new ScanClient(appIf, isServer, settings, filters));
1238            }
1239            Set<ScanFilter> newFilters = configureScanFiltersLocked();
1240            if (isScaning) {
1241                // Reset scan filters if BLE scan was started and scan filters changed.
1242                if (!Objects.deepEquals(newFilters, mScanFilters)) {
1243                    mScanFilters = newFilters;
1244                    // Restart scan using new filters.
1245                    sendStopScanMessage();
1246                    sendStartScanMessage(mScanFilters);
1247                }
1248            } else {
1249                // Always start scanning with new filters if scan not started yet.
1250                mScanFilters = newFilters;
1251                sendStartScanMessage(mScanFilters);
1252            }
1253        }
1254    }
1255
1256    void configureScanParams() {
1257        if (DBG) Log.d(TAG, "configureScanParams() - queue=" + mScanQueue.size());
1258        int curScanSetting = Integer.MIN_VALUE;
1259
1260        for(ScanClient client : mScanQueue) {
1261            // ScanClient scan settings are assumed to be monotonically increasing in value for more
1262            // power hungry(higher duty cycle) operation
1263            if (client.settings.getScanMode() > curScanSetting) {
1264                curScanSetting = client.settings.getScanMode();
1265            }
1266        }
1267
1268        if (DBG) Log.d(TAG, "configureScanParams() - ScanSetting Scan mode=" + curScanSetting +
1269                    " lastConfiguredScanSetting=" + lastConfiguredScanSetting);
1270
1271        if (curScanSetting != Integer.MIN_VALUE) {
1272            if (curScanSetting != lastConfiguredScanSetting) {
1273                int scanWindow, scanInterval;
1274                switch (curScanSetting){
1275                    case ScanSettings.SCAN_MODE_LOW_POWER:
1276                        scanWindow = SCAN_MODE_LOW_POWER_WINDOW_MS;
1277                        scanInterval = SCAN_MODE_LOW_POWER_INTERVAL_MS;
1278                        break;
1279                    case ScanSettings.SCAN_MODE_BALANCED:
1280                        scanWindow = SCAN_MODE_BALANCED_WINDOW_MS;
1281                        scanInterval = SCAN_MODE_BALANCED_INTERVAL_MS;
1282                        break;
1283                    case ScanSettings.SCAN_MODE_LOW_LATENCY:
1284                        scanWindow = SCAN_MODE_LOW_LATENCY_WINDOW_MS;
1285                        scanInterval = SCAN_MODE_LOW_LATENCY_INTERVAL_MS;
1286                        break;
1287                    default:
1288                        Log.e(TAG, "Invalid value for curScanSetting " + curScanSetting);
1289                        scanWindow = SCAN_MODE_LOW_POWER_WINDOW_MS;
1290                        scanInterval = SCAN_MODE_LOW_POWER_INTERVAL_MS;
1291                        break;
1292                }
1293                // convert scanWindow and scanInterval from ms to LE scan units(0.625ms)
1294                scanWindow = (scanWindow * 1000)/625;
1295                scanInterval = (scanInterval * 1000)/625;
1296                // Presence of scan clients means scan is active.
1297                sendStopScanMessage();
1298                gattSetScanParametersNative(scanInterval, scanWindow);
1299                lastConfiguredScanSetting = curScanSetting;
1300                mScanFilters.clear();
1301                sendStartScanMessage(mScanFilters);
1302            } else {
1303                // Duty cycle did not change but scan filters changed.
1304                if (!mScanFilters.isEmpty()) {
1305                    mScanFilters.clear();
1306                    sendStopScanMessage();
1307                    sendStartScanMessage(mScanFilters);
1308                }
1309            }
1310        } else {
1311            lastConfiguredScanSetting = curScanSetting;
1312            mScanFilters.clear();
1313            sendStopScanMessage();
1314            if (DBG) Log.d(TAG, "configureScanParams() - queue emtpy, scan stopped");
1315        }
1316    }
1317
1318    private Set<ScanFilter> configureScanFiltersLocked() {
1319        Set<ScanFilter> filters = new HashSet<ScanFilter>();
1320        for (ScanClient client : mScanQueue) {
1321            if (client.filters == null || client.filters.isEmpty()) {
1322                filters.clear();
1323                return filters;
1324            }
1325            filters.addAll(client.filters);
1326        }
1327
1328        AdapterService adapter = AdapterService.getAdapterService();
1329        if (filters.size() > adapter.getNumOfOffloadedScanFilterSupported()) {
1330            if (DBG) Log.d(TAG, "filters size > " + adapter.getNumOfOffloadedScanFilterSupported()
1331                    + ", clearing filters");
1332            filters = new HashSet<ScanFilter>();
1333        }
1334        return filters;
1335    }
1336
1337    /**
1338     * Returns whether scan filter is supported.
1339     */
1340    boolean isScanFilterSupported() {
1341        AdapterService adapter = AdapterService.getAdapterService();
1342        return adapter.getNumOfOffloadedScanFilterSupported() > 0;
1343    }
1344
1345    private void sendStartScanMessage(Set<ScanFilter> filters) {
1346        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.START_BLE_SCAN);
1347        message.obj = filters;
1348        mStateMachine.sendMessage(message);
1349    }
1350
1351    private void sendStopScanMessage() {
1352        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.STOP_BLE_SCAN);
1353        mStateMachine.sendMessage(message);
1354    }
1355
1356    void stopScan(int appIf, boolean isServer) {
1357        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH_ADMIN permission");
1358
1359        if (DBG) Log.d(TAG, "stopScan() - queue=" + mScanQueue.size());
1360        removeScanClient(appIf, isServer);
1361        configureScanParams();
1362
1363        if (mScanQueue.isEmpty()) {
1364            if (DBG) Log.d(TAG, "stopScan() - queue empty; stopping scan");
1365        }
1366    }
1367
1368    /**************************************************************************
1369     * GATT Service functions - CLIENT
1370     *************************************************************************/
1371
1372    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
1373        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1374
1375        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1376        mClientMap.add(uuid, callback);
1377        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1378                                    uuid.getMostSignificantBits());
1379    }
1380
1381    void unregisterClient(int clientIf) {
1382        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1383
1384        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1385        mClientMap.remove(clientIf);
1386        gattClientUnregisterAppNative(clientIf);
1387    }
1388
1389    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1390        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1391
1392        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1393        gattClientConnectNative(clientIf, address, isDirect, transport);
1394    }
1395
1396    void clientDisconnect(int clientIf, String address) {
1397        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1398
1399        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1400        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1401
1402        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1403    }
1404
1405    synchronized boolean setAdvServiceData(byte[] serviceData) {
1406        enforcePrivilegedPermission();
1407        if (serviceData == null) return false;
1408        // Calculate how many more bytes are needed for advertising service data field.
1409        int extraBytes = (mServiceData == null) ?
1410                FIELD_OVERHEAD_BYTES + serviceData.length :
1411                    serviceData.length - mServiceData.length;
1412        if (getAvailableSize() < extraBytes) {
1413            Log.e(TAG, "cannot set service data, available size " + getAvailableSize());
1414            return false;
1415        }
1416        mServiceData = serviceData;
1417        return true;
1418    }
1419
1420    byte[] getAdvServiceData() {
1421        enforcePrivilegedPermission();
1422        return mServiceData;
1423    }
1424
1425    synchronized boolean setAdvManufacturerCodeAndData(
1426        int manufacturerCode, byte[] manufacturerData) {
1427        enforcePrivilegedPermission();
1428        if (manufacturerCode <= 0 || manufacturerData == null) {
1429            return false;
1430        }
1431        if (mManufacturerCode > 0 && mManufacturerData != null) {
1432            Log.e(TAG, "manufacture data is already set");
1433            return false;
1434        }
1435        if (getAvailableSize() <
1436            FIELD_OVERHEAD_BYTES + manufacturerData.length) {
1437            Log.e(TAG, "cannot set manu data, available size " + getAvailableSize());
1438            return false;
1439        }
1440        this.mManufacturerCode = manufacturerCode;
1441        this.mManufacturerData = manufacturerData;
1442        return true;
1443    }
1444
1445    void removeAdvManufacturerCodeAndData(int manufacturerCode) {
1446        enforcePrivilegedPermission();
1447        if (mManufacturerCode != manufacturerCode) {
1448            return;
1449        }
1450        mManufacturerCode = -1;
1451        mManufacturerData = new byte[0];
1452    }
1453
1454    byte[] getAdvManufacturerData() {
1455        enforcePrivilegedPermission();
1456        return mManufacturerData;
1457    }
1458
1459    synchronized List<ParcelUuid> getAdvServiceUuids() {
1460        enforcePrivilegedPermission();
1461        boolean fullUuidFound = false;
1462        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1463        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1464            if (entry.advertisePreferred) {
1465                ParcelUuid parcelUuid = new ParcelUuid(entry.uuid);
1466                if (BluetoothUuid.is16BitUuid(parcelUuid)) {
1467                    serviceUuids.add(parcelUuid);
1468                } else {
1469                    // Allow at most one 128 bit service uuid to be advertised.
1470                    if (!fullUuidFound) {
1471                      fullUuidFound = true;
1472                      serviceUuids.add(parcelUuid);
1473                    }
1474                }
1475            }
1476        }
1477        return serviceUuids;
1478    }
1479
1480    boolean isAdvertising() {
1481        enforcePrivilegedPermission();
1482        return mAdvertisingState != BluetoothAdapter.STATE_ADVERTISE_STOPPED;
1483    }
1484
1485    void startAdvertising(int clientIf) {
1486        enforcePrivilegedPermission();
1487        if (DBG) Log.d(TAG, "start advertising for app - " + clientIf);
1488        List<ParcelUuid> serviceUuids = getAdvServiceUuids();
1489        int advertisingServiceUuidLength = serviceUuids == null ? 0 : serviceUuids.size();
1490
1491        // Note according to Bluetooth Spec Version 4.0, for advertising and scan response data
1492        // "all numerical multi-byte entities and values shall use little-endian byte order".
1493        ByteBuffer advertisingUuidBytes = ByteBuffer.allocate(advertisingServiceUuidLength * 16)
1494                .order(ByteOrder.LITTLE_ENDIAN);
1495        for (ParcelUuid parcelUuid : serviceUuids) {
1496            UUID uuid = parcelUuid.getUuid();
1497            // Least signifcant bits first as the advertising uuid should be in little-endian.
1498            advertisingUuidBytes.putLong(uuid.getLeastSignificantBits())
1499                    .putLong(uuid.getMostSignificantBits());
1500        }
1501
1502        // Set advertising data.
1503        gattSetAdvDataNative(clientIf,
1504                false,  // not scan response data
1505                false,  // no device name
1506                false,  // no tx power included
1507                DEFAULT_SCAN_INTERVAL_MILLIS,
1508                DEFAULT_SCAN_INTERVAL_MILLIS,
1509                0,  // no appearance limit
1510                mManufacturerData,
1511                mServiceData,
1512                advertisingUuidBytes.array());
1513
1514        // Start advertising if advertising is not already started.
1515        if (!isAdvertising()) {
1516            gattAdvertiseNative(clientIf, true);
1517            mAdvertisingClientIf = clientIf;
1518            mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STARTING;
1519        }
1520    }
1521
1522    void stopAdvertising() {
1523        stopAdvertising(false);
1524    }
1525
1526    void stopAdvertising(boolean forceStop) {
1527        enforcePrivilegedPermission();
1528        gattAdvertiseNative(mAdvertisingClientIf, false);
1529        synchronized (mLock) {
1530            if (forceStop) {
1531                mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_FORCE_STOPPING;
1532            } else {
1533                mAdvertisingState = BluetoothAdapter.STATE_ADVERTISE_STOPPING;
1534            }
1535        }
1536    }
1537
1538    void startMultiAdvertising(int clientIf, AdvertisementData advertiseData,
1539            AdvertisementData scanResponse, AdvertiseSettings settings) {
1540        enforceAdminPermission();
1541        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.START_ADVERTISING);
1542        message.obj = new AdvertiseClient(clientIf, settings, advertiseData, scanResponse);
1543        mStateMachine.sendMessage(message);
1544    }
1545
1546    void stopMultiAdvertising(int clientIf) {
1547        enforceAdminPermission();
1548        Message message = mStateMachine.obtainMessage(GattServiceStateMachine.STOP_ADVERTISING);
1549        message.arg1 = clientIf;
1550        mStateMachine.sendMessage(message);
1551    }
1552
1553    List<String> getConnectedDevices() {
1554        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1555
1556        Set<String> connectedDevAddress = new HashSet<String>();
1557        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1558        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1559        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1560        return connectedDeviceList;
1561    }
1562
1563    void refreshDevice(int clientIf, String address) {
1564        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1565
1566        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1567        gattClientRefreshNative(clientIf, address);
1568    }
1569
1570    void discoverServices(int clientIf, String address) {
1571        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1572
1573        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1574        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1575
1576        if (connId != null)
1577            gattClientSearchServiceNative(connId, true, 0, 0);
1578        else
1579            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1580    }
1581
1582    void readCharacteristic(int clientIf, String address, int srvcType,
1583                            int srvcInstanceId, UUID srvcUuid,
1584                            int charInstanceId, UUID charUuid, int authReq) {
1585        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1586
1587        if (DBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1588
1589        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1590        if (connId != null)
1591            gattClientReadCharacteristicNative(connId, srvcType,
1592                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1593                srvcUuid.getMostSignificantBits(), charInstanceId,
1594                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1595                authReq);
1596        else
1597            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1598    }
1599
1600    void writeCharacteristic(int clientIf, String address, int srvcType,
1601                             int srvcInstanceId, UUID srvcUuid,
1602                             int charInstanceId, UUID charUuid, int writeType,
1603                             int authReq, byte[] value) {
1604        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1605
1606        if (DBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1607
1608        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1609
1610        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1611        if (connId != null)
1612            gattClientWriteCharacteristicNative(connId, srvcType,
1613                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1614                srvcUuid.getMostSignificantBits(), charInstanceId,
1615                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1616                writeType, authReq, value);
1617        else
1618            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1619    }
1620
1621    void readDescriptor(int clientIf, String address, int srvcType,
1622                            int srvcInstanceId, UUID srvcUuid,
1623                            int charInstanceId, UUID charUuid,
1624                            int descrInstanceId, UUID descrUuid,
1625                            int authReq) {
1626        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1627
1628        if (DBG) Log.d(TAG, "readDescriptor() - address=" + address);
1629
1630        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1631        if (connId != null)
1632            gattClientReadDescriptorNative(connId, srvcType,
1633                srvcInstanceId,
1634                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1635                charInstanceId,
1636                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1637                descrInstanceId,
1638                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1639                authReq);
1640        else
1641            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1642    };
1643
1644    void writeDescriptor(int clientIf, String address, int srvcType,
1645                            int srvcInstanceId, UUID srvcUuid,
1646                            int charInstanceId, UUID charUuid,
1647                            int descrInstanceId, UUID descrUuid,
1648                            int writeType, int authReq, byte[] value) {
1649        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1650
1651        if (DBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1652
1653        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1654        if (connId != null)
1655            gattClientWriteDescriptorNative(connId, srvcType,
1656                srvcInstanceId,
1657                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1658                charInstanceId,
1659                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1660                descrInstanceId,
1661                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1662                writeType, authReq, value);
1663        else
1664            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1665    }
1666
1667    void beginReliableWrite(int clientIf, String address) {
1668        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1669
1670        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1671        mReliableQueue.add(address);
1672    }
1673
1674    void endReliableWrite(int clientIf, String address, boolean execute) {
1675        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1676
1677        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1678                                + " execute: " + execute);
1679        mReliableQueue.remove(address);
1680
1681        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1682        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1683    }
1684
1685    void registerForNotification(int clientIf, String address, int srvcType,
1686                int srvcInstanceId, UUID srvcUuid,
1687                int charInstanceId, UUID charUuid,
1688                boolean enable) {
1689        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1690
1691        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1692
1693        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1694        if (connId != null) {
1695            gattClientRegisterForNotificationsNative(clientIf, address,
1696                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1697                srvcUuid.getMostSignificantBits(), charInstanceId,
1698                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1699                enable);
1700        } else {
1701            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1702        }
1703    }
1704
1705    void readRemoteRssi(int clientIf, String address) {
1706        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1707
1708        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1709        gattClientReadRemoteRssiNative(clientIf, address);
1710    }
1711
1712    void configureMTU(int clientIf, String address, int mtu) {
1713        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1714
1715        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1716        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1717        if (connId != null) {
1718            gattClientConfigureMTUNative(connId, mtu);
1719        } else {
1720            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1721        }
1722    }
1723
1724    /**************************************************************************
1725     * Callback functions - SERVER
1726     *************************************************************************/
1727
1728    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1729            throws RemoteException {
1730
1731        UUID uuid = new UUID(uuidMsb, uuidLsb);
1732        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1733        ServerMap.App app = mServerMap.getByUuid(uuid);
1734        if (app != null) {
1735            app.id = serverIf;
1736            app.linkToDeath(new ServerDeathRecipient(serverIf));
1737            app.callback.onServerRegistered(status, serverIf);
1738        }
1739    }
1740
1741    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1742                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1743                        throws RemoteException {
1744        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1745        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1746            + ", handle=" + srvcHandle);
1747        if (status == 0) {
1748            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1749                mAdvertisingServiceUuids.remove(uuid));
1750        }
1751
1752        continueServiceDeclaration(serverIf, status, srvcHandle);
1753    }
1754
1755    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1756                                int includedSrvcHandle) throws RemoteException {
1757        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1758            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1759        continueServiceDeclaration(serverIf, status, srvcHandle);
1760    }
1761
1762    void onCharacteristicAdded(int status, int serverIf,
1763                               long charUuidLsb, long charUuidMsb,
1764                               int srvcHandle, int charHandle)
1765                               throws RemoteException {
1766            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1767        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1768            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1769        if (status == 0)
1770            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1771        continueServiceDeclaration(serverIf, status, srvcHandle);
1772    }
1773
1774    void onDescriptorAdded(int status, int serverIf,
1775                           long descrUuidLsb, long descrUuidMsb,
1776                           int srvcHandle, int descrHandle)
1777                           throws RemoteException {
1778            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1779        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1780            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1781        if (status == 0)
1782            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1783        continueServiceDeclaration(serverIf, status, srvcHandle);
1784    }
1785
1786    void onServiceStarted(int status, int serverIf, int srvcHandle)
1787            throws RemoteException {
1788        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1789            + ", status=" + status);
1790        if (status == 0)
1791            mHandleMap.setStarted(serverIf, srvcHandle, true);
1792    }
1793
1794    void onServiceStopped(int status, int serverIf, int srvcHandle)
1795            throws RemoteException {
1796        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1797            + ", status=" + status);
1798        if (status == 0)
1799            mHandleMap.setStarted(serverIf, srvcHandle, false);
1800        stopNextService(serverIf, status);
1801    }
1802
1803    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1804        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1805            + ", status=" + status);
1806        mHandleMap.deleteService(serverIf, srvcHandle);
1807    }
1808
1809    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1810            throws RemoteException {
1811
1812        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1813            + ", address=" + address + ", connected=" + connected);
1814
1815        ServerMap.App app = mServerMap.getById(serverIf);
1816        if (app == null) return;
1817
1818        if (connected) {
1819            mServerMap.addConnection(serverIf, connId, address);
1820        } else {
1821            mServerMap.removeConnection(serverIf, connId);
1822        }
1823
1824        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1825    }
1826
1827    void onAttributeRead(String address, int connId, int transId,
1828                            int attrHandle, int offset, boolean isLong)
1829                            throws RemoteException {
1830        if (DBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1831            + ", address=" + address + ", handle=" + attrHandle
1832            + ", requestId=" + transId + ", offset=" + offset);
1833
1834        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1835        if (entry == null) return;
1836
1837        if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid
1838            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1839
1840        mHandleMap.addRequest(transId, attrHandle);
1841
1842        ServerMap.App app = mServerMap.getById(entry.serverIf);
1843        if (app == null) return;
1844
1845        switch(entry.type) {
1846            case HandleMap.TYPE_CHARACTERISTIC:
1847            {
1848                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1849                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1850                    serviceEntry.serviceType, serviceEntry.instance,
1851                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1852                    new ParcelUuid(entry.uuid));
1853                break;
1854            }
1855
1856            case HandleMap.TYPE_DESCRIPTOR:
1857            {
1858                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1859                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1860                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1861                    serviceEntry.serviceType, serviceEntry.instance,
1862                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1863                    new ParcelUuid(charEntry.uuid),
1864                    new ParcelUuid(entry.uuid));
1865                break;
1866            }
1867
1868            default:
1869                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1870                break;
1871        }
1872    }
1873
1874    void onAttributeWrite(String address, int connId, int transId,
1875                            int attrHandle, int offset, int length,
1876                            boolean needRsp, boolean isPrep,
1877                            byte[] data)
1878                            throws RemoteException {
1879        if (DBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1880            + ", address=" + address + ", handle=" + attrHandle
1881            + ", requestId=" + transId + ", isPrep=" + isPrep
1882            + ", offset=" + offset);
1883
1884        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1885        if (entry == null) return;
1886
1887        if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid
1888            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1889
1890        mHandleMap.addRequest(transId, attrHandle);
1891
1892        ServerMap.App app = mServerMap.getById(entry.serverIf);
1893        if (app == null) return;
1894
1895        switch(entry.type) {
1896            case HandleMap.TYPE_CHARACTERISTIC:
1897            {
1898                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1899                app.callback.onCharacteristicWriteRequest(address, transId,
1900                            offset, length, isPrep, needRsp,
1901                            serviceEntry.serviceType, serviceEntry.instance,
1902                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1903                            new ParcelUuid(entry.uuid), data);
1904                break;
1905            }
1906
1907            case HandleMap.TYPE_DESCRIPTOR:
1908            {
1909                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1910                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1911                app.callback.onDescriptorWriteRequest(address, transId,
1912                            offset, length, isPrep, needRsp,
1913                            serviceEntry.serviceType, serviceEntry.instance,
1914                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1915                            new ParcelUuid(charEntry.uuid),
1916                            new ParcelUuid(entry.uuid), data);
1917                break;
1918            }
1919
1920            default:
1921                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1922                break;
1923        }
1924    }
1925
1926    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1927            throws RemoteException {
1928        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1929            + ", address=" + address + ", transId=" + transId);
1930
1931        ServerMap.App app = mServerMap.getByConnId(connId);
1932        if (app == null) return;
1933
1934        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1935    }
1936
1937    void onResponseSendCompleted(int status, int attrHandle) {
1938        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1939    }
1940
1941    /**************************************************************************
1942     * GATT Service functions - SERVER
1943     *************************************************************************/
1944
1945    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1946        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1947
1948        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1949        mServerMap.add(uuid, callback);
1950        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1951                                    uuid.getMostSignificantBits());
1952    }
1953
1954    void unregisterServer(int serverIf) {
1955        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1956
1957        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1958
1959        deleteServices(serverIf);
1960
1961        mServerMap.remove(serverIf);
1962        gattServerUnregisterAppNative(serverIf);
1963    }
1964
1965    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1966        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1967
1968        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1969        gattServerConnectNative(serverIf, address, isDirect,transport);
1970    }
1971
1972    void serverDisconnect(int serverIf, String address) {
1973        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1974
1975        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1976        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1977
1978        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1979    }
1980
1981    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1982                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1983        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1984
1985        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1986        ServiceDeclaration serviceDeclaration = addDeclaration();
1987        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1988            advertisePreferred);
1989    }
1990
1991    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1992                            UUID srvcUuid) {
1993        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1994
1995        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1996        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1997    }
1998
1999    void addCharacteristic(int serverIf, UUID charUuid, int properties,
2000                           int permissions) {
2001        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2002
2003        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
2004        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
2005    }
2006
2007    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
2008        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2009
2010        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
2011        getActiveDeclaration().addDescriptor(descUuid, permissions);
2012    }
2013
2014    void endServiceDeclaration(int serverIf) {
2015        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2016
2017        if (DBG) Log.d(TAG, "endServiceDeclaration()");
2018
2019        if (getActiveDeclaration() == getPendingDeclaration()) {
2020            try {
2021                continueServiceDeclaration(serverIf, (byte)0, 0);
2022            } catch (RemoteException e) {
2023                Log.e(TAG,""+e);
2024            }
2025        }
2026    }
2027
2028    void removeService(int serverIf, int srvcType,
2029                  int srvcInstanceId, UUID srvcUuid) {
2030        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2031
2032        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
2033
2034        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
2035        if (srvcHandle == 0) return;
2036        gattServerDeleteServiceNative(serverIf, srvcHandle);
2037    }
2038
2039    void clearServices(int serverIf) {
2040        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2041
2042        if (DBG) Log.d(TAG, "clearServices()");
2043        deleteServices(serverIf);
2044    }
2045
2046    void sendResponse(int serverIf, String address, int requestId,
2047                      int status, int offset, byte[] value) {
2048        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2049
2050        if (DBG) Log.d(TAG, "sendResponse() - address=" + address);
2051
2052        int handle = 0;
2053        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
2054        if (entry != null) handle = entry.handle;
2055
2056        int connId = mServerMap.connIdByAddress(serverIf, address);
2057        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
2058                                     handle, offset, value, (byte)0);
2059        mHandleMap.deleteRequest(requestId);
2060    }
2061
2062    void sendNotification(int serverIf, String address, int srvcType,
2063                                 int srvcInstanceId, UUID srvcUuid,
2064                                 int charInstanceId, UUID charUuid,
2065                                 boolean confirm, byte[] value) {
2066        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2067
2068        if (DBG) Log.d(TAG, "sendNotification() - address=" + address);
2069
2070        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
2071        if (srvcHandle == 0) return;
2072
2073        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
2074        if (charHandle == 0) return;
2075
2076        int connId = mServerMap.connIdByAddress(serverIf, address);
2077        if (connId == 0) return;
2078
2079        if (confirm) {
2080            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
2081        } else {
2082            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
2083        }
2084    }
2085
2086
2087    /**************************************************************************
2088     * Private functions
2089     *************************************************************************/
2090
2091    private int getDeviceType(BluetoothDevice device) {
2092        int type = gattClientGetDeviceTypeNative(device.getAddress());
2093        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
2094            + ", type=" + type);
2095        return type;
2096    }
2097
2098    private synchronized int getAvailableSize() {
2099        enforcePrivilegedPermission();
2100        int availableSize = ADVERTISING_PACKET_MAX_BYTES - ADVERTISING_FLAGS_BYTES;
2101
2102        for (ParcelUuid parcelUuid : getAdvServiceUuids()) {
2103            if (BluetoothUuid.is16BitUuid(parcelUuid)) {
2104                availableSize -= FIELD_OVERHEAD_BYTES + SHORT_UUID_BYTES;
2105            } else {
2106                availableSize -= FIELD_OVERHEAD_BYTES + FULL_UUID_BYTES;
2107            }
2108        }
2109        if (mManufacturerCode > 0 && mManufacturerData != null) {
2110            availableSize -= (FIELD_OVERHEAD_BYTES + mManufacturerData.length);
2111        }
2112        if (mServiceData != null) {
2113            availableSize -= (FIELD_OVERHEAD_BYTES + mServiceData.length);
2114        }
2115        return availableSize;
2116    }
2117
2118    private void enforceAdminPermission() {
2119        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
2120    }
2121
2122    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
2123    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
2124    private void enforcePrivilegedPermission() {
2125        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
2126            "Need BLUETOOTH_PRIVILEGED permission");
2127    }
2128
2129    private void continueSearch(int connId, int status) throws RemoteException {
2130        if (status == 0 && !mSearchQueue.isEmpty()) {
2131            SearchQueue.Entry svc = mSearchQueue.pop();
2132
2133            if (svc.charUuidLsb == 0) {
2134                // Characteristic is up next
2135                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
2136                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
2137            } else {
2138                // Descriptor is up next
2139                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
2140                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
2141                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
2142            }
2143        } else {
2144            ClientMap.App app = mClientMap.getByConnId(connId);
2145            if (app != null) {
2146                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
2147            }
2148        }
2149    }
2150
2151    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
2152        if (mServiceDeclarations.size() == 0) return;
2153        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
2154
2155        boolean finished = false;
2156
2157        ServiceDeclaration.Entry entry = null;
2158        if (status == 0)
2159            entry = getPendingDeclaration().getNext();
2160
2161        if (entry != null) {
2162            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
2163                + entry.type);
2164            switch(entry.type) {
2165                case ServiceDeclaration.TYPE_SERVICE:
2166                    if (entry.advertisePreferred) {
2167                        mAdvertisingServiceUuids.add(entry.uuid);
2168                    }
2169                    gattServerAddServiceNative(serverIf, entry.serviceType,
2170                        entry.instance,
2171                        entry.uuid.getLeastSignificantBits(),
2172                        entry.uuid.getMostSignificantBits(),
2173                        getPendingDeclaration().getNumHandles());
2174                    break;
2175
2176                case ServiceDeclaration.TYPE_CHARACTERISTIC:
2177                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
2178                        entry.uuid.getLeastSignificantBits(),
2179                        entry.uuid.getMostSignificantBits(),
2180                        entry.properties, entry.permissions);
2181                    break;
2182
2183                case ServiceDeclaration.TYPE_DESCRIPTOR:
2184                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2185                        entry.uuid.getLeastSignificantBits(),
2186                        entry.uuid.getMostSignificantBits(),
2187                        entry.permissions);
2188                    break;
2189
2190                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2191                {
2192                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2193                                            entry.serviceType, entry.instance);
2194                    if (inclSrvc != 0) {
2195                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2196                                                           inclSrvc);
2197                    } else {
2198                        finished = true;
2199                    }
2200                    break;
2201                }
2202            }
2203        } else {
2204            gattServerStartServiceNative(serverIf, srvcHandle,
2205                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2206            finished = true;
2207        }
2208
2209        if (finished) {
2210            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2211            ServerMap.App app = mServerMap.getById(serverIf);
2212            if (app != null) {
2213                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2214
2215                if (serviceEntry != null) {
2216                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2217                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2218                } else {
2219                    app.callback.onServiceAdded(status, 0, 0, null);
2220                }
2221            }
2222            removePendingDeclaration();
2223
2224            if (getPendingDeclaration() != null) {
2225                continueServiceDeclaration(serverIf, (byte)0, 0);
2226            }
2227        }
2228    }
2229
2230    private void stopNextService(int serverIf, int status) throws RemoteException {
2231        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2232            + ", status=" + status);
2233
2234        if (status == 0) {
2235            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2236            for(HandleMap.Entry entry : entries) {
2237                if (entry.type != HandleMap.TYPE_SERVICE ||
2238                    entry.serverIf != serverIf ||
2239                    entry.started == false)
2240                        continue;
2241
2242                gattServerStopServiceNative(serverIf, entry.handle);
2243                return;
2244            }
2245        }
2246    }
2247
2248    private void deleteServices(int serverIf) {
2249        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2250
2251        /*
2252         * Figure out which handles to delete.
2253         * The handles are copied into a new list to avoid race conditions.
2254         */
2255        List<Integer> handleList = new ArrayList<Integer>();
2256        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2257        for(HandleMap.Entry entry : entries) {
2258            if (entry.type != HandleMap.TYPE_SERVICE ||
2259                entry.serverIf != serverIf)
2260                    continue;
2261            handleList.add(entry.handle);
2262        }
2263
2264        /* Now actually delete the services.... */
2265        for(Integer handle : handleList) {
2266            gattServerDeleteServiceNative(serverIf, handle);
2267        }
2268    }
2269
2270    private List<UUID> parseUuids(byte[] adv_data) {
2271        List<UUID> uuids = new ArrayList<UUID>();
2272
2273        int offset = 0;
2274        while(offset < (adv_data.length-2)) {
2275            int len = adv_data[offset++];
2276            if (len == 0) break;
2277
2278            int type = adv_data[offset++];
2279            switch (type) {
2280                case 0x02: // Partial list of 16-bit UUIDs
2281                case 0x03: // Complete list of 16-bit UUIDs
2282                    while (len > 1) {
2283                        int uuid16 = adv_data[offset++];
2284                        uuid16 += (adv_data[offset++] << 8);
2285                        len -= 2;
2286                        uuids.add(UUID.fromString(String.format(
2287                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2288                    }
2289                    break;
2290
2291                default:
2292                    offset += (len - 1);
2293                    break;
2294            }
2295        }
2296
2297        return uuids;
2298    }
2299
2300    /**************************************************************************
2301     * GATT Test functions
2302     *************************************************************************/
2303
2304    void gattTestCommand(int command, UUID uuid1, String bda1,
2305                         int p1, int p2, int p3, int p4, int p5) {
2306        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2307        if (uuid1 != null)
2308            gattTestNative(command, uuid1.getLeastSignificantBits(),
2309                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2310        else
2311            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2312    }
2313
2314    private native void gattTestNative(int command,
2315                                    long uuid1_lsb, long uuid1_msb, String bda1,
2316                                    int p1, int p2, int p3, int p4, int p5);
2317
2318    /**************************************************************************
2319     * Native functions prototypes
2320     *************************************************************************/
2321
2322    private native static void classInitNative();
2323    private native void initializeNative();
2324    private native void cleanupNative();
2325
2326    private native int gattClientGetDeviceTypeNative(String address);
2327
2328    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2329                                                    long app_uuid_msb);
2330
2331    private native void gattClientUnregisterAppNative(int clientIf);
2332
2333    private native void gattSetScanParametersNative(int scan_interval, int scan_window);
2334
2335    private native void gattClientConnectNative(int clientIf, String address,
2336            boolean isDirect, int transport);
2337
2338    private native void gattClientDisconnectNative(int clientIf, String address,
2339            int conn_id);
2340
2341    private native void gattClientRefreshNative(int clientIf, String address);
2342
2343    private native void gattClientSearchServiceNative(int conn_id,
2344            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2345
2346    private native void gattClientGetCharacteristicNative(int conn_id,
2347            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2348            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2349            long char_id_uuid_msb);
2350
2351    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2352            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2353            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2354            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2355
2356    private native void gattClientGetIncludedServiceNative(int conn_id,
2357            int service_type, int service_id_inst_id,
2358            long service_id_uuid_lsb, long service_id_uuid_msb,
2359            int incl_service_id_inst_id, int incl_service_type,
2360            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2361
2362    private native void gattClientReadCharacteristicNative(int conn_id,
2363            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2364            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2365            long char_id_uuid_msb, int authReq);
2366
2367    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2368            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2369            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2370            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2371            int authReq);
2372
2373    private native void gattClientWriteCharacteristicNative(int conn_id,
2374            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2375            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2376            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2377
2378    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2379            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2380            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2381            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2382            int write_type, int auth_req, byte[] value);
2383
2384    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2385
2386    private native void gattClientRegisterForNotificationsNative(int clientIf,
2387            String address, int service_type, int service_id_inst_id,
2388            long service_id_uuid_lsb, long service_id_uuid_msb,
2389            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2390            boolean enable);
2391
2392    private native void gattClientReadRemoteRssiNative(int clientIf,
2393            String address);
2394
2395    private native void gattAdvertiseNative(int client_if, boolean start);
2396
2397    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2398
2399    private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
2400            boolean inclTxPower, int minInterval, int maxInterval,
2401            int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
2402
2403    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2404                                                    long app_uuid_msb);
2405
2406    private native void gattServerUnregisterAppNative(int serverIf);
2407
2408    private native void gattServerConnectNative(int server_if, String address,
2409                                             boolean is_direct, int transport);
2410
2411    private native void gattServerDisconnectNative(int serverIf, String address,
2412                                              int conn_id);
2413
2414    private native void gattServerAddServiceNative (int server_if,
2415            int service_type, int service_id_inst_id,
2416            long service_id_uuid_lsb, long service_id_uuid_msb,
2417            int num_handles);
2418
2419    private native void gattServerAddIncludedServiceNative (int server_if,
2420            int svc_handle, int included_svc_handle);
2421
2422    private native void gattServerAddCharacteristicNative (int server_if,
2423            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2424            int properties, int permissions);
2425
2426    private native void gattServerAddDescriptorNative (int server_if,
2427            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2428            int permissions);
2429
2430    private native void gattServerStartServiceNative (int server_if,
2431            int svc_handle, int transport );
2432
2433    private native void gattServerStopServiceNative (int server_if,
2434                                                     int svc_handle);
2435
2436    private native void gattServerDeleteServiceNative (int server_if,
2437                                                       int svc_handle);
2438
2439    private native void gattServerSendIndicationNative (int server_if,
2440            int attr_handle, int conn_id, byte[] val);
2441
2442    private native void gattServerSendNotificationNative (int server_if,
2443            int attr_handle, int conn_id, byte[] val);
2444
2445    private native void gattServerSendResponseNative (int server_if,
2446            int conn_id, int trans_id, int status, int handle, int offset,
2447            byte[] val, int auth_req);
2448}
2449