replace : iotivity -> iotivity-sec
[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, "we found that has the Device [" + device.getAddress() +
225                                "] which has custom adv");
226                     caLeScanCallback(device);
227                 }
228             }
229         } catch(UnsatisfiedLinkError e) {
230             e.printStackTrace();
231         }
232     }
233
234     private static List<UUID> getUuids(final byte[] scanRecord) {
235         List<UUID> uuids = new ArrayList<UUID>();
236
237         int offset = 0;
238         while (offset < (scanRecord.length - 2)) {
239             int len = scanRecord[offset++];
240             if (len <= 0)
241                 break;
242
243             int type = scanRecord[offset++];
244
245             switch (type) {
246             case 0x02:
247             case 0x03:
248                 while (len > 1) {
249                     int uuid16 = scanRecord[offset++];
250                     uuid16 += (scanRecord[offset++] << 8);
251                     len -= 2;
252                     uuids.add(UUID.fromString(String.format(
253                             "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
254                 }
255                 break;
256             case 0x06:
257             case 0x07:
258                 while (len >= 16) {
259                     try {
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());
267                         continue;
268                     } finally {
269                         offset += 15;
270                         len -= 16;
271                     }
272                 }
273                 break;
274             default:
275                 if (len >= custom_uuid_len1) {
276                     StringBuffer strbuf1 = new StringBuffer();
277                     int strcnt = 0;
278                     int backlen = len;
279                     while (backlen > 1) {
280                         String str = String.format("%02x", scanRecord[offset++]);
281                         backlen -= 1;
282                         if (strcnt < custom_uuid_strlen1) {
283                             strbuf1.append(str);
284                         }
285                         else {
286                             break;
287                         }
288                         strcnt++;
289                     }
290                     offset += (backlen - 1);
291                     uuids.add(UUID.fromString(String.format(
292                             "%4s-0000-0000-0000-000000000000",
293                             strbuf1.toString())));
294                 } else {
295                     offset += (len - 1);
296                 }
297                 break;
298             }
299         }
300         return uuids;
301     }
302
303     private static final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
304
305         @Override
306         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
307             super.onConnectionStateChange(gatt, status, newState);
308
309             caLeGattConnectionStateChangeCallback(gatt, status, newState);
310             caManagerLeGattConnectionStateChangeCB(gatt, status, newState);
311             caLeGattNWConnectionStateChangeCallback(gatt, status, newState);
312         }
313
314         @Override
315         public void onServicesDiscovered(BluetoothGatt gatt, int status) {
316             super.onServicesDiscovered(gatt, status);
317
318             caLeGattServicesDiscoveredCallback(gatt, status);
319             caManagerLeServicesDiscoveredCallback(gatt, status);
320             caLeGattNWServicesDiscoveredCallback(gatt, status);
321         }
322
323         @Override
324         public void onCharacteristicRead(BluetoothGatt gatt,
325                 BluetoothGattCharacteristic characteristic, int status) {
326             super.onCharacteristicRead(gatt, characteristic, status);
327         }
328
329         @Override
330         public void onCharacteristicWrite(BluetoothGatt gatt,
331                 BluetoothGattCharacteristic characteristic, int status) {
332             super.onCharacteristicWrite(gatt, characteristic, status);
333
334             caLeGattCharacteristicWriteCallback(gatt, characteristic.getValue(), status);
335         }
336
337         @Override
338         public void onCharacteristicChanged(BluetoothGatt gatt,
339                 BluetoothGattCharacteristic characteristic) {
340             super.onCharacteristicChanged(gatt, characteristic);
341
342             caLeGattCharacteristicChangedCallback(gatt, characteristic.getValue());
343         }
344
345         @Override
346         public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
347                 int status) {
348             super.onDescriptorRead(gatt, descriptor, status);
349         }
350
351         @Override
352         public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
353                 int status) {
354             super.onDescriptorWrite(gatt, descriptor, status);
355
356             caLeGattDescriptorWriteCallback(gatt, status);
357             caLeGattNWDescriptorWriteCallback(gatt, status);
358         }
359
360         @Override
361         public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
362             super.onReliableWriteCompleted(gatt, status);
363         }
364
365         @Override
366         public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
367             super.onReadRemoteRssi(gatt, rssi, status);
368             caManagerLeRemoteRssiCallback(gatt, rssi, status);
369         }
370
371         @Override
372         public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
373             super.onMtuChanged(gatt, mtu, status);
374             caLeGattMtuChangedCallback(gatt, mtu, status);
375         }
376     };
377
378     private static final BroadcastReceiver mReceiver = new BroadcastReceiver() {
379
380         @Override
381         public void onReceive(Context context, Intent intent) {
382
383             String action = intent.getAction();
384
385             if (action != null && action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
386
387                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
388                                                BluetoothAdapter.ERROR);
389
390                 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_OFF
391                         || state == BluetoothAdapter.STATE_TURNING_OFF)
392                 {
393                     caLeStateChangedCallback(state);
394                     caManagerAdapterStateChangedCallback(state);
395                 }
396             }
397
398             if (action != null && action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
399
400                 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
401                                                    BluetoothDevice.ERROR);
402
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);
408
409                         caManagerBondStateChangedCallback(device);
410                         caLeBondStateChangedCallback(device.getAddress());
411                     }
412                 }
413             }
414         }
415     };
416 }
417