1 /******************************************************************
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 ******************************************************************/
21 package org.iotivity.ca;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.UUID;
29 import android.bluetooth.BluetoothAdapter;
30 import android.bluetooth.BluetoothDevice;
31 import android.bluetooth.BluetoothGatt;
32 import android.bluetooth.BluetoothGattCallback;
33 import android.bluetooth.BluetoothGattCharacteristic;
34 import android.bluetooth.BluetoothGattDescriptor;
35 import android.content.BroadcastReceiver;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.IntentFilter;
39 import android.util.Log;
41 // For using bluetooth.le APIs
42 import android.bluetooth.le.BluetoothLeScanner;
43 import android.bluetooth.le.ScanCallback;
44 import android.bluetooth.le.ScanFilter;
45 import android.bluetooth.le.ScanResult;
46 import android.bluetooth.le.ScanSettings;
47 import android.os.ParcelUuid;
48 import java.util.Iterator;
49 import android.os.Build;
51 public class CaLeClientInterface {
53 private static String SERVICE_UUID = "ADE3D529-C784-4F63-A987-EB69F70EE816";
54 private static String TAG = "OIC_LE_CB_INTERFACE";
55 private static Context mContext;
56 private static volatile boolean isLeClientInitialized = false;
58 //For custom uuid ble server
59 final static String CUSTOM_UUID = "75004209-0000-0000-0000-000000000000";
60 final static String CUSTOM_UUID2 = "75004204-0000-0000-0000-000000000000";
61 final static int custom_uuid_len1 = 9;
62 final static int custom_uuid_strlen1 = 4;
64 private CaLeClientInterface(Context context) {
66 caLeRegisterGattCallback(mGattCallback);
67 synchronized(CaLeClientInterface.class) {
70 if (!isLeClientInitialized) {
71 registerIntentFilter();
72 isLeClientInitialized = true;
76 public static void getLeScanCallback() {
77 // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
78 // caLeRegisterLeScanCallbackForV21(mLeScanCallbackForV21);
80 caLeRegisterLeScanCallback(mLeScanCallback);
84 public static void getLeGattCallback() {
85 caLeRegisterGattCallback(mGattCallback);
88 private static IntentFilter registerIntentFilter() {
89 IntentFilter filter = new IntentFilter();
90 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
91 filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
92 mContext.registerReceiver(mReceiver, filter);
96 public static void destroyLeInterface() {
97 if (isLeClientInitialized) {
98 mContext.unregisterReceiver(mReceiver);
99 isLeClientInitialized = false;
103 public static BluetoothGatt connectGattforHidden(BluetoothDevice device,
104 String address, boolean autoConnect) {
105 if (isLeClientInitialized) {
106 BluetoothAdapter mbluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
107 BluetoothDevice mDevice = mbluetoothAdapter.getRemoteDevice(address);
108 Log.d(TAG, "connectGattforHidden method : getAddress : " + mDevice.getAddress()
109 + ", autoconnect : " + autoConnect);
110 return mDevice.connectGatt(mContext, autoConnect, mGattCallback);
115 private native static void caLeRegisterLeScanCallback(BluetoothAdapter.LeScanCallback callback);
117 private native static void caLeRegisterLeScanCallbackForV21(ScanCallback callback);
119 private native static void caLeRegisterGattCallback(BluetoothGattCallback callback);
121 // BluetoothAdapter.LeScanCallback
122 private native static void caLeScanCallback(BluetoothDevice device);
124 // scan failed callback for ca layer
125 private native static void caLeScanFailedCallback(int errorCode);
127 // BluetoothGattCallback
128 private native static void caLeGattConnectionStateChangeCallback(
129 BluetoothGatt gatt, int status, int newState);
131 // BluetoothGattCallback for Connection Manager
132 private native static void caManagerLeGattConnectionStateChangeCB(
133 BluetoothGatt gatt, int status, int newState);
135 private native static void caLeGattNWConnectionStateChangeCallback(
136 BluetoothGatt gatt, int status, int newState);
138 private native static void caLeGattServicesDiscoveredCallback(BluetoothGatt gatt, int status);
140 private native static void caLeGattNWServicesDiscoveredCallback(BluetoothGatt gatt,
143 private native static void caLeGattNWDescriptorWriteCallback(BluetoothGatt gatt, int status);
145 private native static void caLeGattCharacteristicWriteCallback(
146 BluetoothGatt gatt, byte[] data, int status);
148 private native static void caLeGattCharacteristicChangedCallback(
149 BluetoothGatt gatt, byte[] data);
151 private native static void caLeGattDescriptorWriteCallback(BluetoothGatt gatt, int status);
153 private native static void caLeGattReliableWriteCompletedCallback(BluetoothGatt gatt,
156 private native static void caLeGattReadRemoteRssiCallback(BluetoothGatt gatt, int rssi,
160 private native static void caLeStateChangedCallback(int state);
163 private native static void caLeBondStateChangedCallback(String address);
166 private native static void caManagerAdapterStateChangedCallback(int state);
169 private native static void caManagerBondStateChangedCallback(BluetoothDevice address);
171 private native static void caManagerLeServicesDiscoveredCallback(BluetoothGatt gatt,
174 private native static void caManagerLeRemoteRssiCallback(BluetoothGatt gatt, int rssi,
177 private native static void caLeGattMtuChangedCallback(BluetoothGatt gatt, int mtu,
180 // Le Scan Callback which lower than API 21
181 private static BluetoothAdapter.LeScanCallback mLeScanCallback =
182 new BluetoothAdapter.LeScanCallback() {
185 public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
186 filteringScanResult(device, scanRecord);
190 // Le Scan Callback which upper than API 21
191 private static ScanCallback mLeScanCallbackForV21 = new ScanCallback() {
193 public void onScanResult(int callbackType, ScanResult result) {
194 super.onScanResult(callbackType, result);
195 Log.d(TAG, "onScanResult from ScanCallback");
196 filteringScanResult(result.getDevice(), result.getScanRecord().getBytes());
200 public void onBatchScanResults(List<ScanResult> results) {
201 super.onBatchScanResults(results);
202 Iterator<ScanResult> itr = results.iterator();
203 while (itr.hasNext()) {
204 filteringScanResult(itr.next().getDevice(),
205 itr.next().getScanRecord().getBytes());
210 public void onScanFailed(int errorCode) {
211 super.onScanFailed(errorCode);
212 caLeScanFailedCallback(errorCode);
216 private static void filteringScanResult(BluetoothDevice device, byte[] scanRecord) {
218 List<UUID> uuids = getUuids(scanRecord);
219 for (UUID uuid : uuids) {
220 if(uuid.toString().contains(SERVICE_UUID.toLowerCase())) {
221 caLeScanCallback(device);
222 } else if(uuid.toString().contains(CUSTOM_UUID.toLowerCase()) ||
223 uuid.toString().contains(CUSTOM_UUID2.toLowerCase())) {
224 Log.d(TAG, "Found device which has custom adv");
225 caLeScanCallback(device);
228 } catch(UnsatisfiedLinkError e) {
233 private static List<UUID> getUuids(final byte[] scanRecord) {
234 List<UUID> uuids = new ArrayList<UUID>();
237 while (offset < (scanRecord.length - 2)) {
238 int len = scanRecord[offset++];
242 int type = scanRecord[offset++];
248 int uuid16 = scanRecord[offset++];
249 uuid16 += (scanRecord[offset++] << 8);
251 uuids.add(UUID.fromString(String.format(
252 "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
259 ByteBuffer buffer = ByteBuffer.wrap(scanRecord, offset++, 16).
260 order(ByteOrder.LITTLE_ENDIAN);
261 long mostSigBits = buffer.getLong();
262 long leastSigBits = buffer.getLong();
263 uuids.add(new UUID(leastSigBits, mostSigBits));
264 } catch (IndexOutOfBoundsException e) {
265 Log.e(TAG, e.toString());
274 if (len >= custom_uuid_len1) {
275 StringBuffer strbuf1 = new StringBuffer();
278 while (backlen > 1) {
279 String str = String.format("%02x", scanRecord[offset++]);
281 if (strcnt < custom_uuid_strlen1) {
289 offset += (backlen - 1);
290 uuids.add(UUID.fromString(String.format(
291 "%4s-0000-0000-0000-000000000000",
292 strbuf1.toString())));
302 private static final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
305 public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
306 super.onConnectionStateChange(gatt, status, newState);
308 caLeGattConnectionStateChangeCallback(gatt, status, newState);
309 caManagerLeGattConnectionStateChangeCB(gatt, status, newState);
310 caLeGattNWConnectionStateChangeCallback(gatt, status, newState);
314 public void onServicesDiscovered(BluetoothGatt gatt, int status) {
315 super.onServicesDiscovered(gatt, status);
317 caLeGattServicesDiscoveredCallback(gatt, status);
318 caManagerLeServicesDiscoveredCallback(gatt, status);
319 caLeGattNWServicesDiscoveredCallback(gatt, status);
323 public void onCharacteristicRead(BluetoothGatt gatt,
324 BluetoothGattCharacteristic characteristic, int status) {
325 super.onCharacteristicRead(gatt, characteristic, status);
329 public void onCharacteristicWrite(BluetoothGatt gatt,
330 BluetoothGattCharacteristic characteristic, int status) {
331 super.onCharacteristicWrite(gatt, characteristic, status);
333 caLeGattCharacteristicWriteCallback(gatt, characteristic.getValue(), status);
337 public void onCharacteristicChanged(BluetoothGatt gatt,
338 BluetoothGattCharacteristic characteristic) {
339 super.onCharacteristicChanged(gatt, characteristic);
341 caLeGattCharacteristicChangedCallback(gatt, characteristic.getValue());
345 public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
347 super.onDescriptorRead(gatt, descriptor, status);
351 public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
353 super.onDescriptorWrite(gatt, descriptor, status);
355 caLeGattDescriptorWriteCallback(gatt, status);
356 caLeGattNWDescriptorWriteCallback(gatt, status);
360 public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
361 super.onReliableWriteCompleted(gatt, status);
365 public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
366 super.onReadRemoteRssi(gatt, rssi, status);
367 caManagerLeRemoteRssiCallback(gatt, rssi, status);
371 public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
372 super.onMtuChanged(gatt, mtu, status);
373 caLeGattMtuChangedCallback(gatt, mtu, status);
377 private static final BroadcastReceiver mReceiver = new BroadcastReceiver() {
380 public void onReceive(Context context, Intent intent) {
382 String action = intent.getAction();
384 if (action != null && action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
386 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
387 BluetoothAdapter.ERROR);
389 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_OFF
390 || state == BluetoothAdapter.STATE_TURNING_OFF)
392 caLeStateChangedCallback(state);
393 caManagerAdapterStateChangedCallback(state);
397 if (action != null && action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
399 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
400 BluetoothDevice.ERROR);
402 if (bondState == BluetoothDevice.BOND_NONE) {
403 if ((intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,
404 BluetoothDevice.ERROR) == BluetoothDevice.BOND_BONDED)) {
405 BluetoothDevice device = intent
406 .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
408 caManagerBondStateChangedCallback(device);
409 caLeBondStateChangedCallback(device.getAddress());