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, "we found that has the Device [" + device.getAddress() +
225 "] which has custom adv");
226 caLeScanCallback(device);
229 } catch(UnsatisfiedLinkError e) {
234 private static List<UUID> getUuids(final byte[] scanRecord) {
235 List<UUID> uuids = new ArrayList<UUID>();
238 while (offset < (scanRecord.length - 2)) {
239 int len = scanRecord[offset++];
243 int type = scanRecord[offset++];
249 int uuid16 = scanRecord[offset++];
250 uuid16 += (scanRecord[offset++] << 8);
252 uuids.add(UUID.fromString(String.format(
253 "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
260 ByteBuffer buffer = ByteBuffer.wrap(scanRecord, offset++, 16).
261 order(ByteOrder.LITTLE_ENDIAN);
262 long mostSigBits = buffer.getLong();
263 long leastSigBits = buffer.getLong();
264 uuids.add(new UUID(leastSigBits, mostSigBits));
265 } catch (IndexOutOfBoundsException e) {
266 Log.e(TAG, e.toString());
275 if (len >= custom_uuid_len1) {
276 StringBuffer strbuf1 = new StringBuffer();
279 while (backlen > 1) {
280 String str = String.format("%02x", scanRecord[offset++]);
282 if (strcnt < custom_uuid_strlen1) {
290 offset += (backlen - 1);
291 uuids.add(UUID.fromString(String.format(
292 "%4s-0000-0000-0000-000000000000",
293 strbuf1.toString())));
303 private static final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
306 public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
307 super.onConnectionStateChange(gatt, status, newState);
309 caLeGattConnectionStateChangeCallback(gatt, status, newState);
310 caManagerLeGattConnectionStateChangeCB(gatt, status, newState);
311 caLeGattNWConnectionStateChangeCallback(gatt, status, newState);
315 public void onServicesDiscovered(BluetoothGatt gatt, int status) {
316 super.onServicesDiscovered(gatt, status);
318 caLeGattServicesDiscoveredCallback(gatt, status);
319 caManagerLeServicesDiscoveredCallback(gatt, status);
320 caLeGattNWServicesDiscoveredCallback(gatt, status);
324 public void onCharacteristicRead(BluetoothGatt gatt,
325 BluetoothGattCharacteristic characteristic, int status) {
326 super.onCharacteristicRead(gatt, characteristic, status);
330 public void onCharacteristicWrite(BluetoothGatt gatt,
331 BluetoothGattCharacteristic characteristic, int status) {
332 super.onCharacteristicWrite(gatt, characteristic, status);
334 caLeGattCharacteristicWriteCallback(gatt, characteristic.getValue(), status);
338 public void onCharacteristicChanged(BluetoothGatt gatt,
339 BluetoothGattCharacteristic characteristic) {
340 super.onCharacteristicChanged(gatt, characteristic);
342 caLeGattCharacteristicChangedCallback(gatt, characteristic.getValue());
346 public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
348 super.onDescriptorRead(gatt, descriptor, status);
352 public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
354 super.onDescriptorWrite(gatt, descriptor, status);
356 caLeGattDescriptorWriteCallback(gatt, status);
357 caLeGattNWDescriptorWriteCallback(gatt, status);
361 public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
362 super.onReliableWriteCompleted(gatt, status);
366 public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
367 super.onReadRemoteRssi(gatt, rssi, status);
368 caManagerLeRemoteRssiCallback(gatt, rssi, status);
372 public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
373 super.onMtuChanged(gatt, mtu, status);
374 caLeGattMtuChangedCallback(gatt, mtu, status);
378 private static final BroadcastReceiver mReceiver = new BroadcastReceiver() {
381 public void onReceive(Context context, Intent intent) {
383 String action = intent.getAction();
385 if (action != null && action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
387 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
388 BluetoothAdapter.ERROR);
390 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_OFF
391 || state == BluetoothAdapter.STATE_TURNING_OFF)
393 caLeStateChangedCallback(state);
394 caManagerAdapterStateChangedCallback(state);
398 if (action != null && action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
400 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
401 BluetoothDevice.ERROR);
403 if (bondState == BluetoothDevice.BOND_NONE) {
404 if ((intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,
405 BluetoothDevice.ERROR) == BluetoothDevice.BOND_BONDED)) {
406 BluetoothDevice device = intent
407 .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
409 caManagerBondStateChangedCallback(device);
410 caLeBondStateChangedCallback(device.getAddress());