75dde183750ca019523a64871d04035289032360
[platform/upstream/iotivity.git] / android / android_api / base / src / main / java / org / iotivity / ca / CaLeClientInterface.java
1 /******************************************************************
2  *
3  * Copyright 2014 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  ******************************************************************/
20
21 package org.iotivity.ca;
22
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;
28
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;
40
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;
50
51 public class CaLeClientInterface {
52
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;
57
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;
63
64     private CaLeClientInterface(Context context) {
65         getLeScanCallback();
66         caLeRegisterGattCallback(mGattCallback);
67         synchronized(CaLeClientInterface.class) {
68             mContext = context;
69         }
70         if (!isLeClientInitialized) {
71             registerIntentFilter();
72             isLeClientInitialized = true;
73         }
74     }
75
76     public static void getLeScanCallback() {
77 //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
78 //            caLeRegisterLeScanCallbackForV21(mLeScanCallbackForV21);
79 //        } else {
80             caLeRegisterLeScanCallback(mLeScanCallback);
81 //        }
82     }
83
84     public static void getLeGattCallback() {
85         caLeRegisterGattCallback(mGattCallback);
86     }
87
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);
93         return filter;
94     }
95
96     public static void destroyLeInterface() {
97         if (isLeClientInitialized) {
98             mContext.unregisterReceiver(mReceiver);
99             isLeClientInitialized = false;
100         }
101     }
102
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);
111         }
112         return null;
113     }
114
115     private native static void caLeRegisterLeScanCallback(BluetoothAdapter.LeScanCallback callback);
116
117     private native static void caLeRegisterLeScanCallbackForV21(ScanCallback callback);
118
119     private native static void caLeRegisterGattCallback(BluetoothGattCallback callback);
120
121     // BluetoothAdapter.LeScanCallback
122     private native static void caLeScanCallback(BluetoothDevice device);
123
124     // scan failed callback for ca layer
125     private native static void caLeScanFailedCallback(int errorCode);
126
127     // BluetoothGattCallback
128     private native static void caLeGattConnectionStateChangeCallback(
129             BluetoothGatt gatt, int status, int newState);
130
131     // BluetoothGattCallback for Connection Manager
132     private native static void caManagerLeGattConnectionStateChangeCB(
133             BluetoothGatt gatt, int status, int newState);
134
135     private native static void caLeGattNWConnectionStateChangeCallback(
136             BluetoothGatt gatt, int status, int newState);
137
138     private native static void caLeGattServicesDiscoveredCallback(BluetoothGatt gatt, int status);
139
140     private native static void caLeGattNWServicesDiscoveredCallback(BluetoothGatt gatt,
141                                                                     int status);
142
143     private native static void caLeGattNWDescriptorWriteCallback(BluetoothGatt gatt, int status);
144
145     private native static void caLeGattCharacteristicWriteCallback(
146             BluetoothGatt gatt, byte[] data, int status);
147
148     private native static void caLeGattCharacteristicChangedCallback(
149             BluetoothGatt gatt, byte[] data);
150
151     private native static void caLeGattDescriptorWriteCallback(BluetoothGatt gatt, int status);
152
153     private native static void caLeGattReliableWriteCompletedCallback(BluetoothGatt gatt,
154                                                                      int status);
155
156     private native static void caLeGattReadRemoteRssiCallback(BluetoothGatt gatt, int rssi,
157                                                              int status);
158
159     // Network Monitor
160     private native static void caLeStateChangedCallback(int state);
161
162     // bond state
163     private native static void caLeBondStateChangedCallback(String address);
164
165     // adapter state
166     private native static void caManagerAdapterStateChangedCallback(int state);
167
168     // bond state
169     private native static void caManagerBondStateChangedCallback(BluetoothDevice address);
170
171     private native static void caManagerLeServicesDiscoveredCallback(BluetoothGatt gatt,
172                                                                      int status);
173
174     private native static void caManagerLeRemoteRssiCallback(BluetoothGatt gatt, int rssi,
175                                                              int status);
176
177     private native static void caLeGattMtuChangedCallback(BluetoothGatt gatt, int mtu,
178                                                           int status);
179
180     // Le Scan Callback which lower than API 21
181     private static BluetoothAdapter.LeScanCallback mLeScanCallback =
182                    new BluetoothAdapter.LeScanCallback() {
183
184         @Override
185         public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
186             filteringScanResult(device, scanRecord);
187         }
188     };
189
190     // Le Scan Callback which upper than API 21
191     private static ScanCallback mLeScanCallbackForV21 = new ScanCallback() {
192         @Override
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());
197         }
198
199         @Override
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());
206             }
207         }
208
209         @Override
210         public void onScanFailed(int errorCode) {
211             super.onScanFailed(errorCode);
212             caLeScanFailedCallback(errorCode);
213         }
214     };
215
216     private static void filteringScanResult(BluetoothDevice device, byte[] scanRecord) {
217         try {
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);
226                 }
227             }
228         } catch(UnsatisfiedLinkError e) {
229             e.printStackTrace();
230         }
231     }
232
233     private static List<UUID> getUuids(final byte[] scanRecord) {
234         List<UUID> uuids = new ArrayList<UUID>();
235
236         int offset = 0;
237         while (offset < (scanRecord.length - 2)) {
238             int len = scanRecord[offset++];
239             if (len <= 0)
240                 break;
241
242             int type = scanRecord[offset++];
243
244             switch (type) {
245             case 0x02:
246             case 0x03:
247                 while (len > 1) {
248                     int uuid16 = scanRecord[offset++];
249                     uuid16 += (scanRecord[offset++] << 8);
250                     len -= 2;
251                     uuids.add(UUID.fromString(String.format(
252                             "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
253                 }
254                 break;
255             case 0x06:
256             case 0x07:
257                 while (len >= 16) {
258                     try {
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());
266                         continue;
267                     } finally {
268                         offset += 15;
269                         len -= 16;
270                     }
271                 }
272                 break;
273             default:
274                 if (len >= custom_uuid_len1) {
275                     StringBuffer strbuf1 = new StringBuffer();
276                     int strcnt = 0;
277                     int backlen = len;
278                     while (backlen > 1) {
279                         String str = String.format("%02x", scanRecord[offset++]);
280                         backlen -= 1;
281                         if (strcnt < custom_uuid_strlen1) {
282                             strbuf1.append(str);
283                         }
284                         else {
285                             break;
286                         }
287                         strcnt++;
288                     }
289                     offset += (backlen - 1);
290                     uuids.add(UUID.fromString(String.format(
291                             "%4s-0000-0000-0000-000000000000",
292                             strbuf1.toString())));
293                 } else {
294                     offset += (len - 1);
295                 }
296                 break;
297             }
298         }
299         return uuids;
300     }
301
302     private static final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
303
304         @Override
305         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
306             super.onConnectionStateChange(gatt, status, newState);
307
308             caLeGattConnectionStateChangeCallback(gatt, status, newState);
309             caManagerLeGattConnectionStateChangeCB(gatt, status, newState);
310             caLeGattNWConnectionStateChangeCallback(gatt, status, newState);
311         }
312
313         @Override
314         public void onServicesDiscovered(BluetoothGatt gatt, int status) {
315             super.onServicesDiscovered(gatt, status);
316
317             caLeGattServicesDiscoveredCallback(gatt, status);
318             caManagerLeServicesDiscoveredCallback(gatt, status);
319             caLeGattNWServicesDiscoveredCallback(gatt, status);
320         }
321
322         @Override
323         public void onCharacteristicRead(BluetoothGatt gatt,
324                 BluetoothGattCharacteristic characteristic, int status) {
325             super.onCharacteristicRead(gatt, characteristic, status);
326         }
327
328         @Override
329         public void onCharacteristicWrite(BluetoothGatt gatt,
330                 BluetoothGattCharacteristic characteristic, int status) {
331             super.onCharacteristicWrite(gatt, characteristic, status);
332
333             caLeGattCharacteristicWriteCallback(gatt, characteristic.getValue(), status);
334         }
335
336         @Override
337         public void onCharacteristicChanged(BluetoothGatt gatt,
338                 BluetoothGattCharacteristic characteristic) {
339             super.onCharacteristicChanged(gatt, characteristic);
340
341             caLeGattCharacteristicChangedCallback(gatt, characteristic.getValue());
342         }
343
344         @Override
345         public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
346                 int status) {
347             super.onDescriptorRead(gatt, descriptor, status);
348         }
349
350         @Override
351         public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
352                 int status) {
353             super.onDescriptorWrite(gatt, descriptor, status);
354
355             caLeGattDescriptorWriteCallback(gatt, status);
356             caLeGattNWDescriptorWriteCallback(gatt, status);
357         }
358
359         @Override
360         public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
361             super.onReliableWriteCompleted(gatt, status);
362         }
363
364         @Override
365         public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
366             super.onReadRemoteRssi(gatt, rssi, status);
367             caManagerLeRemoteRssiCallback(gatt, rssi, status);
368         }
369
370         @Override
371         public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
372             super.onMtuChanged(gatt, mtu, status);
373             caLeGattMtuChangedCallback(gatt, mtu, status);
374         }
375     };
376
377     private static final BroadcastReceiver mReceiver = new BroadcastReceiver() {
378
379         @Override
380         public void onReceive(Context context, Intent intent) {
381
382             String action = intent.getAction();
383
384             if (action != null && action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
385
386                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
387                                                BluetoothAdapter.ERROR);
388
389                 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_OFF
390                         || state == BluetoothAdapter.STATE_TURNING_OFF)
391                 {
392                     caLeStateChangedCallback(state);
393                     caManagerAdapterStateChangedCallback(state);
394                 }
395             }
396
397             if (action != null && action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
398
399                 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
400                                                    BluetoothDevice.ERROR);
401
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);
407
408                         caManagerBondStateChangedCallback(device);
409                         caLeBondStateChangedCallback(device.getAddress());
410                     }
411                 }
412             }
413         }
414     };
415 }
416