GattService.java revision 00975169ba4eb5251397a66532ee9a3288c0f137
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
2a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * Copyright (C) 2013 The Android Open Source Project
3d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt *
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Licensed under the Apache License, Version 2.0 (the "License");
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * you may not use this file except in compliance with the License.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * You may obtain a copy of the License at
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      http://www.apache.org/licenses/LICENSE-2.0
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Unless required by applicable law or agreed to in writing, software
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * distributed under the License is distributed on an "AS IS" BASIS,
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See the License for the specific language governing permissions and
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * limitations under the License.
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtpackage com.android.bluetooth.gatt;
1861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtimport android.app.Service;
2061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtimport android.bluetooth.BluetoothAdapter;
2161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtimport android.bluetooth.BluetoothDevice;
22a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtimport android.bluetooth.BluetoothGatt;
23a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtimport android.bluetooth.BluetoothProfile;
24a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtimport android.bluetooth.IBluetoothGatt;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtimport android.bluetooth.IBluetoothGattCallback;
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtimport android.bluetooth.IBluetoothGattServerCallback;
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtimport android.bluetooth.le.AdvertiseCallback;
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtimport android.bluetooth.le.AdvertiseData;
29fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtimport android.bluetooth.le.AdvertiseSettings;
30fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtimport android.bluetooth.le.ScanFilter;
31807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtimport android.bluetooth.le.ScanRecord;
324ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidtimport android.bluetooth.le.ScanResult;
334ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidtimport android.bluetooth.le.ScanSettings;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtimport android.content.Intent;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtimport android.os.IBinder;
361d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport android.os.ParcelUuid;
371d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport android.os.RemoteException;
381d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport android.os.SystemClock;
391d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport android.util.Log;
401d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
411d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport com.android.bluetooth.Utils;
421d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport com.android.bluetooth.btservice.ProfileService;
431d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
441d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.ArrayList;
451d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.Arrays;
461d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.Collections;
471d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.HashMap;
481d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.HashSet;
491d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.List;
501d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.Map;
511d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtimport java.util.Set;
527f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidtimport java.util.UUID;
537f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidtimport java.util.concurrent.TimeUnit;
5457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
551d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt/**
561d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt * Provides Bluetooth Gatt profile, as a service in
571d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt * the Bluetooth application.
581d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt * @hide
591d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt */
601d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidtpublic class GattService extends ProfileService {
611d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    private static final boolean DBG = GattServiceConfig.DBG;
621d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    private static final boolean VDBG = GattServiceConfig.VDBG;
631d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService";
641d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
651d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    static final int SCAN_FILTER_ENABLED = 1;
661d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    static final int SCAN_FILTER_MODIFIED = 2;
671d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
681d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    /**
691d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt     * Scan params corresponding to scan setting
701d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt     */
711d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    private static final int SCAN_MODE_LOW_POWER_WINDOW_MS = 500;
727f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt    private static final int SCAN_MODE_LOW_POWER_INTERVAL_MS = 5000;
737f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt    private static final int SCAN_MODE_BALANCED_WINDOW_MS = 2000;
747f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt    private static final int SCAN_MODE_BALANCED_INTERVAL_MS = 5000;
751d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    private static final int SCAN_MODE_LOW_LATENCY_WINDOW_MS = 5000;
761d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    private static final int SCAN_MODE_LOW_LATENCY_INTERVAL_MS = 5000;
771d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
781d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    private static final int MAC_ADDRESS_LENGTH = 6;
791d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    // Batch scan related constants.
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    private static final int TRUNCATED_RESULT_SIZE = 11;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    private static final int TIME_STAMP_LENGTH = 2;
827f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt
837f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt    // onFoundLost related constants
847f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt    private static final int ADVT_STATE_ONFOUND = 0;
857f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt    private static final int ADVT_STATE_ONLOST = 1;
867f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /**
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * Search queue to serialize remote onbject inspection.
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    SearchQueue mSearchQueue = new SearchQueue();
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /**
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * List of our registered clients.
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    class ClientMap extends ContextMap<IBluetoothGattCallback> {}
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ClientMap mClientMap = new ClientMap();
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /**
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * List of our registered server apps.
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    class ServerMap extends ContextMap<IBluetoothGattServerCallback> {}
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    ServerMap mServerMap = new ServerMap();
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /**
1067f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt     * Server handle map.
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    HandleMap mHandleMap = new HandleMap();
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    private List<UUID> mAdvertisingServiceUuids = new ArrayList<UUID>();
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    private int mMaxScanFilters;
112092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
113092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart    /**
114092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart     * Pending service declaration queue
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    private List<ServiceDeclaration> mServiceDeclarations = new ArrayList<ServiceDeclaration>();
11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    private ServiceDeclaration addDeclaration() {
11955840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        synchronized (mServiceDeclarations) {
12055840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            mServiceDeclarations.add(new ServiceDeclaration());
12155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        }
12255840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        return getActiveDeclaration();
12355840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    }
12455840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt
12555840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    private ServiceDeclaration getActiveDeclaration() {
12655840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        synchronized (mServiceDeclarations) {
12755840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            if (mServiceDeclarations.size() > 0)
12855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                return mServiceDeclarations.get(mServiceDeclarations.size() - 1);
12955840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        }
13055840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        return null;
13155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    }
13255840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt
13355840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    private ServiceDeclaration getPendingDeclaration() {
13455840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        synchronized (mServiceDeclarations) {
13555840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            if (mServiceDeclarations.size() > 0)
13655840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                return mServiceDeclarations.get(0);
13755840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        }
13855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        return null;
13955840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    }
14055840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt
14155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    private void removePendingDeclaration() {
14255840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        synchronized (mServiceDeclarations) {
14355840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            if (mServiceDeclarations.size() > 0)
14455840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                mServiceDeclarations.remove(0);
14555840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        }
14655840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    }
14755840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt
14855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    private AdvertiseManager mAdvertiseManager;
14955840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    private ScanManager mScanManager;
15055840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt
15155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    /**
15255840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt     * Reliable write queue
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    private Set<String> mReliableQueue = new HashSet<String>();
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
156d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    static {
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        classInitNative();
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    protected String getName() {
161d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        return TAG;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
164d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    protected IProfileServiceBinder initBinder() {
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return new BluetoothGattBinder(this);
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    protected boolean start() {
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "start()");
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        initializeNative();
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mAdvertiseManager = new AdvertiseManager(this);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mAdvertiseManager.start();
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mScanManager = new ScanManager(this);
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mScanManager.start();
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return true;
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1799ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    protected boolean stop() {
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "stop()");
182d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        mClientMap.clear();
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mServerMap.clear();
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mSearchQueue.clear();
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mHandleMap.clear();
186d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        mServiceDeclarations.clear();
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mReliableQueue.clear();
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mAdvertiseManager.cleanup();
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mScanManager.cleanup();
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return true;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1931d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    protected boolean cleanup() {
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "cleanup()");
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        cleanupNative();
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mAdvertiseManager.cleanup();
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mScanManager.cleanup();
1981d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        return true;
1991d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    }
2001d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
2011d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    @Override
2021d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    public int onStartCommand(Intent intent, int flags, int startId) {
2031d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        if (GattDebugUtils.handleDebugAction(this, intent)) {
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            return Service.START_NOT_STICKY;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return super.onStartCommand(intent, flags, startId);
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    /**
2101d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt     * DeathReceipient handlers used to unregister applications that
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * disconnect ungracefully (ie. crash or forced close).
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     */
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    class ClientDeathRecipient implements IBinder.DeathRecipient {
2151d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        int mAppIf;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public ClientDeathRecipient(int appIf) {
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            mAppIf = appIf;
2191d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        }
22057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void binderDied() {
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (isScanClient(mAppIf)) {
224d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                stopScan(mAppIf, false);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            } else {
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                stopMultiAdvertising(mAppIf);
227d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            }
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            // TODO: Move unregisterClient after stop scan/advertise callback to avoid race
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            // condition.
23061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            unregisterClient(mAppIf);
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
232d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        private boolean isScanClient(int clientIf) {
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            for (ScanClient client : mScanManager.getRegularScanQueue()) {
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (client.clientIf == clientIf) {
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    return true;
23761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                }
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            for (ScanClient client : mScanManager.getBatchScanQueue()) {
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (client.clientIf == clientIf) {
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    return true;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                }
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            return false;
24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    class ServerDeathRecipient implements IBinder.DeathRecipient {
249d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int mAppIf;
250092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
251092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart        public ServerDeathRecipient(int appIf) {
252092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart            mAppIf = appIf;
253092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart        }
254092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart
255092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart        public void binderDied() {
256092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart            if (DBG) Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!");
257092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart            unregisterServer(mAppIf);
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
259d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
260d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
261d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    /**
262d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt     * Handlers for incoming service calls
263d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt     */
264d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {
265d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        private GattService mService;
266d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
267d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        public BluetoothGattBinder(GattService svc) {
26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            mService = svc;
26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
27061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
27161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public boolean cleanup()  {
27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            mService = null;
2739ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt            return true;
27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
2769ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt        private GattService getService() {
27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (mService  != null && mService.isAvailable()) return mService;
27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            Log.e(TAG, "getService() - Service requested, but not available!");
27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            return null;
28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
28361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            GattService service = getService();
28461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return new ArrayList<BluetoothDevice>();
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            return service.getDevicesMatchingConnectionStates(states);
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) {
28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            GattService service = getService();
2901d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            if (service == null) return;
2911d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.registerClient(uuid.getUuid(), callback);
2921d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        }
29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void unregisterClient(int clientIf) {
29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            GattService service = getService();
29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return;
2971d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.unregisterClient(clientIf);
29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        @Override
30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void startScan(int appIf, boolean isServer, ScanSettings settings,
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                List<ScanFilter> filters) {
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return;
30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            service.startScan(appIf, isServer, settings, filters);
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void stopScan(int appIf, boolean isServer) {
309d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            GattService service = getService();
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
31161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            service.stopScan(appIf, isServer);
31261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
31361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
31461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        @Override
31561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void flushPendingBatchResults(int appIf, boolean isServer) {
316d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            GattService service = getService();
31761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return;
318d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            service.flushPendingBatchResults(appIf, isServer);
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            service.clientConnect(clientIf, address, isDirect, transport);
32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
32661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
32761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void clientDisconnect(int clientIf, String address) {
32861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            GattService service = getService();
32961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return;
33061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            service.clientDisconnect(clientIf, address);
33161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
33261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
33361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void refreshDevice(int clientIf, String address) {
33461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            GattService service = getService();
3351d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            if (service == null) return;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.refreshDevice(clientIf, address);
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void discoverServices(int clientIf, String address) {
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
34161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return;
34261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            service.discoverServices(clientIf, address);
34361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
3441d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
3451d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        public void readCharacteristic(int clientIf, String address, int srvcType,
3461d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                                       int srvcInstanceId, ParcelUuid srvcId,
34761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                                       int charInstanceId, ParcelUuid charId,
34861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                                       int authReq) {
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
35061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return;
3511d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.readCharacteristic(clientIf, address, srvcType, srvcInstanceId,
35261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                                       srvcId.getUuid(), charInstanceId,
35361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                                       charId.getUuid(), authReq);
35461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
3551d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void writeCharacteristic(int clientIf, String address, int srvcType,
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                             int srvcInstanceId, ParcelUuid srvcId,
35861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                             int charInstanceId, ParcelUuid charId,
35961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                             int writeType, int authReq, byte[] value) {
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.writeCharacteristic(clientIf, address, srvcType, srvcInstanceId,
363d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                                       srvcId.getUuid(), charInstanceId,
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                       charId.getUuid(), writeType, authReq,
36561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                                       value);
36661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
36761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
36861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void readDescriptor(int clientIf, String address, int srvcType,
36961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                            int srvcInstanceId, ParcelUuid srvcId,
370d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            int charInstanceId, ParcelUuid charId,
37161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                            int descrInstanceId, ParcelUuid descrId,
372d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            int authReq) {
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.readDescriptor(clientIf, address, srvcType,
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                   srvcInstanceId, srvcId.getUuid(),
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                   charInstanceId, charId.getUuid(),
37861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                                   descrInstanceId, descrId.getUuid(),
37961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                                   authReq);
38061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
38161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
38261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        public void writeDescriptor(int clientIf, String address, int srvcType,
38361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                            int srvcInstanceId, ParcelUuid srvcId,
38461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                            int charInstanceId, ParcelUuid charId,
38561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                            int descrInstanceId, ParcelUuid descrId,
38661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                            int writeType, int authReq, byte[] value) {
38761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            GattService service = getService();
38861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (service == null) return;
3891d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.writeDescriptor(clientIf, address, srvcType,
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                    srvcInstanceId, srvcId.getUuid(),
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                    charInstanceId, charId.getUuid(),
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                    descrInstanceId, descrId.getUuid(),
393d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                                    writeType, authReq, value);
394d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        }
395d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
396216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        public void beginReliableWrite(int clientIf, String address) {
397216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            GattService service = getService();
398216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            if (service == null) return;
399216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            service.beginReliableWrite(clientIf, address);
400216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
401ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt
402ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt        public void endReliableWrite(int clientIf, String address, boolean execute) {
403216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            GattService service = getService();
404216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            if (service == null) return;
405216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            service.endReliableWrite(clientIf, address, execute);
406216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
407216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt
408216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        public void registerForNotification(int clientIf, String address, int srvcType,
409216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt                            int srvcInstanceId, ParcelUuid srvcId,
410216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt                            int charInstanceId, ParcelUuid charId,
411216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt                            boolean enable) {
412216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            GattService service = getService();
413216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            if (service == null) return;
414216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            service.registerForNotification(clientIf, address, srvcType, srvcInstanceId,
415216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt                                       srvcId.getUuid(), charInstanceId,
416216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt                                       charId.getUuid(), enable);
417ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt        }
418ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt
419216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        public void readRemoteRssi(int clientIf, String address) {
420216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            GattService service = getService();
421216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            if (service == null) return;
422216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            service.readRemoteRssi(clientIf, address);
423216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
424216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt
425216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        public void configureMTU(int clientIf, String address, int mtu) {
426d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            GattService service = getService();
427d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            if (service == null) return;
428d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            service.configureMTU(clientIf, address, mtu);
429216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
430912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt
431912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        public void connectionParameterUpdate(int clientIf, String address,
4321d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                                              int connectionPriority) {
433912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            GattService service = getService();
434912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            if (service == null) return;
4351d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.connectionParameterUpdate(clientIf, address, connectionPriority);
436912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        }
437d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt
438d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt        public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback) {
439d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt            GattService service = getService();
4401d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            if (service == null) return;
4411d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.registerServer(uuid.getUuid(), callback);
442912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        }
443912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt
444912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        public void unregisterServer(int serverIf) {
4451d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            GattService service = getService();
4461d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            if (service == null) return;
4471d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.unregisterServer(serverIf);
4481d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        }
4491d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt
4501d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        public void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
45157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt            GattService service = getService();
452912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            if (service == null) return;
4531d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.serverConnect(serverIf, address, isDirect, transport);
454912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        }
455912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt
456912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        public void serverDisconnect(int serverIf, String address) {
457912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            GattService service = getService();
458912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            if (service == null) return;
4591d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.serverDisconnect(serverIf, address);
460912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        }
461912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt
4621d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        public void beginServiceDeclaration(int serverIf, int srvcType,
463912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt                                            int srvcInstanceId, int minHandles,
464d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt                                            ParcelUuid srvcId, boolean advertisePreferred) {
465d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt            GattService service = getService();
466d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt            if (service == null) return;
4671d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.beginServiceDeclaration(serverIf, srvcType, srvcInstanceId,
4681d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                               minHandles, srvcId.getUuid(), advertisePreferred);
469912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        }
470912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt
471912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt        public void addIncludedService(int serverIf, int srvcType,
4721d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                            int srvcInstanceId, ParcelUuid srvcId) {
4731d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            GattService service = getService();
4741d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            if (service == null) return;
4751d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            service.addIncludedService(serverIf, srvcType, srvcInstanceId,
4761d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                                            srvcId.getUuid());
4771d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        }
47857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
4791d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        public void addCharacteristic(int serverIf, ParcelUuid charId,
4801d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                            int properties, int permissions) {
481912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            GattService service = getService();
482912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            if (service == null) return;
483912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt            service.addCharacteristic(serverIf, charId.getUuid(), properties,
484912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt                                      permissions);
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void addDescriptor(int serverIf, ParcelUuid descId,
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                           int permissions) {
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.addDescriptor(serverIf, descId.getUuid(), permissions);
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void endServiceDeclaration(int serverIf) {
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.endServiceDeclaration(serverIf);
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void removeService(int serverIf, int srvcType,
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                           int srvcInstanceId, ParcelUuid srvcId) {
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.removeService(serverIf, srvcType, srvcInstanceId,
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                  srvcId.getUuid());
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void clearServices(int serverIf) {
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.clearServices(serverIf);
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5147f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt        public void sendResponse(int serverIf, String address, int requestId,
5157f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                                 int status, int offset, byte[] value) {
5167f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt            GattService service = getService();
5177f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt            if (service == null) return;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.sendResponse(serverIf, address, requestId, status, offset, value);
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void sendNotification(int serverIf, String address, int srvcType,
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                              int srvcInstanceId, ParcelUuid srvcId,
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                              int charInstanceId, ParcelUuid charId,
5241d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                                              boolean confirm, byte[] value) {
5251d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            GattService service = getService();
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.sendNotification(serverIf, address, srvcType, srvcInstanceId,
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                srvcId.getUuid(), charInstanceId, charId.getUuid(), confirm, value);
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        @Override
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                AdvertiseData scanResponse, AdvertiseSettings settings) {
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            GattService service = getService();
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.startMultiAdvertising(clientIf, advertiseData, scanResponse, settings);
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        @Override
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void stopMultiAdvertising(int clientIf) {
541d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            GattService service = getService();
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (service == null) return;
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            service.stopMultiAdvertising(clientIf);
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    };
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
547d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    /**************************************************************************
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     * Callback functions - CLIENT
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt     *************************************************************************/
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onScanResult(String address, int rssi, byte[] adv_data) {
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (VDBG) Log.d(TAG, "onScanResult() - address=" + address
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    + ", rssi=" + rssi);
5549ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt        ScanRecord record = ScanRecord.parseFromBytes(adv_data);
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        List<UUID> remoteUuids = parseUuids(adv_data);
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        for (ScanClient client : mScanManager.getRegularScanQueue()) {
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (client.uuids.length > 0) {
5589ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt                int matches = 0;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                for (UUID search : client.uuids) {
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    for (UUID remote: remoteUuids) {
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        if (remote.equals(search)) {
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            ++matches;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            break; // Only count 1st match in case of duplicates
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        }
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    }
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                }
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (matches < client.uuids.length) continue;
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (!client.isServer) {
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                ClientMap.App app = mClientMap.getById(client.clientIf);
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (app != null) {
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    BluetoothDevice device = BluetoothAdapter.getDefaultAdapter()
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            .getRemoteDevice(address);
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    long scanTimeNanos =
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            TimeUnit.NANOSECONDS.toMicros(SystemClock.elapsedRealtimeNanos());
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data),
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            rssi, scanTimeNanos);
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    if (matchesFilters(client, result)) {
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        try {
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            app.callback.onScanResult(result);
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        } catch (RemoteException e) {
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            Log.e(TAG, "Exception: " + e);
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                            mClientMap.remove(client.clientIf);
5861d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                            mScanManager.stopScan(client);
5871d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                        }
5881d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                    }
5891d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                }
5901d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            } else {
5911d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                ServerMap.App app = mServerMap.getById(client.clientIf);
59257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt                if (app != null) {
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    try {
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        app.callback.onScanResult(address, rssi, adv_data);
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    } catch (RemoteException e) {
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        Log.e(TAG, "Exception: " + e);
5971d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                        mServerMap.remove(client.clientIf);
5981d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                        mScanManager.stopScan(client);
5991d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                    }
6001d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt                }
6011d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            }
60257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt        }
6031d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt    }
60457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Check if a scan record matches a specific filters.
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    private boolean matchesFilters(ScanClient client, ScanResult scanResult) {
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (client.filters == null || client.filters.isEmpty()) {
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            return true;
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "result: " + scanResult.toString());
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        for (ScanFilter filter : client.filters) {
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (DBG) Log.d(TAG, "filter: " + filter.toString());
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (filter.matches(scanResult)) {
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                return true;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
6171d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt        return false;
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            throws RemoteException {
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        UUID uuid = new UUID(uuidMsb, uuidLsb);
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ClientMap.App app = mClientMap.getByUuid(uuid);
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (app != null) {
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.id = clientIf;
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.linkToDeath(new ClientDeathRecipient(clientIf));
6281d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt            app.callback.onClientRegistered(status, clientIf);
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onConnected(int clientIf, int connId, int status, String address)
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            throws RemoteException  {
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            + ", connId=" + connId + ", address=" + address);
63657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt
63757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt        if (status == 0) mClientMap.addConnection(clientIf, connId, address);
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ClientMap.App app = mClientMap.getById(clientIf);
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (app != null) {
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.callback.onClientConnectionState(status, clientIf, true, address);
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6449839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt    void onDisconnected(int clientIf, int connId, int status, String address)
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            throws RemoteException {
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            + ", connId=" + connId + ", address=" + address);
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mClientMap.removeConnection(clientIf, connId);
650849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        mSearchQueue.removeConnId(connId);
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ClientMap.App app = mClientMap.getById(clientIf);
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (app != null) {
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.callback.onClientConnectionState(status, clientIf, false, address);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onSearchCompleted(int connId, int status) throws RemoteException {
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status);
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // We got all services, now let's explore characteristics...
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        continueSearch(connId, status);
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onSearchResult(int connId, int srvcType,
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb)
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            throws RemoteException {
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        String address = mClientMap.addressByConnId(connId);
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (VDBG) Log.d(TAG, "onSearchResult() - address=" + address + ", uuid=" + uuid);
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        mSearchQueue.add(connId, srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb);
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (app != null) {
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.callback.onGetService(address, srvcType, srvcInstId,
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                        new ParcelUuid(uuid));
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onGetCharacteristic(int connId, int status, int srvcType,
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb,
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            int charProp) throws RemoteException {
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
685ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
686ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        String address = mClientMap.addressByConnId(connId);
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
689849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        if (VDBG) Log.d(TAG, "onGetCharacteristic() - address=" + address
690849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            + ", status=" + status + ", charUuid=" + charUuid + ", prop=" + charProp);
691849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
692849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        if (status == 0) {
6934ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt            mSearchQueue.add(connId, srvcType,
6944ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt                            srvcInstId, srvcUuidLsb, srvcUuidMsb,
695849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                            charInstId, charUuidLsb, charUuidMsb);
696849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
697849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            ClientMap.App app = mClientMap.getByConnId(connId);
698849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            if (app != null) {
699849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                app.callback.onGetCharacteristic(address, srvcType,
700849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                            srvcInstId, new ParcelUuid(srvcUuid),
701849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                            charInstId, new ParcelUuid(charUuid), charProp);
702849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            }
703849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
704849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            // Get next characteristic in the current service
705849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            gattClientGetCharacteristicNative(connId, srvcType,
706849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                                        srvcInstId, srvcUuidLsb, srvcUuidMsb,
707849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                                        charInstId, charUuidLsb, charUuidMsb);
708849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        } else {
709849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            // Check for included services next
710849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            gattClientGetIncludedServiceNative(connId,
711849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
712849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                0,0,0,0);
713849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        }
714849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    }
715849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
716849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    void onGetDescriptor(int connId, int status, int srvcType,
717849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
718849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb,
719849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
720849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
721849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
722849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
723849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        UUID descUuid = new UUID(descrUuidMsb, descrUuidLsb);
724849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        String address = mClientMap.addressByConnId(connId);
725849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
726849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        if (VDBG) Log.d(TAG, "onGetDescriptor() - address=" + address
727849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            + ", status=" + status + ", descUuid=" + descUuid);
728849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
729849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        if (status == 0) {
730849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            ClientMap.App app = mClientMap.getByConnId(connId);
731849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            if (app != null) {
732849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                app.callback.onGetDescriptor(address, srvcType,
733849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                            srvcInstId, new ParcelUuid(srvcUuid),
734849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                            charInstId, new ParcelUuid(charUuid),
735849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                            descrInstId, new ParcelUuid(descUuid));
736849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            }
737849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
738849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            // Get next descriptor for the current characteristic
739849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            gattClientGetDescriptorNative(connId, srvcType,
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                    srvcInstId, srvcUuidLsb, srvcUuidMsb,
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                    charInstId, charUuidLsb, charUuidMsb,
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                                    descrInstId, descrUuidLsb, descrUuidMsb);
74304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        } else {
74404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            // Explore the next service
7459839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt            continueSearch(connId, 0);
74604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
74704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    }
74804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
74904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    void onGetIncludedService(int connId, int status, int srvcType,
75004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, int inclSrvcType,
75104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int inclSrvcInstId, long inclSrvcUuidLsb, long inclSrvcUuidMsb)
75204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            throws RemoteException {
75304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
75404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID inclSrvcUuid = new UUID(inclSrvcUuidMsb, inclSrvcUuidLsb);
75504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        String address = mClientMap.addressByConnId(connId);
75604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
75704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (VDBG) Log.d(TAG, "onGetIncludedService() - address=" + address
75804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            + ", status=" + status + ", uuid=" + srvcUuid
75904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            + ", inclUuid=" + inclSrvcUuid);
76004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
76104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (status == 0) {
76204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            ClientMap.App app = mClientMap.getByConnId(connId);
76304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            if (app != null) {
76404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                app.callback.onGetIncludedService(address,
76504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                    srvcType, srvcInstId, new ParcelUuid(srvcUuid),
76604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                    inclSrvcType, inclSrvcInstId, new ParcelUuid(inclSrvcUuid));
76704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            }
76804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
76904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            // Find additional included services
77004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            gattClientGetIncludedServiceNative(connId,
77104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb,
77204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                inclSrvcType, inclSrvcInstId, inclSrvcUuidLsb, inclSrvcUuidMsb);
77304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        } else {
77404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            // Discover descriptors now
77504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            continueSearch(connId, 0);
776849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        }
777849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    }
778849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
779849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    void onRegisterForNotifications(int connId, int status, int registered, int srvcType,
780849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
781849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb) {
782849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
783849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
784849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        String address = mClientMap.addressByConnId(connId);
785849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
786849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address
787849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            + ", status=" + status + ", registered=" + registered
788849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            + ", charUuid=" + charUuid);
789849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    }
790849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
791849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    void onNotify(int connId, String address, int srvcType,
792849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
793849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb,
79458d12adcdf693a076f719cef9b9f2ccf81892045Dmitry Shmidt            boolean isNotify, byte[] data) throws RemoteException {
795849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
796849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
797849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
798849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        if (VDBG) Log.d(TAG, "onNotify() - address=" + address
799849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            + ", charUuid=" + charUuid + ", length=" + data.length);
800849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
801849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
802849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        if (app != null) {
803849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            app.callback.onNotify(address, srvcType,
804849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                        srvcInstId, new ParcelUuid(srvcUuid),
805849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                        charInstId, new ParcelUuid(charUuid),
806849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt                        data);
807849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt        }
808849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    }
809849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
810849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt    void onReadCharacteristic(int connId, int status, int srvcType,
811849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
81204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb,
81304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int charType, byte[] data) throws RemoteException {
81404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        String address = mClientMap.addressByConnId(connId);
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (VDBG) Log.d(TAG, "onReadCharacteristic() - address=" + address
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            + ", status=" + status + ", length=" + data.length);
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (app != null) {
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.callback.onCharacteristicRead(address, status, srvcType,
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        srvcInstId, new ParcelUuid(srvcUuid),
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        charInstId, new ParcelUuid(charUuid), data);
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onWriteCharacteristic(int connId, int status, int srvcType,
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb)
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            throws RemoteException {
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        String address = mClientMap.addressByConnId(connId);
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (VDBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            + ", status=" + status);
8417f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (app != null) {
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.callback.onCharacteristicWrite(address, status, srvcType,
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                        srvcInstId, new ParcelUuid(srvcUuid),
8467f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                        charInstId, new ParcelUuid(charUuid));
847ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt        }
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void onExecuteCompleted(int connId, int status) throws RemoteException {
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        String address = mClientMap.addressByConnId(connId);
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (VDBG) Log.d(TAG, "onExecuteCompleted() - address=" + address
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            + ", status=" + status);
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (app != null) {
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            app.callback.onExecuteWrite(address, status);
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
86004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
86104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    void onReadDescriptor(int connId, int status, int srvcType,
86204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
86355840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb,
86404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int descrInstId, long descrUuidLsb, long descrUuidMsb,
86504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int charType, byte[] data) throws RemoteException {
86604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
86704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
86804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
86904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
87004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        String address = mClientMap.addressByConnId(connId);
87104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
87204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (VDBG) Log.d(TAG, "onReadDescriptor() - address=" + address
87304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            + ", status=" + status + ", length=" + data.length);
87404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
87504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
87604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (app != null) {
87704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            app.callback.onDescriptorRead(address, status, srvcType,
87804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                        srvcInstId, new ParcelUuid(srvcUuid),
87904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                        charInstId, new ParcelUuid(charUuid),
88004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                        descrInstId, new ParcelUuid(descrUuid), data);
88104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
88204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    }
88304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
88404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    void onWriteDescriptor(int connId, int status, int srvcType,
88504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
88604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int charInstId, long charUuidLsb, long charUuidMsb,
88704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
88804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
88904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
89004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
89104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb);
89204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        String address = mClientMap.addressByConnId(connId);
89304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
89404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (VDBG) Log.d(TAG, "onWriteDescriptor() - address=" + address
89504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            + ", status=" + status);
89604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
89704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
89855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        if (app != null) {
89955840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            app.callback.onDescriptorWrite(address, status, srvcType,
90055840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                        srvcInstId, new ParcelUuid(srvcUuid),
90155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                        charInstId, new ParcelUuid(charUuid),
90255840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                        descrInstId, new ParcelUuid(descrUuid));
90355840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        }
90455840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    }
90555840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt
90655840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    void onReadRemoteRssi(int clientIf, String address,
90755840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                    int rssi, int status) throws RemoteException{
90855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" +
90904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                     address + ", rssi=" + rssi + ", status=" + status);
91004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
91104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        ClientMap.App app = mClientMap.getById(clientIf);
91204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (app != null) {
91304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            app.callback.onReadRemoteRssi(address, rssi, status);
91404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
91504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    }
91604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
91704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    void onScanFilterEnableDisabled(int action, int status, int clientIf) {
91855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        if (DBG) {
91904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            Log.d(TAG, "onScanFilterEnableDisabled() - clientIf=" + clientIf + ", status=" + status
92004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                    + ", action=" + action);
92104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
92204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        mScanManager.callbackDone(clientIf, status);
92304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    }
92404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
92504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) {
92604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (DBG) {
92704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            Log.d(TAG, "onScanFilterParamsConfigured() - clientIf=" + clientIf
92804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                    + ", status=" + status + ", action=" + action
92904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt                    + ", availableSpace=" + availableSpace);
93004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
93155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        mScanManager.callbackDone(clientIf, status);
932ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt    }
93304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
93404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    void onScanFilterConfig(int action, int status, int clientIf, int filterType,
93504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            int availableSpace) {
93604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (DBG) {
93755840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            Log.d(TAG, "onScanFilterConfig() - clientIf=" + clientIf + ", action = " + action
93855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                    + " status = " + status + ", filterType=" + filterType
939ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt                    + ", availableSpace=" + availableSpace);
94004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
94104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
94204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        mScanManager.callbackDone(clientIf, status);
94304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    }
94404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
94504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt    void onBatchScanStorageConfigured(int status, int clientIf) {
94604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (DBG) {
94704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            Log.d(TAG, "onBatchScanStorageConfigured() - clientIf="+ clientIf + ", status=" + status);
94861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
94961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        mScanManager.callbackDone(clientIf, status);
950216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    }
951216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt
952216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    // TODO: split into two different callbacks : onBatchScanStarted and onBatchScanStopped.
953216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    void onBatchScanStartStopped(int startStopAction, int status, int clientIf) {
95461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        if (DBG) {
95555840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            Log.d(TAG, "onBatchScanStartStopped() - clientIf=" + clientIf
95655840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                    + ", status=" + status + ", startStopAction=" + startStopAction);
95755840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        }
95855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        mScanManager.callbackDone(clientIf, status);
95955840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    }
96055840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt
96155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt    void onBatchScanReports(int status, int clientIf, int reportType, int numRecords,
96255840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            byte[] recordData) throws RemoteException {
96355840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        if (DBG) {
96455840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            Log.d(TAG, "onBatchScanReports() - clientIf=" + clientIf + ", status=" + status
96555840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                    + ", reportType=" + reportType + ", numRecords=" + numRecords);
96655840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        }
96755840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        mScanManager.callbackDone(clientIf, status);
96855840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData);
96955840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
97055840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            // We only support single client for truncated mode.
97155840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            ClientMap.App app = mClientMap.getById(clientIf);
97255840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            if (app == null) return;
97355840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            app.callback.onBatchScanResults(new ArrayList<ScanResult>(results));
97455840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt        } else {
97555840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt            for (ScanClient client : mScanManager.getBatchScanQueue()) {
97655840adb6cd32ca52064f327b72a40e769f70661Dmitry Shmidt                // Deliver results for each client.
97761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                deliverBatchScan(client, results);
97861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            }
97961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
980216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    }
981216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt
982216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    // Check and deliver scan results for different scan clients.
983216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults) throws
984216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            RemoteException {
985216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        ClientMap.App app = mClientMap.getById(client.clientIf);
986216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        if (app == null) return;
987216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        if (client.filters == null || client.filters.isEmpty()) {
988216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            app.callback.onBatchScanResults(new ArrayList<ScanResult>(allResults));
989216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
990216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        // Reconstruct the scan results.
991216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        List<ScanResult> results = new ArrayList<ScanResult>();
992216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        for (ScanResult scanResult : allResults) {
993216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            if (matchesFilters(client, scanResult)) {
994216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt                results.add(scanResult);
995216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            }
996216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
997216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        app.callback.onBatchScanResults(results);
998216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    }
999216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt
1000216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    private Set<ScanResult> parseBatchScanResults(int numRecords, int reportType,
1001216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            byte[] batchRecord) {
1002216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        if (numRecords == 0) {
1003216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            return Collections.emptySet();
1004216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
1005216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        if (DBG) Log.d(TAG, "current time is " + SystemClock.elapsedRealtimeNanos());
1006216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
1007216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            return parseTruncatedResults(numRecords, batchRecord);
1008216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        } else {
1009216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            return parseFullResults(numRecords, batchRecord);
1010216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        }
1011216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    }
1012216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt
1013216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    private Set<ScanResult> parseTruncatedResults(int numRecords, byte[] batchRecord) {
1014216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        if (DBG) Log.d(TAG, "batch record " + Arrays.toString(batchRecord));
1015216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
1016216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        for (int i = 0; i < numRecords; ++i) {
101761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            byte[] record = extractBytes(batchRecord, i * TRUNCATED_RESULT_SIZE,
101861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                    TRUNCATED_RESULT_SIZE);
101961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            byte[] address = extractBytes(record, 0, 6);
102061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            // TODO: remove temp hack.
102161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            reverse(address);
102261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            BluetoothDevice device = mAdapter.getRemoteDevice(address);
102361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            int rssi = record[8];
102461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            // Timestamp is in every 50 ms.
102561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            long timestampNanos = parseTimestampNanos(extractBytes(record, 9, 2));
102661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            results.add(new ScanResult(device, ScanRecord.parseFromBytes(new byte[0]),
102761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                    rssi, timestampNanos));
102861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
1029216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt        return results;
1030216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt    }
103161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
103261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    private long parseTimestampNanos(byte[] data) {
103361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        long timestampUnit = data[1] & 0xFF << 8 + data[0];
103461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        long timestampNanos = SystemClock.elapsedRealtimeNanos() -
103561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                TimeUnit.MILLISECONDS.toNanos(timestampUnit * 50);
103661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        return timestampNanos;
103761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    }
103861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
103961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) {
104061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord));
104161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
104261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        int position = 0;
1043807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        while (position < batchRecord.length) {
1044807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            byte[] address = extractBytes(batchRecord, position, 6);
1045807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            // TODO: remove temp hack.
1046807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            reverse(address);
1047807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1048216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt            position += 6;
1049ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt            // Skip address type.
1050807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            position++;
1051807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            // Skip tx power level.
1052807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            position++;
1053807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            int rssi = batchRecord[position++];
1054807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            long timestampNanos = parseTimestampNanos(extractBytes(batchRecord, position, 2));
1055807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            position += 2;
1056807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
1057807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            // Combine advertise packet and scan response packet.
1058807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            int advertisePacketLen = batchRecord[position++];
1059807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            byte[] advertiseBytes = extractBytes(batchRecord, position, advertisePacketLen);
1060807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            position += advertisePacketLen;
1061807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            int scanResponsePacketLen = batchRecord[position++];
1062d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            byte[] scanResponseBytes = extractBytes(batchRecord, position, scanResponsePacketLen);
1063d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            position += scanResponsePacketLen;
1064d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            byte[] scanRecord = new byte[advertisePacketLen + scanResponsePacketLen];
1065d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen);
1066d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            System.arraycopy(scanResponseBytes, 0, scanRecord,
1067d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                    advertisePacketLen, scanResponsePacketLen);
1068d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord));
1069d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord),
1070d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                    rssi, timestampNanos));
1071d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        }
1072d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        return results;
1073d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1074d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1075d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    // Reverse byte array.
1076d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    private void reverse(byte[] address) {
1077d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int len = address.length;
1078d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        for (int i = 0; i < len / 2; ++i) {
1079d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            byte b = address[i];
1080d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            address[i] = address[len - 1 - i];
108161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            address[len - 1 - i] = b;
108261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
108361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    }
108461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
108561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    // Helper method to extract bytes from byte array.
108661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
108761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        byte[] bytes = new byte[length];
108861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        System.arraycopy(scanRecord, start, bytes, 0, length);
108961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        return bytes;
1090807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt    }
1091807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
109261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    void onBatchScanThresholdCrossed(int clientIf) {
109361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        if (DBG) {
109461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            Log.d(TAG, "onBatchScanThresholdCrossed() - clientIf=" + clientIf);
109561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
109661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        boolean isServer = false;
1097d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        flushPendingBatchResults(clientIf, isServer);
1098d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    }
1099d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
110061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    void onTrackAdvFoundLost(int filterIndex, int addrType, String address, int advState,
110161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            int clientIf) throws RemoteException {
110261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        if (DBG) Log.d(TAG, "onClientAdvertiserFoundLost() - clientIf="
110361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                + clientIf + "address = " + address + "adv_state = "
1104807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt                + advState + "client_if = " + clientIf);
1105807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        ClientMap.App app = mClientMap.getById(clientIf);
1106807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        if (app == null || app.callback == null) {
1107807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            Log.e(TAG, "app or callback is null");
1108807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            return;
1109807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        }
1110807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        if (advState == ADVT_STATE_ONFOUND || advState == ADVT_STATE_ONLOST) {
111161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            int rssi = 0;
1112807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            byte [] advData = new byte[0];
111361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            boolean found;
111461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            if (advState == ADVT_STATE_ONFOUND) {
111561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                found = true;
111661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            } else {
111761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt                found = false;
111861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            }
111961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            //ToDo: Address reporting format and content and then enable
112061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            app.callback.onFoundOrLost(found, address, rssi, advData);
112161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
112261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    }
112361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
112461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    // callback from AdvertiseManager for advertise status dispatch.
112561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    void onMultipleAdvertiseCallback(int clientIf, int status, boolean isStart,
112661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt            AdvertiseSettings settings) throws RemoteException {
1127807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        ClientMap.App app = mClientMap.getById(clientIf);
1128807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        if (app == null || app.callback == null) {
1129807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            Log.e(TAG, "Advertise app or callback is null");
1130807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            return;
1131807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        }
1132807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        app.callback.onMultiAdvertiseCallback(status, isStart, settings);
1133807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt    }
113461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
113561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    void onConfigureMTU(int connId, int status, int mtu) throws RemoteException {
113661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        String address = mClientMap.addressByConnId(connId);
113761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1138807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        if (DBG) Log.d(TAG, "onConfigureMTU() address=" + address + ", status="
1139807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            + status + ", mtu=" + mtu);
1140807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
1141807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
1142807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt        if (app != null) {
1143807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt            app.callback.onConfigureMTU(address, mtu, status);
114461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        }
1145a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1146a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1147a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // Callback for standard advertising instance.
1148a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onAdvertiseCallback(int status, int clientIf) {
1149e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (DBG) Log.d(TAG, "onAdvertiseCallback,- clientIf=" + clientIf + ", status=" + status);
1150e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    }
1151a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1152a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // Followings are callbacks for Bluetooth LE Advertise operations.
1153a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // Start advertising flow is
1154a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    //     enable advertising instance -> onAdvertiseInstaceEnabled
1155a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // ->  set advertise data          -> onAdvertiseDataSet
1156a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // ->  set scan response           -> onAdvertiseDataSet
1157e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1158e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    // Callback when advertise instance is enabled.
1159e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    void onAdvertiseInstanceEnabled(int status, int clientIf) {
1160e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (DBG) Log.d(TAG, "onAdvertiseInstanceEnabled() - "
1161e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt                + "clientIf=" + clientIf + ", status=" + status);
1162e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        mAdvertiseManager.callbackDone(clientIf, status);
1163a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1164a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1165a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // Not really used.
1166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onAdvertiseDataUpdated(int status, int client_if) {
1167a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onAdvertiseDataUpdated() - client_if=" + client_if
1168a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", status=" + status);
1169a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1170a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1171a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // Callback when advertise data or scan response is set.
1172a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onAdvertiseDataSet(int status, int clientIf) {
1173a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onAdvertiseDataSet() - clientIf=" + clientIf
1174a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", status=" + status);
1175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        mAdvertiseManager.callbackDone(clientIf, status);
1176a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1177a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1178a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    // Callback when advertise instance is disabled
1179a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onAdvertiseInstanceDisabled(int status, int clientIf) throws RemoteException {
1180a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onAdvertiseInstanceEnabled() - clientIf=" + clientIf
1181e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt            + ", status=" + status);
1182e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        ClientMap.App app = mClientMap.getById(clientIf);
1183e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (app != null) {
1184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            Log.d(TAG, "Client app is not null!");
1185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            boolean isStart = false;
1186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            if (status == 0) {
1187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.ADVERTISE_SUCCESS,
1188a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                        isStart, null);
1189a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            } else {
1190a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                app.callback.onMultiAdvertiseCallback(
1191a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                        AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR, isStart, null);
1192a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            }
1193a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1194a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1195a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1196a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onClientCongestion(int connId, boolean congested) throws RemoteException {
1197a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested);
1198a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1199a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        ClientMap.App app = mClientMap.getByConnId(connId);
1200a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (app != null) {
1201a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            app.callback.onConnectionCongested(mClientMap.addressByConnId(connId), congested);
1202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1203a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1205a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    /**************************************************************************
1206a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     * GATT Service functions - Shared CLIENT/SERVER
1207a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     *************************************************************************/
1208a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
1210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        final int DEVICE_TYPE_BREDR = 0x1;
1213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1214a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice,
1215a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                                                                 Integer>();
1216a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1217a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        // Add paired LE devices
1218a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1219a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
1220a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        for (BluetoothDevice device : bondedDevices) {
1221a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            if (getDeviceType(device) != DEVICE_TYPE_BREDR) {
1222a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
1223a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            }
1224a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1225a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1226a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        // Add connected deviceStates
1227a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1228a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Set<String> connectedDevices = new HashSet<String>();
1229a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        connectedDevices.addAll(mClientMap.getConnectedDevices());
1230a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        connectedDevices.addAll(mServerMap.getConnectedDevices());
1231a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1232a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        for (String address : connectedDevices ) {
1233a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1234a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            if (device != null) {
1235a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
1236a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            }
1237e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        }
1238e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1239e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        // Create matching device sub-set
1240a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1241a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
1242a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1243a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
1244a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            for(int state : states) {
1245a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                if (entry.getValue() == state) {
1246a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                    deviceList.add(entry.getKey());
1247a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                }
1248a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            }
1249a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1250a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1251a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        return deviceList;
1252a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1253a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1254a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void startScan(int appIf, boolean isServer, ScanSettings settings,
1255a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            List<ScanFilter> filters) {
1256a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "start scan with filters");
1257a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceAdminPermission();
1258e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        mScanManager.startScan(new ScanClient(appIf, isServer, settings, filters));
1259e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    }
1260a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1261a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void flushPendingBatchResults(int clientIf, boolean isServer) {
1262a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "flushPendingBatchResults - clientIf=" + clientIf +
1263a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                ", isServer=" + isServer);
1264a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        mScanManager.flushBatchScanResults(new ScanClient(clientIf, isServer));
1265a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1266a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1267a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void stopScan(int appIf, boolean isServer) {
1268a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceAdminPermission();
1269a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        int scanQueueSize = mScanManager.getBatchScanQueue().size() +
1270a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                mScanManager.getRegularScanQueue().size();
1271a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize);
1272a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        mScanManager.stopScan(new ScanClient(appIf, isServer));
1273a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1274a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1275e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    /**************************************************************************
1276e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt     * GATT Service functions - CLIENT
1277a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     *************************************************************************/
1278a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1279a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void registerClient(UUID uuid, IBluetoothGattCallback callback) {
1280a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1281a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1282a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1283a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        mClientMap.add(uuid, callback);
1284a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1285a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                                    uuid.getMostSignificantBits());
1286a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1287a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1288a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void unregisterClient(int clientIf) {
1289a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1290e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1291e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1292e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        mClientMap.remove(clientIf);
1293a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        gattClientUnregisterAppNative(clientIf);
1294a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1295a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1296a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1297a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1298a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1299a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1300a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        gattClientConnectNative(clientIf, address, isDirect, transport);
1301a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1302a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1303a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void clientDisconnect(int clientIf, String address) {
1304a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1305a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1306a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1307a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1308a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1309a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1310a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1311a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1312a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,
1313e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt            AdvertiseData scanResponse, AdvertiseSettings settings) {
1314e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        enforceAdminPermission();
1315e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData,
1316a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                scanResponse));
1317a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1318a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1319a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void stopMultiAdvertising(int clientIf) {
1320a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceAdminPermission();
1321a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        mAdvertiseManager.stopAdvertising(new AdvertiseClient(clientIf));
1322a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1323a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1324a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1325a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    synchronized List<ParcelUuid> getRegisteredServiceUuids() {
1326a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Utils.enforceAdminPermission(this);
1327a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1328a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1329a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            serviceUuids.add(new ParcelUuid(entry.uuid));
1330a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1331a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        return serviceUuids;
1332a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1333a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1334a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    List<String> getConnectedDevices() {
1335a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1336a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1337a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Set<String> connectedDevAddress = new HashSet<String>();
1338a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1339a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1340a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1341a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        return connectedDeviceList;
1342a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1343a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1344a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void refreshDevice(int clientIf, String address) {
1345a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1346a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1347a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1348a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        gattClientRefreshNative(clientIf, address);
1349a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1350a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1351a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void discoverServices(int clientIf, String address) {
13524171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
13534171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13544171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
13554171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
13564171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13574171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (connId != null)
13584171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            gattClientSearchServiceNative(connId, true, 0, 0);
1359e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        else
1360e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1361e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    }
13624171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13634171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    void readCharacteristic(int clientIf, String address, int srvcType,
13644171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int srvcInstanceId, UUID srvcUuid,
13654171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int charInstanceId, UUID charUuid, int authReq) {
13664171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
13674171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13684171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address);
13694171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13704171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
13714171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (connId != null)
13724171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            gattClientReadCharacteristicNative(connId, srvcType,
13734171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
13744171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                srvcUuid.getMostSignificantBits(), charInstanceId,
13754171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
13764171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                authReq);
13774171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        else
13784171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
13794171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    }
13804171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13814171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    void writeCharacteristic(int clientIf, String address, int srvcType,
13824171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                             int srvcInstanceId, UUID srvcUuid,
13834171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                             int charInstanceId, UUID charUuid, int writeType,
13844171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                             int authReq, byte[] value) {
13854171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
13864171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13874171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
13884171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
13894171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
13904171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
1391a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1392a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (connId != null)
1393a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            gattClientWriteCharacteristicNative(connId, srvcType,
1394a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                srvcInstanceId, srvcUuid.getLeastSignificantBits(),
1395d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                srvcUuid.getMostSignificantBits(), charInstanceId,
1396a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1397a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                writeType, authReq, value);
1398a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        else
13994171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
14004171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    }
1401a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1402a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void readDescriptor(int clientIf, String address, int srvcType,
1403a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                            int srvcInstanceId, UUID srvcUuid,
1404a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                            int charInstanceId, UUID charUuid,
1405a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                            int descrInstanceId, UUID descrUuid,
1406a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                            int authReq) {
1407a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1408a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1409a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address);
1410a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1411a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1412a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (connId != null)
1413a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            gattClientReadDescriptorNative(connId, srvcType,
1414a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                srvcInstanceId,
1415a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
1416a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                charInstanceId,
1417a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1418a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                descrInstanceId,
1419a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
1420a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                authReq);
1421a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        else
1422a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1423a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    };
1424a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
14254171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    void writeDescriptor(int clientIf, String address, int srvcType,
14264171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int srvcInstanceId, UUID srvcUuid,
14274171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int charInstanceId, UUID charUuid,
14284171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int descrInstanceId, UUID descrUuid,
14294171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int writeType, int authReq, byte[] value) {
14304171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14314171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
14324171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address);
14334171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
14344171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
14354171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (connId != null)
14364171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            gattClientWriteDescriptorNative(connId, srvcType,
14374171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                srvcInstanceId,
14384171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
14394171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                charInstanceId,
14404171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
14414171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                descrInstanceId,
14424171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
14434171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                writeType, authReq, value);
14444171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        else
1445a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1446a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1447a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1448a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void beginReliableWrite(int clientIf, String address) {
1449a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1450a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1451a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1452a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        mReliableQueue.add(address);
1453d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1454a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1455a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void endReliableWrite(int clientIf, String address, boolean execute) {
1456a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1457a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
14584171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
14594171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                                + " execute: " + execute);
1460a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        mReliableQueue.remove(address);
14614171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
14624171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1463a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1464a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1465a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1466a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void registerForNotification(int clientIf, String address, int srvcType,
1467a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                int srvcInstanceId, UUID srvcUuid,
1468a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                int charInstanceId, UUID charUuid,
1469a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                boolean enable) {
1470a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1471a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1472a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1473a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1474a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1475a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (connId != null) {
14764171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            gattClientRegisterForNotificationsNative(clientIf, address,
14774171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(),
14787f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                srvcUuid.getMostSignificantBits(), charInstanceId,
1479661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt                charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
1480a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                enable);
1481a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        } else {
1482a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1483a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1484a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1485a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1486a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void readRemoteRssi(int clientIf, String address) {
1487a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1488e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1489e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1490a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        gattClientReadRemoteRssiNative(clientIf, address);
1491a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1492a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1493a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void configureMTU(int clientIf, String address, int mtu) {
1494a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1495a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1496a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1497a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1498a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (connId != null) {
1499a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            gattClientConfigureMTUNative(connId, mtu);
1500a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        } else {
1501a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1502a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1503a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1504a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1505a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
1506a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1507a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1508a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        // Default spec recommended interval is 30->50 ms
1509a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        int minInterval = 24; // 24 * 1.25ms = 30ms
1510a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        int maxInterval = 40; // 40 * 1.25ms = 50ms
1511a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1512a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        // Slave latency
1513a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        int latency = 0;
1514a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1515a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        // Link supervision timeout is measured in N * 10ms
1516a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        int timeout = 2000; // 20s
1517a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1518a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        switch (connectionPriority)
1519a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        {
1520a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            case BluetoothGatt.GATT_CONNECTION_HIGH_PRIORITY:
1521a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                minInterval = 6; // 7.5ms
1522a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                maxInterval = 8; // 10ms
1523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                break;
1524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            case BluetoothGatt.GATT_CONNECTION_LOW_POWER:
1526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                minInterval = 80; // 100ms
1527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                maxInterval = 100; // 125ms
1528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                latency = 2;
1529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                break;
1530a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address
1533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
1534a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
1535a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                                            latency, timeout);
1536e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    }
1537e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1538e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    /**************************************************************************
1539a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     * Callback functions - SERVER
1540a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt     *************************************************************************/
1541a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1542a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1543a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            throws RemoteException {
1544a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1545a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        UUID uuid = new UUID(uuidMsb, uuidLsb);
1546a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1547a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        ServerMap.App app = mServerMap.getByUuid(uuid);
1548a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (app != null) {
1549a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            app.id = serverIf;
1550a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            app.linkToDeath(new ServerDeathRecipient(serverIf));
1551a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            app.callback.onServerRegistered(status, serverIf);
1552a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1553a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1554a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1555a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
15567f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
15577f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                        throws RemoteException {
1558a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1559a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1560a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", handle=" + srvcHandle);
1561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (status == 0) {
1562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1563a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                mAdvertisingServiceUuids.remove(uuid));
1564a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1565a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1566a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        continueServiceDeclaration(serverIf, status, srvcHandle);
1567a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1568a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1569e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1570e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt                                int includedSrvcHandle) throws RemoteException {
1571e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1572a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1573a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        continueServiceDeclaration(serverIf, status, srvcHandle);
1574a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1575a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
15767f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt    void onCharacteristicAdded(int status, int serverIf,
15777f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                               long charUuidLsb, long charUuidMsb,
15787f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                               int srvcHandle, int charHandle)
1579a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                               throws RemoteException {
1580a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1581a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1582a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1583a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (status == 0)
15847f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1585a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        continueServiceDeclaration(serverIf, status, srvcHandle);
1586a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1587a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
15887f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt    void onDescriptorAdded(int status, int serverIf,
15897f0b69e88015ca077ef7a417fde0a76c10df23a5Dmitry Shmidt                           long descrUuidLsb, long descrUuidMsb,
1590a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                           int srvcHandle, int descrHandle)
1591a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                           throws RemoteException {
1592a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1593a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1594a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1595a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (status == 0)
1596a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1597a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        continueServiceDeclaration(serverIf, status, srvcHandle);
1598a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1599e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1600e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    void onServiceStarted(int status, int serverIf, int srvcHandle)
1601a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            throws RemoteException {
1602a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1603a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", status=" + status);
1604a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (status == 0)
1605a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            mHandleMap.setStarted(serverIf, srvcHandle, true);
1606a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1607a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1608a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onServiceStopped(int status, int serverIf, int srvcHandle)
1609a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            throws RemoteException {
1610e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1611e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt            + ", status=" + status);
1612a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (status == 0)
1613a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            mHandleMap.setStarted(serverIf, srvcHandle, false);
1614a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        stopNextService(serverIf, status);
1615a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1616a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1617a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1618a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1619a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", status=" + status);
1620e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        mHandleMap.deleteService(serverIf, srvcHandle);
1621e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt    }
1622a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1623a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1624a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            throws RemoteException {
1625a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1626a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1627a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", address=" + address + ", connected=" + connected);
1628a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1629a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        ServerMap.App app = mServerMap.getById(serverIf);
1630e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (app == null) return;
1631e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1632a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (connected) {
1633a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            mServerMap.addConnection(serverIf, connId, address);
1634a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        } else {
1635a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            mServerMap.removeConnection(serverIf, connId);
1636a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        }
1637a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
1638a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1639a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt    }
1640a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
16414171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    void onAttributeRead(String address, int connId, int transId,
16424171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int attrHandle, int offset, boolean isLong)
16434171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            throws RemoteException {
16444171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (VDBG) Log.d(TAG, "onAttributeRead() connId=" + connId
16454171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            + ", address=" + address + ", handle=" + attrHandle
16464171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            + ", requestId=" + transId + ", offset=" + offset);
1647e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
1648e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1649e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt        if (entry == null) return;
16504171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
16514171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid
16524171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
16534171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
16544171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        mHandleMap.addRequest(transId, attrHandle);
16554171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
16564171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        ServerMap.App app = mServerMap.getById(entry.serverIf);
16574171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        if (app == null) return;
16584171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
16594171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        switch(entry.type) {
16604171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            case HandleMap.TYPE_CHARACTERISTIC:
16614171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            {
16624171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
16634171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
16644171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                    serviceEntry.serviceType, serviceEntry.instance,
16654171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                    new ParcelUuid(serviceEntry.uuid), entry.instance,
16664171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                    new ParcelUuid(entry.uuid));
16674171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                break;
16684171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            }
16694171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
16704171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            case HandleMap.TYPE_DESCRIPTOR:
1671a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            {
1672a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1673a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1674a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1675a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                    serviceEntry.serviceType, serviceEntry.instance,
1676a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1677a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                    new ParcelUuid(charEntry.uuid),
1678a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                    new ParcelUuid(entry.uuid));
1679a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                break;
1680a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            }
16814171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
16824171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt            default:
16834171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
16844171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                break;
16854171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt        }
16864171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    }
16874171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt
16884171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt    void onAttributeWrite(String address, int connId, int transId,
16894171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            int attrHandle, int offset, int length,
16904171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            boolean needRsp, boolean isPrep,
16914171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt                            byte[] data)
1692a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt                            throws RemoteException {
1693a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1694d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            + ", address=" + address + ", handle=" + attrHandle
1695d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            + ", requestId=" + transId + ", isPrep=" + isPrep
1696d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            + ", offset=" + offset);
1697d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1698d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1699d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (entry == null) return;
1700d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1701d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid
1702d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            + ", serverIf=" + entry.serverIf + ", type=" + entry.type);
1703d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1704d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        mHandleMap.addRequest(transId, attrHandle);
1705d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1706d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        ServerMap.App app = mServerMap.getById(entry.serverIf);
1707d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (app == null) return;
1708d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1709d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        switch(entry.type) {
1710d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            case HandleMap.TYPE_CHARACTERISTIC:
1711d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            {
1712d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1713d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                app.callback.onCharacteristicWriteRequest(address, transId,
1714d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            offset, length, isPrep, needRsp,
1715d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            serviceEntry.serviceType, serviceEntry.instance,
1716d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1717d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            new ParcelUuid(entry.uuid), data);
1718d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                break;
1719d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            }
1720d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1721d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            case HandleMap.TYPE_DESCRIPTOR:
1722d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            {
1723d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1724d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1725d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                app.callback.onDescriptorWriteRequest(address, transId,
1726d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            offset, length, isPrep, needRsp,
1727d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            serviceEntry.serviceType, serviceEntry.instance,
1728d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1729d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            new ParcelUuid(charEntry.uuid),
1730d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            new ParcelUuid(entry.uuid), data);
1731d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                break;
1732d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            }
1733d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1734d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            default:
1735d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1736d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                break;
1737d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        }
1738d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1739d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1740d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1741d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            throws RemoteException {
1742d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1743d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            + ", address=" + address + ", transId=" + transId);
1744d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1745d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        ServerMap.App app = mServerMap.getByConnId(connId);
1746d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (app == null) return;
1747d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1748d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1749d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1750d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1751d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void onResponseSendCompleted(int status, int attrHandle) {
1752d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1753d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1754d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1755d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void onNotificationSent(int connId, int status) throws RemoteException {
1756d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
1757d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1758d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        String address = mServerMap.addressByConnId(connId);
1759d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (address == null) return;
1760d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1761d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        ServerMap.App app = mServerMap.getByConnId(connId);
1762d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (app == null) return;
1763d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1764d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        app.callback.onNotificationSent(address, status);
1765d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1766d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1767d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void onServerCongestion(int connId, boolean congested) throws RemoteException {
1768d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
1769d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1770d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        ServerMap.App app = mServerMap.getByConnId(connId);
1771d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (app != null) {
1772d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            app.callback.onConnectionCongested(mServerMap.addressByConnId(connId), congested);
1773d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        }
1774d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1775d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1776d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    /**************************************************************************
1777d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt     * GATT Service functions - SERVER
1778d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt     *************************************************************************/
1779d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1780d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1781d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1782d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1783d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1784d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        mServerMap.add(uuid, callback);
1785d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1786d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                                    uuid.getMostSignificantBits());
1787d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1788d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1789d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void unregisterServer(int serverIf) {
1790d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1791d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1792d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1793d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1794d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        deleteServices(serverIf);
1795d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1796d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        mServerMap.remove(serverIf);
1797d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        gattServerUnregisterAppNative(serverIf);
1798d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1799d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1800d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1801d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1802d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1803d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1804d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        gattServerConnectNative(serverIf, address, isDirect,transport);
1805d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1806d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1807d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void serverDisconnect(int serverIf, String address) {
1808d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1809d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1810d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1811d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1812d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1813d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1814d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1815d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1816d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1817d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1818d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1819d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1820d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1821d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        ServiceDeclaration serviceDeclaration = addDeclaration();
1822d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1823d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            advertisePreferred);
1824d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1825d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1826d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1827d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                            UUID srvcUuid) {
1828d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1829d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1830d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1831d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1832d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1833d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1834d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1835d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                           int permissions) {
1836d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1837d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1838d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1839d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1840d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1841d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1842d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1843d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1844d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1845d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1846d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        getActiveDeclaration().addDescriptor(descUuid, permissions);
1847d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1848d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1849d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void endServiceDeclaration(int serverIf) {
1850d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1851d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1852d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1853d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1854d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (getActiveDeclaration() == getPendingDeclaration()) {
1855d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            try {
1856d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                continueServiceDeclaration(serverIf, (byte)0, 0);
1857d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            } catch (RemoteException e) {
1858d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                Log.e(TAG,""+e);
1859d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            }
1860d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        }
1861d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1862d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1863d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void removeService(int serverIf, int srvcType,
1864d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                  int srvcInstanceId, UUID srvcUuid) {
1865d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1866d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1867d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
1868d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1869d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1870d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (srvcHandle == 0) return;
1871d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        gattServerDeleteServiceNative(serverIf, srvcHandle);
1872d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1873d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1874d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void clearServices(int serverIf) {
1875d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1876d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1877d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "clearServices()");
1878d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        deleteServices(serverIf);
1879d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1880d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1881d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void sendResponse(int serverIf, String address, int requestId,
1882d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                      int status, int offset, byte[] value) {
1883d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1884d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1885d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
1886d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1887d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int handle = 0;
1888d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
1889d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (entry != null) handle = entry.handle;
1890d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1891d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int connId = mServerMap.connIdByAddress(serverIf, address);
1892d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
1893d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                                     handle, offset, value, (byte)0);
1894d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        mHandleMap.deleteRequest(requestId);
1895d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1896d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1897d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    void sendNotification(int serverIf, String address, int srvcType,
1898d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                                 int srvcInstanceId, UUID srvcUuid,
1899d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                                 int charInstanceId, UUID charUuid,
1900d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt                                 boolean confirm, byte[] value) {
1901d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1902d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1903d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address);
1904d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1905d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1906d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (srvcHandle == 0) return;
1907d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1908d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
1909d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (charHandle == 0) return;
1910d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1911d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int connId = mServerMap.connIdByAddress(serverIf, address);
1912d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (connId == 0) return;
1913d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1914d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (confirm) {
1915d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
1916d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        } else {
1917d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
1918d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        }
1919d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    }
1920d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1921d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1922d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    /**************************************************************************
1923d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt     * Private functions
1924d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt     *************************************************************************/
1925d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
1926d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt    private int getDeviceType(BluetoothDevice device) {
1927d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        int type = gattClientGetDeviceTypeNative(device.getAddress());
1928d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
1929a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt            + ", type=" + type);
1930        return type;
1931    }
1932
1933    private void enforceAdminPermission() {
1934        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1935    }
1936
1937    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
1938    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
1939    private void enforcePrivilegedPermission() {
1940        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
1941            "Need BLUETOOTH_PRIVILEGED permission");
1942    }
1943
1944    private void continueSearch(int connId, int status) throws RemoteException {
1945        if (status == 0 && !mSearchQueue.isEmpty()) {
1946            SearchQueue.Entry svc = mSearchQueue.pop();
1947
1948            if (svc.charUuidLsb == 0) {
1949                // Characteristic is up next
1950                gattClientGetCharacteristicNative(svc.connId, svc.srvcType,
1951                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0);
1952            } else {
1953                // Descriptor is up next
1954                gattClientGetDescriptorNative(svc.connId, svc.srvcType,
1955                    svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
1956                    svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
1957            }
1958        } else {
1959            ClientMap.App app = mClientMap.getByConnId(connId);
1960            if (app != null) {
1961                app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status);
1962            }
1963        }
1964    }
1965
1966    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
1967        if (mServiceDeclarations.size() == 0) return;
1968        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
1969
1970        boolean finished = false;
1971
1972        ServiceDeclaration.Entry entry = null;
1973        if (status == 0)
1974            entry = getPendingDeclaration().getNext();
1975
1976        if (entry != null) {
1977            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
1978                + entry.type);
1979            switch(entry.type) {
1980                case ServiceDeclaration.TYPE_SERVICE:
1981                    if (entry.advertisePreferred) {
1982                        mAdvertisingServiceUuids.add(entry.uuid);
1983                    }
1984                    gattServerAddServiceNative(serverIf, entry.serviceType,
1985                        entry.instance,
1986                        entry.uuid.getLeastSignificantBits(),
1987                        entry.uuid.getMostSignificantBits(),
1988                        getPendingDeclaration().getNumHandles());
1989                    break;
1990
1991                case ServiceDeclaration.TYPE_CHARACTERISTIC:
1992                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
1993                        entry.uuid.getLeastSignificantBits(),
1994                        entry.uuid.getMostSignificantBits(),
1995                        entry.properties, entry.permissions);
1996                    break;
1997
1998                case ServiceDeclaration.TYPE_DESCRIPTOR:
1999                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2000                        entry.uuid.getLeastSignificantBits(),
2001                        entry.uuid.getMostSignificantBits(),
2002                        entry.permissions);
2003                    break;
2004
2005                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2006                {
2007                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2008                                            entry.serviceType, entry.instance);
2009                    if (inclSrvc != 0) {
2010                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2011                                                           inclSrvc);
2012                    } else {
2013                        finished = true;
2014                    }
2015                    break;
2016                }
2017            }
2018        } else {
2019            gattServerStartServiceNative(serverIf, srvcHandle,
2020                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2021            finished = true;
2022        }
2023
2024        if (finished) {
2025            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2026            ServerMap.App app = mServerMap.getById(serverIf);
2027            if (app != null) {
2028                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2029
2030                if (serviceEntry != null) {
2031                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2032                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2033                } else {
2034                    app.callback.onServiceAdded(status, 0, 0, null);
2035                }
2036            }
2037            removePendingDeclaration();
2038
2039            if (getPendingDeclaration() != null) {
2040                continueServiceDeclaration(serverIf, (byte)0, 0);
2041            }
2042        }
2043    }
2044
2045    private void stopNextService(int serverIf, int status) throws RemoteException {
2046        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2047            + ", status=" + status);
2048
2049        if (status == 0) {
2050            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2051            for(HandleMap.Entry entry : entries) {
2052                if (entry.type != HandleMap.TYPE_SERVICE ||
2053                    entry.serverIf != serverIf ||
2054                    entry.started == false)
2055                        continue;
2056
2057                gattServerStopServiceNative(serverIf, entry.handle);
2058                return;
2059            }
2060        }
2061    }
2062
2063    private void deleteServices(int serverIf) {
2064        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2065
2066        /*
2067         * Figure out which handles to delete.
2068         * The handles are copied into a new list to avoid race conditions.
2069         */
2070        List<Integer> handleList = new ArrayList<Integer>();
2071        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2072        for(HandleMap.Entry entry : entries) {
2073            if (entry.type != HandleMap.TYPE_SERVICE ||
2074                entry.serverIf != serverIf)
2075                    continue;
2076            handleList.add(entry.handle);
2077        }
2078
2079        /* Now actually delete the services.... */
2080        for(Integer handle : handleList) {
2081            gattServerDeleteServiceNative(serverIf, handle);
2082        }
2083    }
2084
2085    private List<UUID> parseUuids(byte[] adv_data) {
2086        List<UUID> uuids = new ArrayList<UUID>();
2087
2088        int offset = 0;
2089        while(offset < (adv_data.length-2)) {
2090            int len = adv_data[offset++];
2091            if (len == 0) break;
2092
2093            int type = adv_data[offset++];
2094            switch (type) {
2095                case 0x02: // Partial list of 16-bit UUIDs
2096                case 0x03: // Complete list of 16-bit UUIDs
2097                    while (len > 1) {
2098                        int uuid16 = adv_data[offset++];
2099                        uuid16 += (adv_data[offset++] << 8);
2100                        len -= 2;
2101                        uuids.add(UUID.fromString(String.format(
2102                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2103                    }
2104                    break;
2105
2106                default:
2107                    offset += (len - 1);
2108                    break;
2109            }
2110        }
2111
2112        return uuids;
2113    }
2114
2115    /**************************************************************************
2116     * GATT Test functions
2117     *************************************************************************/
2118
2119    void gattTestCommand(int command, UUID uuid1, String bda1,
2120                         int p1, int p2, int p3, int p4, int p5) {
2121        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2122        if (uuid1 != null)
2123            gattTestNative(command, uuid1.getLeastSignificantBits(),
2124                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2125        else
2126            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2127    }
2128
2129    private native void gattTestNative(int command,
2130                                    long uuid1_lsb, long uuid1_msb, String bda1,
2131                                    int p1, int p2, int p3, int p4, int p5);
2132
2133    /**************************************************************************
2134     * Native functions prototypes
2135     *************************************************************************/
2136
2137    private native static void classInitNative();
2138    private native void initializeNative();
2139    private native void cleanupNative();
2140
2141    private native int gattClientGetDeviceTypeNative(String address);
2142
2143    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2144                                                    long app_uuid_msb);
2145
2146    private native void gattClientUnregisterAppNative(int clientIf);
2147
2148    private native void gattClientConnectNative(int clientIf, String address,
2149            boolean isDirect, int transport);
2150
2151    private native void gattClientDisconnectNative(int clientIf, String address,
2152            int conn_id);
2153
2154    private native void gattClientRefreshNative(int clientIf, String address);
2155
2156    private native void gattClientSearchServiceNative(int conn_id,
2157            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2158
2159    private native void gattClientGetCharacteristicNative(int conn_id,
2160            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2161            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2162            long char_id_uuid_msb);
2163
2164    private native void gattClientGetDescriptorNative(int conn_id, int service_type,
2165            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2166            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2167            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
2168
2169    private native void gattClientGetIncludedServiceNative(int conn_id,
2170            int service_type, int service_id_inst_id,
2171            long service_id_uuid_lsb, long service_id_uuid_msb,
2172            int incl_service_id_inst_id, int incl_service_type,
2173            long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb);
2174
2175    private native void gattClientReadCharacteristicNative(int conn_id,
2176            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2177            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2178            long char_id_uuid_msb, int authReq);
2179
2180    private native void gattClientReadDescriptorNative(int conn_id, int service_type,
2181            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2182            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2183            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2184            int authReq);
2185
2186    private native void gattClientWriteCharacteristicNative(int conn_id,
2187            int service_type, int service_id_inst_id, long service_id_uuid_lsb,
2188            long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
2189            long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
2190
2191    private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
2192            int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
2193            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2194            int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
2195            int write_type, int auth_req, byte[] value);
2196
2197    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2198
2199    private native void gattClientRegisterForNotificationsNative(int clientIf,
2200            String address, int service_type, int service_id_inst_id,
2201            long service_id_uuid_lsb, long service_id_uuid_msb,
2202            int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
2203            boolean enable);
2204
2205    private native void gattClientReadRemoteRssiNative(int clientIf,
2206            String address);
2207
2208    private native void gattAdvertiseNative(int client_if, boolean start);
2209
2210    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2211
2212    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2213            int minInterval, int maxInterval, int latency, int timeout);
2214
2215    private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
2216            boolean inclTxPower, int minInterval, int maxInterval,
2217            int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
2218
2219    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2220                                                    long app_uuid_msb);
2221
2222    private native void gattServerUnregisterAppNative(int serverIf);
2223
2224    private native void gattServerConnectNative(int server_if, String address,
2225                                             boolean is_direct, int transport);
2226
2227    private native void gattServerDisconnectNative(int serverIf, String address,
2228                                              int conn_id);
2229
2230    private native void gattServerAddServiceNative (int server_if,
2231            int service_type, int service_id_inst_id,
2232            long service_id_uuid_lsb, long service_id_uuid_msb,
2233            int num_handles);
2234
2235    private native void gattServerAddIncludedServiceNative (int server_if,
2236            int svc_handle, int included_svc_handle);
2237
2238    private native void gattServerAddCharacteristicNative (int server_if,
2239            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2240            int properties, int permissions);
2241
2242    private native void gattServerAddDescriptorNative (int server_if,
2243            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2244            int permissions);
2245
2246    private native void gattServerStartServiceNative (int server_if,
2247            int svc_handle, int transport );
2248
2249    private native void gattServerStopServiceNative (int server_if,
2250                                                     int svc_handle);
2251
2252    private native void gattServerDeleteServiceNative (int server_if,
2253                                                       int svc_handle);
2254
2255    private native void gattServerSendIndicationNative (int server_if,
2256            int attr_handle, int conn_id, byte[] val);
2257
2258    private native void gattServerSendNotificationNative (int server_if,
2259            int attr_handle, int conn_id, byte[] val);
2260
2261    private native void gattServerSendResponseNative (int server_if,
2262            int conn_id, int trans_id, int status, int handle, int offset,
2263            byte[] val, int auth_req);
2264}
2265