From: samanway Date: Tue, 3 Sep 2019 08:01:03 +0000 (+0530) Subject: SimpleClient Android Application change for BLE X-Git-Tag: accepted/tizen/unified/20190924.062108~3^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f7c3e18a7331bb933e2fd842fc479a8b5063ee0c;p=platform%2Fupstream%2Fiotivity.git SimpleClient Android Application change for BLE This patch is to provide BLE scanning functionality in Android BLE client side. - First application will start BLE scan for nearby devices. - Then app will provide list of BLE devices which are advertising. - Then user will select a device and app will internally connect to it. https://github.sec.samsung.net/RS7-IOTIVITY/IoTivity/pull/563/commits/6d7c44e1c073d74ff117a456007156214b310f1c (cherry-picked from 6d7c44e1c073d74ff117a456007156214b310f1c) Change-Id: I6efd7762ddb33c1e3dee2f2c225c8231d4381b93 Signed-off-by: samanway-dey Signed-off-by: Sudipto --- diff --git a/android/examples/simpleclientblescan/build.gradle b/android/examples/simpleclientblescan/build.gradle new file mode 100644 index 0000000..3a70696 --- /dev/null +++ b/android/examples/simpleclientblescan/build.gradle @@ -0,0 +1,37 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "20.0.0" + + defaultConfig { + applicationId "org.iotivity.base.examples.simpleclientblescan" + minSdkVersion 21 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } +} +repositories { + flatDir { + dirs "../../android_api/base/build/outputs/aar/" + } +} + +try { + dependencies { + compile ":iotivity-base-${TARGET_ARCH}-${RELEASE}@aar" + } +} catch (all) { + print "${ERROR_MSG}" + assert all +} diff --git a/android/examples/simpleclientblescan/proguard-rules.pro b/android/examples/simpleclientblescan/proguard-rules.pro new file mode 100644 index 0000000..d26150c --- /dev/null +++ b/android/examples/simpleclientblescan/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /home/rahul/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/android/examples/simpleclientblescan/simpleclientblescan.iml b/android/examples/simpleclientblescan/simpleclientblescan.iml new file mode 100644 index 0000000..65d6cf5 --- /dev/null +++ b/android/examples/simpleclientblescan/simpleclientblescan.iml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/examples/simpleclientblescan/src/main/AndroidManifest.xml b/android/examples/simpleclientblescan/src/main/AndroidManifest.xml new file mode 100644 index 0000000..021c1ec --- /dev/null +++ b/android/examples/simpleclientblescan/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/examples/simpleclientblescan/src/main/assets/oic_svr_db_client.json b/android/examples/simpleclientblescan/src/main/assets/oic_svr_db_client.json new file mode 100644 index 0000000..c7f5c4e --- /dev/null +++ b/android/examples/simpleclientblescan/src/main/assets/oic_svr_db_client.json @@ -0,0 +1,83 @@ +{ + "acl": { + "aclist": { + "aces": [ + { + "subjectuuid": "*", + "resources": [ + { + "href": "/oic/res", + "rel": "", + "rt": ["oic.wk.res"], + "if": ["oic.if.ll"] + }, + { + "href": "/oic/d", + "rel": "", + "rt": ["oic.wk.d"], + "if": ["oic.if.baseline", "oic.if.r"] + }, + { + "href": "/oic/p", + "rel": "", + "rt": ["oic.wk.p"], + "if": ["oic.if.baseline", "oic.if.r"] + } + ], + "permission": 2 + }, + { + "subjectuuid": "*", + "resources": [ + { + "href": "/oic/sec/doxm", + "rel": "", + "rt": ["oic.r.doxm"], + "if": ["oic.if.baseline"] + }, + { + "href": "/oic/sec/pstat", + "rel": "", + "rt": ["oic.r.pstat"], + "if": ["oic.if.baseline"] + } + ], + "permission": 2 + } + ] + }, + "rowneruuid" : "32323232-3232-3232-3232-323232323232" + }, + "pstat": { + "isop": true, + "deviceuuid": "32323232-3232-3232-3232-323232323232", + "rowneruuid": "32323232-3232-3232-3232-323232323232", + "cm": 0, + "tm": 0, + "om": 4, + "sm": 4 + }, + "doxm": { + "oxms": [0], + "oxmsel": 0, + "sct": 1, + "owned": true, + "deviceuuid": "32323232-3232-3232-3232-323232323232", + "devowneruuid": "32323232-3232-3232-3232-323232323232", + "rowneruuid": "32323232-3232-3232-3232-323232323232" + }, + "cred": { + "creds": [ + { + "credid": 1, + "subjectuuid": "31313131-3131-3131-3131-313131313131", + "credtype": 1, + "privatedata": { + "data": "AAAAAAAAAAAAAAAA", + "encoding": "oic.sec.encoding.raw" + } + } + ], + "rowneruuid": "32323232-3232-3232-3232-323232323232" + } +} \ No newline at end of file diff --git a/android/examples/simpleclientblescan/src/main/java/org/iotivity/base/examples/Light.java b/android/examples/simpleclientblescan/src/main/java/org/iotivity/base/examples/Light.java new file mode 100644 index 0000000..d40c196 --- /dev/null +++ b/android/examples/simpleclientblescan/src/main/java/org/iotivity/base/examples/Light.java @@ -0,0 +1,92 @@ +/* + ******************************************************************* + * + * Copyright 2015 Intel Corporation. + * + *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + */ +package org.iotivity.base.examples; + +import org.iotivity.base.OcException; +import org.iotivity.base.OcRepresentation; + +/** + * Light + *

+ * This class is used by SimpleClient to create an object representation of a remote light resource + * and update the values depending on the server response + */ +public class Light { + public static final String NAME_KEY = "name"; + public static final String STATE_KEY = "state"; + public static final String POWER_KEY = "power"; + + private String mName; + private boolean mState; + private int mPower; + + public Light() { + mName = ""; + mState = false; + mPower = 0; + } + + public void setOcRepresentation(OcRepresentation rep) throws OcException { + mName = rep.getValue(NAME_KEY); + mState = rep.getValue(Light.STATE_KEY); + mPower = rep.getValue(Light.POWER_KEY); + } + + public OcRepresentation getOcRepresentation() throws OcException { + OcRepresentation rep = new OcRepresentation(); + rep.setValue(NAME_KEY, mName); + rep.setValue(STATE_KEY, mState); + rep.setValue(POWER_KEY, mPower); + return rep; + } + + public String getName() { + return mName; + } + + public void setName(String name) { + this.mName = mName; + } + + public boolean getState() { + return mState; + } + + public void setState(boolean state) { + this.mState = state; + } + + public int getPower() { + return mPower; + } + + public void setPower(int power) { + this.mPower = power; + } + + @Override + public String toString() { + return "\t" + NAME_KEY + ": " + mName + + "\n\t" + STATE_KEY + ": " + mState + + "\n\t" + POWER_KEY + ": " + mPower; + } +} diff --git a/android/examples/simpleclientblescan/src/main/java/org/iotivity/base/examples/SimpleClientBleScan.java b/android/examples/simpleclientblescan/src/main/java/org/iotivity/base/examples/SimpleClientBleScan.java new file mode 100644 index 0000000..70162bd --- /dev/null +++ b/android/examples/simpleclientblescan/src/main/java/org/iotivity/base/examples/SimpleClientBleScan.java @@ -0,0 +1,768 @@ +/* + ******************************************************************* + * + * Copyright 2015 Intel Corporation. + * + *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + */ +package org.iotivity.base.examples; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.BroadcastReceiver; +import android.content.IntentFilter; +import android.nfc.NfcAdapter; +import android.os.Bundle; +import android.text.method.ScrollingMovementMethod; +import android.util.Log; +import android.view.View; +import android.widget.ListView; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; +import android.os.ParcelUuid; +import android.os.Handler; +import android.text.TextUtils; + +import org.iotivity.base.ErrorCode; +import org.iotivity.base.ModeType; +import org.iotivity.base.ObserveType; +import org.iotivity.base.OcConnectivityType; +import org.iotivity.base.OcException; +import org.iotivity.base.OcHeaderOption; +import org.iotivity.base.OcPlatform; +import org.iotivity.base.OcRepresentation; +import org.iotivity.base.OcResource; +import org.iotivity.base.OcResourceIdentifier; +import org.iotivity.base.PlatformConfig; +import org.iotivity.base.QualityOfService; +import org.iotivity.base.ServiceType; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import java.nio.charset.Charset; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.le.AdvertiseCallback; +import android.bluetooth.le.AdvertiseData; +import android.bluetooth.le.AdvertiseSettings; +import android.bluetooth.le.BluetoothLeAdvertiser; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanResult; +import android.bluetooth.le.ScanSettings; + +/** + * SimpleClientBleScan + *

+ * SimpleClientBleScan is a sample client app which should be started after the simpleServer is started. + * It finds resources advertised by the server and calls different operations on it (GET, PUT, + * POST, DELETE and OBSERVE). + */ +public class SimpleClientBleScan extends Activity implements + OcPlatform.OnResourceFoundListener, + OcResource.OnGetListener, + OcResource.OnPutListener, + OcResource.OnPostListener, + OcResource.OnObserveListener { + + private Map mFoundResources = new HashMap<>(); + private OcResource mFoundLightResource = null; + //local representation of a server's light resource + private Light mLight = new Light(); + //variables related observer + private int maxSequenceNumber = 0xFFFFFF; + private OcConnectivityType adapterFlag = OcConnectivityType.CT_ADAPTER_IP; + //flags related TCP transport test + private boolean isRequestFlag = false; + private boolean isTCPContained = false; + + /** + * A local method to configure and initialize platform, and then search for the light resources. + */ + private void startSimpleClientBleScan(OcConnectivityType type, String device_addr) { + Context context = this; + adapterFlag = type; + + PlatformConfig platformConfig = new PlatformConfig( + this, + context, + ServiceType.IN_PROC, + ModeType.CLIENT, + "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces + 0, // Uses randomly available port + QualityOfService.LOW + ); + msg("Configuring platform."); + OcPlatform.Configure(platformConfig); + + try { + msg("Finding all resources of type \"core.light\"."); + msg("Setting Device address: " + device_addr); + String requestUri = OcPlatform.WELL_KNOWN_QUERY + "?rt=core.light"; + OcPlatform.findResource(device_addr, + requestUri, + EnumSet.of(OcConnectivityType.CT_ADAPTER_GATT_BTLE), + this + ); + sleep(1); + + /*Find resource is done twice so that we discover the original resources a second time. + These resources will have the same uniqueidentifier (yet be different objects), + so that we can verify/show the duplicate-checking code in foundResource(above); + */ + msg("Finding all resources of type \"core.light\" for the second time"); + OcPlatform.findResource(device_addr, + requestUri, + EnumSet.of(OcConnectivityType.CT_ADAPTER_GATT_BTLE), + this + ); + + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Failed to invoke find resource API"); + } + + printLine(); + } + + /** + * An event handler to be executed whenever a "findResource" request completes successfully + * + * @param ocResource found resource + */ + @Override + public synchronized void onResourceFound(OcResource ocResource) { + if (null == ocResource) { + msg("Found resource is invalid"); + return; + } + + if (mFoundResources.containsKey(ocResource.getUniqueIdentifier())) { + msg("Found a previously seen resource again!"); + } else { + msg("Found resource for the first time on server with ID: " + ocResource.getServerId()); + mFoundResources.put(ocResource.getUniqueIdentifier(), ocResource); + } + + if (null != mFoundLightResource) { + if (ocResource.getUri().equals("/a/light")) { + if (ocResource.getConnectivityTypeSet().contains(OcConnectivityType.CT_ADAPTER_TCP)) { + msg("Found resource which has TCP transport"); + if (isTCPContained == false) + { + isTCPContained = true; + return; + } + } + } + msg("Found another resource, ignoring"); + return; + + } + // Get the resource URI + String resourceUri = ocResource.getUri(); + // Get the resource host address + String hostAddress = ocResource.getHost(); + msg("\tURI of the resource: " + resourceUri); + msg("\tHost address of the resource: " + hostAddress); + // Get the resource types + msg("\tList of resource types: "); + for (String resourceType : ocResource.getResourceTypes()) { + msg("\t\t" + resourceType); + } + msg("\tList of resource interfaces:"); + for (String resourceInterface : ocResource.getResourceInterfaces()) { + msg("\t\t" + resourceInterface); + } + msg("\tList of resource connectivity types:"); + for (OcConnectivityType connectivityType : ocResource.getConnectivityTypeSet()) { + msg("\t\t" + connectivityType); + } + printLine(); + + //In this example we are only interested in the light resources + if (resourceUri.equals("/a/light")) { + //Assign resource reference to a global variable to keep it from being + //destroyed by the GC when it is out of scope. + if (OcConnectivityType.CT_ADAPTER_TCP == adapterFlag) + { + if (ocResource.getConnectivityTypeSet().contains(OcConnectivityType.CT_ADAPTER_TCP)) + { + msg("set mFoundLightResource which has TCP transport"); + mFoundLightResource = ocResource; + // Call a local method which will internally invoke "get" API + getLightResourceRepresentation(); + return; + } + } + else + { + msg("set mFoundLightResource which has UDP transport"); + mFoundLightResource = ocResource; + // Call a local method which will internally invoke "get" API on the foundLightResource + getLightResourceRepresentation(); + } + } + } + + @Override + public synchronized void onFindResourceFailed(Throwable throwable, String uri) { + msg("findResource request has failed"); + Log.e(TAG, throwable.toString()); + } + + /** + * Local method to get representation of a found light resource + */ + private void getLightResourceRepresentation() { + msg("Getting Light Representation..."); + + Map queryParams = new HashMap<>(); + try { + // Invoke resource's "get" API with a OcResource.OnGetListener event + // listener implementation + sleep(1); + mFoundLightResource.get(queryParams, this); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Error occurred while invoking \"get\" API"); + } + } + + /** + * An event handler to be executed whenever a "get" request completes successfully + * + * @param list list of the header options + * @param ocRepresentation representation of a resource + */ + @Override + public synchronized void onGetCompleted(List list, + OcRepresentation ocRepresentation) { + msg("GET request was successful"); + msg("Resource URI: " + ocRepresentation.getUri()); + + try { + //Read attribute values into local representation of a light + mLight.setOcRepresentation(ocRepresentation); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Failed to read the attributes of a light resource"); + } + msg("Light attributes: "); + msg(mLight.toString()); + printLine(); + + //Call a local method which will internally invoke put API on the foundLightResource + putLightRepresentation(); + } + + /** + * An event handler to be executed whenever a "get" request fails + * + * @param throwable exception + */ + @Override + public synchronized void onGetFailed(Throwable throwable) { + if (throwable instanceof OcException) { + OcException ocEx = (OcException) throwable; + Log.e(TAG, ocEx.toString()); + ErrorCode errCode = ocEx.getErrorCode(); + //do something based on errorCode + msg("Error code: " + errCode); + } + msg("Failed to get representation of a found light resource"); + } + + /** + * Local method to put a different state for this light resource + */ + private void putLightRepresentation() { + //set new values + mLight.setState(true); + mLight.setPower(15); + + msg("Putting light representation..."); + OcRepresentation representation = null; + try { + representation = mLight.getOcRepresentation(); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Failed to get OcRepresentation from a light"); + } + + Map queryParams = new HashMap<>(); + + try { + sleep(1); + // Invoke resource's "put" API with a new representation, query parameters and + // OcResource.OnPutListener event listener implementation + mFoundLightResource.put(representation, queryParams, this); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Error occurred while invoking \"put\" API"); + } + } + + /** + * An event handler to be executed whenever a "put" request completes successfully + * + * @param list list of the header options + * @param ocRepresentation representation of a resource + */ + @Override + public synchronized void onPutCompleted(List list, OcRepresentation ocRepresentation) { + msg("PUT request was successful"); + try { + mLight.setOcRepresentation(ocRepresentation); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Failed to create Light representation"); + } + msg("Light attributes: "); + msg(mLight.toString()); + printLine(); + + //Call a local method which will internally invoke post API on the foundLightResource + postLightRepresentation(); + } + + /** + * An event handler to be executed whenever a "put" request fails + * + * @param throwable exception + */ + @Override + public synchronized void onPutFailed(Throwable throwable) { + if (throwable instanceof OcException) { + OcException ocEx = (OcException) throwable; + Log.e(TAG, ocEx.toString()); + ErrorCode errCode = ocEx.getErrorCode(); + //do something based on errorCode + msg("Error code: " + errCode); + } + msg("Failed to \"put\" a new representation"); + } + + /** + * Local method to post a different state for this light resource + */ + private void postLightRepresentation() { + //set new values + mLight.setState(false); + mLight.setPower(105); + + msg("Posting light representation..."); + OcRepresentation representation = null; + try { + representation = mLight.getOcRepresentation(); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Failed to get OcRepresentation from a light"); + } + + Map queryParams = new HashMap<>(); + try { + sleep(1); + // Invoke resource's "post" API with a new representation, query parameters and + // OcResource.OnPostListener event listener implementation + mFoundLightResource.post(representation, queryParams, this); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Error occurred while invoking \"post\" API"); + } + } + + /** + * An event handler to be executed whenever a "post" request completes successfully + * + * @param list list of the header options + * @param ocRepresentation representation of a resource + */ + @Override + public synchronized void onPostCompleted(List list, + OcRepresentation ocRepresentation) { + msg("POST request was successful"); + try { + if (ocRepresentation.hasAttribute(OcResource.CREATED_URI_KEY)) { + msg("\tUri of the created resource: " + + ocRepresentation.getValue(OcResource.CREATED_URI_KEY)); + } else { + mLight.setOcRepresentation(ocRepresentation); + msg(mLight.toString()); + } + } catch (OcException e) { + Log.e(TAG, e.toString()); + } + + //setting new values + mLight.setState(true); + mLight.setPower(55); + msg("Posting again light representation..."); + OcRepresentation representation2 = null; + try { + representation2 = mLight.getOcRepresentation(); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Failed to get OcRepresentation from a light"); + } + + Map queryParams = new HashMap<>(); + try { + // Invoke resource's "post" API with a new representation, query parameters and + // OcResource.OnPostListener event listener implementation + mFoundLightResource.post(representation2, queryParams, onPostListener2); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Error occurred while invoking \"post\" API"); + } + } + + /** + * An event handler to be executed whenever a "post" request fails + * + * @param throwable exception + */ + @Override + public synchronized void onPostFailed(Throwable throwable) { + if (throwable instanceof OcException) { + OcException ocEx = (OcException) throwable; + Log.e(TAG, ocEx.toString()); + ErrorCode errCode = ocEx.getErrorCode(); + //do something based on errorCode + msg("Error code: " + errCode); + } + msg("Failed to \"post\" a new representation"); + } + + /** + * Declare and implement a second OcResource.OnPostListener + */ + OcResource.OnPostListener onPostListener2 = new OcResource.OnPostListener() { + /** + * An event handler to be executed whenever a "post" request completes successfully + * @param list list of the header options + * @param ocRepresentation representation of a resource + */ + @Override + public synchronized void onPostCompleted(List list, + OcRepresentation ocRepresentation) { + msg("Second POST request was successful"); + try { + if (ocRepresentation.hasAttribute(OcResource.CREATED_URI_KEY)) { + msg("\tUri of the created resource: " + + ocRepresentation.getValue(OcResource.CREATED_URI_KEY)); + } else { + mLight.setOcRepresentation(ocRepresentation); + msg(mLight.toString()); + } + } catch (OcException e) { + Log.e(TAG, e.toString()); + } + + //Call a local method which will internally invoke observe API on the foundLightResource + observeFoundLightResource(); + } + + /** + * An event handler to be executed whenever a "post" request fails + * + * @param throwable exception + */ + @Override + public synchronized void onPostFailed(Throwable throwable) { + if (throwable instanceof OcException) { + OcException ocEx = (OcException) throwable; + Log.e(TAG, ocEx.toString()); + ErrorCode errCode = ocEx.getErrorCode(); + //do something based on errorCode + msg("Error code: " + errCode); + } + msg("Failed to \"post\" a new representation"); + } + }; + + /** + * Local method to start observing this light resource + */ + private void observeFoundLightResource() { + try { + sleep(1); + // Invoke resource's "observe" API with a observe type, query parameters and + // OcResource.OnObserveListener event listener implementation + mFoundLightResource.observe(ObserveType.OBSERVE, new HashMap(), this); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Error occurred while invoking \"observe\" API"); + } + } + + // holds current number of observations + private static int mObserveCount = 0; + + /** + * An event handler to be executed whenever a "post" request completes successfully + * + * @param list list of the header options + * @param ocRepresentation representation of a resource + * @param sequenceNumber sequence number + */ + @Override + public synchronized void onObserveCompleted(List list, + OcRepresentation ocRepresentation, + int sequenceNumber) { + + if (sequenceNumber != maxSequenceNumber + 1) + { + msg("OBSERVE Result:"); + msg("\tSequenceNumber:" + sequenceNumber); + try { + mLight.setOcRepresentation(ocRepresentation); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Failed to get the attribute values"); + } + msg(mLight.toString()); + + if ((++mObserveCount) == 11) { + msg("Cancelling Observe..."); + try { + mFoundLightResource.cancelObserve(QualityOfService.HIGH); + } catch (OcException e) { + Log.e(TAG, e.toString()); + msg("Error occurred while invoking \"cancelObserve\" API"); + } + + sleep(10); + resetGlobals(); + if (true == isTCPContained && false == isRequestFlag) + { + msg("Start TCP test..."); + //startSimpleClientBleScan(OcConnectivityType.CT_ADAPTER_TCP); + isRequestFlag = true; + return; + } else if (true == isRequestFlag) + { + msg("End TCP test..."); + isRequestFlag = false; + } + + msg("DONE"); + //prepare for the next restart of the SimpleClientBleScan + //enableStartButton(); + } + } + } + + /** + * An event handler to be executed whenever a "observe" request fails + * + * @param throwable exception + */ + @Override + public synchronized void onObserveFailed(Throwable throwable) { + if (throwable instanceof OcException) { + OcException ocEx = (OcException) throwable; + Log.e(TAG, ocEx.toString()); + ErrorCode errCode = ocEx.getErrorCode(); + //do something based on errorCode + msg("Error code: " + errCode); + } + msg("Observation of the found light resource has failed"); + } + + //****************************************************************************** + // End of the OIC specific code + //****************************************************************************** + + private final static String TAG = SimpleClientBleScan.class.getSimpleName(); + private TextView mConsoleTextView; + private ScrollView mScrollView; + private ArrayAdapter mNewDevicesArrayAdapter; + + private BluetoothLeScanner mBluetoothLeScanner; + private Handler mHandler = new Handler(); + + private ScanCallback mScanCallback = new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + Log.d(TAG, "Scan callback called"); + super.onScanResult(callbackType, result); + if( result == null + || result.getDevice() == null) + { + return; + } + + StringBuilder builder = new StringBuilder( result.getDevice().getAddress()); + + mNewDevicesArrayAdapter.add(result.getDevice().getName() + "\n" + result.getDevice().getAddress()); + Log.d(TAG, builder.toString()); + } + + @Override + public void onBatchScanResults(List results) { + msg("Batch Scan callback called"); + super.onBatchScanResults(results); + } + + @Override + public void onScanFailed(int errorCode) { + msg("Scan Failed !"); + Log.e(TAG, "Discovery onScanFailed: " + errorCode ); + super.onScanFailed(errorCode); + } + }; + + private void discover() { + msg("Discovery started"); + Log.i(TAG, "Discover called"); + List filters = new ArrayList(); + ScanFilter filter = new ScanFilter.Builder().setServiceUuid(new ParcelUuid(UUID.fromString("ADE3D529-C784-4F63-A987-EB69F70EE816"))).build(); + filters.add(filter); + + ScanSettings settings = new ScanSettings.Builder() + .setScanMode( ScanSettings.SCAN_MODE_BALANCED) + .build(); + + mBluetoothLeScanner.startScan(mScanCallback); + + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mBluetoothLeScanner.stopScan(mScanCallback); + msg("Scan Stopped"); + Log.d(TAG, "Scan Stopped"); + } + }, 10000); + } + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_simple_client); + + mConsoleTextView = (TextView) findViewById(R.id.consoleTextView); + mConsoleTextView.setMovementMethod(new ScrollingMovementMethod()); + mScrollView = (ScrollView) findViewById(R.id.scrollView); + mScrollView.fullScroll(View.FOCUS_DOWN); + final Button scan_button = (Button) findViewById(R.id.scan_button); + mNewDevicesArrayAdapter = new ArrayAdapter(this, R.layout.device_name); + + final ListView newDevicesListView = (ListView) findViewById(R.id.new_devices); + newDevicesListView.setAdapter(mNewDevicesArrayAdapter); + + mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner(); + + if (null == savedInstanceState) { + scan_button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + scan_button.setText("Scan Started"); + scan_button.setEnabled(false); + new Thread(new Runnable() { + public void run() { + discover(); + } + }).start(); + } + }); + + newDevicesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + String value = newDevicesListView.getItemAtPosition(position).toString(); + String lines[] = value.split("\\r?\\n"); + startSimpleClientBleScan(OcConnectivityType.CT_ADAPTER_IP, lines[1]); + } + }); + } else { + String consoleOutput = savedInstanceState.getString("consoleOutputString"); + mConsoleTextView.setText(consoleOutput); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("consoleOutputString", mConsoleTextView.getText().toString()); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + String consoleOutput = savedInstanceState.getString("consoleOutputString"); + mConsoleTextView.setText(consoleOutput); + } + + private void sleep(int seconds) { + try { + Thread.sleep(seconds * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + Log.e(TAG, e.toString()); + } + } + + private void msg(final String text) { + runOnUiThread(new Runnable() { + public void run() { + mConsoleTextView.append("\n"); + mConsoleTextView.append(text); + mScrollView.fullScroll(View.FOCUS_DOWN); + } + }); + Log.i(TAG, text); + } + + private void printLine() { + msg("------------------------------------------------------------------------"); + } + + private synchronized void resetGlobals() { + mFoundLightResource = null; + mFoundResources.clear(); + mLight = new Light(); + mObserveCount = 0; + } + + @Override + public void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Log.d(TAG, "onNewIntent with changes sending broadcast IN "); + + Intent i = new Intent(); + i.setAction(intent.getAction()); + i.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, + intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)); + sendBroadcast(i); + Log.d(TAG, "Initialize Context again resetting"); + } + +} diff --git a/android/examples/simpleclientblescan/src/main/res/drawable/iotivityicon.png b/android/examples/simpleclientblescan/src/main/res/drawable/iotivityicon.png new file mode 100644 index 0000000..e1e4aa7 Binary files /dev/null and b/android/examples/simpleclientblescan/src/main/res/drawable/iotivityicon.png differ diff --git a/android/examples/simpleclientblescan/src/main/res/drawable/iotivitylogo.png b/android/examples/simpleclientblescan/src/main/res/drawable/iotivitylogo.png new file mode 100644 index 0000000..a7d3115 Binary files /dev/null and b/android/examples/simpleclientblescan/src/main/res/drawable/iotivitylogo.png differ diff --git a/android/examples/simpleclientblescan/src/main/res/layout/activity_simple_client.xml b/android/examples/simpleclientblescan/src/main/res/layout/activity_simple_client.xml new file mode 100644 index 0000000..ae38278 --- /dev/null +++ b/android/examples/simpleclientblescan/src/main/res/layout/activity_simple_client.xml @@ -0,0 +1,64 @@ + + +