From 00d64b4824a41d645a6b514f0f645c7e9ad665ff Mon Sep 17 00:00:00 2001 From: Martin Mauch Date: Mon, 28 Jan 2019 13:11:06 +0100 Subject: [PATCH] Add RxAndroid extensions --- .../de/fau/sensorlibtest/RxMainActivity.java | 184 ++++++++++++++++++ SensorLib/rxsensorlib/.gitignore | 1 + SensorLib/rxsensorlib/build.gradle | 41 ++++ SensorLib/rxsensorlib/proguard-rules.pro | 21 ++ .../sensorlib/rx/ExampleInstrumentedTest.java | 28 +++ .../rxsensorlib/src/main/AndroidManifest.xml | 2 + .../sensorlib/rx/RxSensorDataProcessor.java | 123 ++++++++++++ .../src/main/res/values/strings.xml | 3 + .../de/fau/sensorlib/rx/ExampleUnitTest.java | 19 ++ SensorLib/settings.gradle | 2 +- 10 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 SensorLib/app/src/main/java/de/fau/sensorlibtest/RxMainActivity.java create mode 100644 SensorLib/rxsensorlib/.gitignore create mode 100644 SensorLib/rxsensorlib/build.gradle create mode 100644 SensorLib/rxsensorlib/proguard-rules.pro create mode 100644 SensorLib/rxsensorlib/src/androidTest/java/de/fau/sensorlib/rx/ExampleInstrumentedTest.java create mode 100644 SensorLib/rxsensorlib/src/main/AndroidManifest.xml create mode 100644 SensorLib/rxsensorlib/src/main/java/de/fau/sensorlib/rx/RxSensorDataProcessor.java create mode 100644 SensorLib/rxsensorlib/src/main/res/values/strings.xml create mode 100644 SensorLib/rxsensorlib/src/test/java/de/fau/sensorlib/rx/ExampleUnitTest.java diff --git a/SensorLib/app/src/main/java/de/fau/sensorlibtest/RxMainActivity.java b/SensorLib/app/src/main/java/de/fau/sensorlibtest/RxMainActivity.java new file mode 100644 index 00000000..0da26ecd --- /dev/null +++ b/SensorLib/app/src/main/java/de/fau/sensorlibtest/RxMainActivity.java @@ -0,0 +1,184 @@ +/** + * Copyright (C) 2015-2016 Digital Sports Group, Friedrich-Alexander University Erlangen-Nuremberg (FAU). + *

+ * This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. If you reuse + * this code you have to keep or cite this comment. + */ +package de.fau.sensorlibtest; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.graphics.Color; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; + +import com.androidplot.xy.LineAndPointFormatter; +import com.androidplot.xy.PointLabelFormatter; +import com.androidplot.xy.SimpleXYSeries; +import com.androidplot.xy.XYPlot; + +import java.util.List; + +import de.fau.sensorlib.BleSensorManager; +import de.fau.sensorlib.SensorDataProcessor; +import de.fau.sensorlib.SensorFoundCallback; +import de.fau.sensorlib.SensorInfo; +import de.fau.sensorlib.dataframe.AccelDataFrame; +import de.fau.sensorlib.dataframe.AmbientDataFrame; +import de.fau.sensorlib.dataframe.SensorDataFrame; +import de.fau.sensorlib.enums.HardwareSensor; +import de.fau.sensorlib.enums.KnownSensor; +import de.fau.sensorlib.rx.RxSensorDataProcessor; +import de.fau.sensorlib.sensors.GenericBleSensor; +import de.fau.sensorlib.sensors.TekSensor; +import io.reactivex.functions.Consumer; + +/** + * A simple example application to demonstrate the use of the SensorLib. + */ +public class RxMainActivity extends AppCompatActivity +{ + + private static final String TAG = "SensorLib::TestApp"; + + GenericBleSensor mSensor; + + XYPlot mPlot; + SimpleXYSeries mPlotData; + + @SuppressLint("CheckResult") + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + try + { + BleSensorManager.checkBtLePermissions(this, true); + } catch (Exception e) + { + // TODO Really handle exception + e.printStackTrace(); + } + + mPlot = (XYPlot) findViewById(R.id.plotViewA); + mPlotData = new SimpleXYSeries("Sensor Values"); + mPlotData.useImplicitXVals(); + mPlot.addSeries(mPlotData, new LineAndPointFormatter(Color.rgb(100, 100, 200), null, null, new PointLabelFormatter(Color.DKGRAY))); + mPlot.setDomainLabel("Sample Index"); + mPlot.setRangeLabel("Value"); + mDataHandler.getNewDataObservable().forEach( + new Consumer() + { + @Override + public void accept(SensorDataFrame data) + { + + if (mPlotData.size() > 99) + { + mPlotData.removeFirst(); + } + + if (data instanceof AccelDataFrame) + { + AccelDataFrame adf = (AccelDataFrame) data; + mPlotData.addLast(null, adf.getAccelX()); + } + if (data instanceof AmbientDataFrame) + { + AmbientDataFrame adf = (AmbientDataFrame) data; + mPlotData.addLast(null, adf.getLight()); + } + + TekSensor.TekDataFrame df = (TekSensor.TekDataFrame) data; + Log.d(TAG, "DataFrame (" + df.getCounter() + "): " + df.toString()); + + // redraw the Plots: + mPlot.redraw(); + } + } + ); + } + + RxSensorDataProcessor mDataHandler = new RxSensorDataProcessor(); + + Activity getThis() + { + return this; + } + + @Override + protected void onResume() + { + super.onResume(); + + /*String tekMac = "52:4D:4B:5F:01:55"; + mSensor = new TekSensor(this, tekMac, mDataHandler); + mSensor.useHardwareSensor(HardwareSensor.ACCELEROMETER); + mSensor.useHardwareSensor(HardwareSensor.LIGHT); + try { + mSensor.connect(); + mSensor.startStreaming(); + } catch (Exception e) { + e.printStackTrace(); + }*/ + + + List list = BleSensorManager.getConnectableSensors(); + for (SensorInfo s : list) + { + Log.d(TAG, "Sensor found: " + s.getName()); + } + + try + { + BleSensorManager.searchBleDevices(new SensorFoundCallback() + { + public boolean onKnownSensorFound(SensorInfo sensor) + { + Log.d(TAG, "BLE Sensor found: " + sensor.getName()); + + // we check what kind of sensor we found + if (sensor.getDeviceClass() == KnownSensor.GENERIC_BLE) + { + // ignore default/unknown BLE sensors + //if (sensor.getDeviceName().contains("miCoach")) { + + } else if (sensor.getDeviceClass() == KnownSensor.TEK) + { + // this is a TEK sensor, create and connect it. + mSensor = new TekSensor(getThis(), sensor, mDataHandler); + mSensor.useHardwareSensor(HardwareSensor.ACCELEROMETER); + mSensor.useHardwareSensor(HardwareSensor.LIGHT); + try + { + mSensor.connect(); + mSensor.startStreaming(); + } catch (Exception e) + { + e.printStackTrace(); + } + return false; + } + return true; + } + }); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + @Override + protected void onPause() + { + if (mSensor != null) + { + mSensor.disconnect(); + } + super.onPause(); + } +} diff --git a/SensorLib/rxsensorlib/.gitignore b/SensorLib/rxsensorlib/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/SensorLib/rxsensorlib/.gitignore @@ -0,0 +1 @@ +/build diff --git a/SensorLib/rxsensorlib/build.gradle b/SensorLib/rxsensorlib/build.gradle new file mode 100644 index 00000000..95cba9b2 --- /dev/null +++ b/SensorLib/rxsensorlib/build.gradle @@ -0,0 +1,41 @@ +apply plugin: 'com.android.library' +apply plugin: 'com.github.dcendents.android-maven' + +group='com.github.gradlman.SensorLib' +version = '1.0' + +android { + compileSdkVersion 27 + + + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + api 'io.reactivex.rxjava2:rxandroid:2.1.0' + api 'io.reactivex.rxjava2:rxjava:2.2.6' + implementation 'com.android.support:appcompat-v7:27.1.1' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + api project(path: ':sensorlib') +} diff --git a/SensorLib/rxsensorlib/proguard-rules.pro b/SensorLib/rxsensorlib/proguard-rules.pro new file mode 100644 index 00000000..f1b42451 --- /dev/null +++ b/SensorLib/rxsensorlib/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/SensorLib/rxsensorlib/src/androidTest/java/de/fau/sensorlib/rx/ExampleInstrumentedTest.java b/SensorLib/rxsensorlib/src/androidTest/java/de/fau/sensorlib/rx/ExampleInstrumentedTest.java new file mode 100644 index 00000000..2568659f --- /dev/null +++ b/SensorLib/rxsensorlib/src/androidTest/java/de/fau/sensorlib/rx/ExampleInstrumentedTest.java @@ -0,0 +1,28 @@ +package de.fau.sensorlib.rx; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest +{ + @Test + public void useAppContext() + { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("de.fau.sensorlib.rx.test", appContext.getPackageName()); + } +} diff --git a/SensorLib/rxsensorlib/src/main/AndroidManifest.xml b/SensorLib/rxsensorlib/src/main/AndroidManifest.xml new file mode 100644 index 00000000..b805ad33 --- /dev/null +++ b/SensorLib/rxsensorlib/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/SensorLib/rxsensorlib/src/main/java/de/fau/sensorlib/rx/RxSensorDataProcessor.java b/SensorLib/rxsensorlib/src/main/java/de/fau/sensorlib/rx/RxSensorDataProcessor.java new file mode 100644 index 00000000..e3ca9df4 --- /dev/null +++ b/SensorLib/rxsensorlib/src/main/java/de/fau/sensorlib/rx/RxSensorDataProcessor.java @@ -0,0 +1,123 @@ +package de.fau.sensorlib.rx; + +import de.fau.sensorlib.SensorDataProcessor; +import de.fau.sensorlib.dataframe.SensorDataFrame; +import de.fau.sensorlib.sensors.AbstractSensor; +import io.reactivex.Observable; +import io.reactivex.subjects.PublishSubject; + +public class RxSensorDataProcessor extends SensorDataProcessor +{ + + public enum SensorState + { + CREATED, CONNECTING, CONNECTED, DISCONNECTED, CONNECTION_LOST, STREAMING_STARTED, STREAMING_STOPPED + } + + public static class SensorNotification + { + private final AbstractSensor sensor; + private final T notification; + + public SensorNotification(AbstractSensor sensor, T notification) + { + this.sensor = sensor; + this.notification = notification; + } + + public AbstractSensor getSensor() + { + return sensor; + } + + public T getNotification() + { + return notification; + } + } + + private PublishSubject> sensorStateSubject = PublishSubject.create(); + private PublishSubject> sensorSamplingRateSubject = PublishSubject.create(); + private PublishSubject> sensorNotificationSubject = PublishSubject.create(); + private PublishSubject newDataSubject = PublishSubject.create(); + + + @Override + public void onSensorCreated(AbstractSensor sensor) + { + sensorStateSubject.onNext(new SensorNotification(sensor, SensorState.CREATED)); + } + + @Override + public void onConnected(AbstractSensor sensor) + { + sensorStateSubject.onNext(new SensorNotification(sensor, SensorState.CONNECTED)); + } + + @Override + public void onConnecting(AbstractSensor sensor) + { + sensorStateSubject.onNext(new SensorNotification(sensor, SensorState.CONNECTING)); + } + + @Override + public void onDisconnected(AbstractSensor sensor) + { + sensorStateSubject.onNext(new SensorNotification(sensor, SensorState.DISCONNECTED)); + } + + @Override + public void onConnectionLost(AbstractSensor sensor) + { + sensorStateSubject.onNext(new SensorNotification(sensor, SensorState.CONNECTION_LOST)); + } + + @Override + public void onStartStreaming(AbstractSensor sensor) + { + sensorStateSubject.onNext(new SensorNotification(sensor, SensorState.STREAMING_STARTED)); + } + + @Override + public void onStopStreaming(AbstractSensor sensor) + { + sensorStateSubject.onNext(new SensorNotification(sensor, SensorState.STREAMING_STOPPED)); + } + + @Override + public void onSamplingRateChanged(AbstractSensor sensor, double newSamplingRate) + { + sensorSamplingRateSubject.onNext(new SensorNotification(sensor, newSamplingRate)); + } + + @Override + public void onNotify(AbstractSensor sensor, Object notification) + { + sensorNotificationSubject.onNext(new SensorNotification(sensor, notification)); + } + + @Override + public void onNewData(SensorDataFrame data) + { + newDataSubject.onNext(data); + } + + public Observable> getSensorStateObservable() + { + return sensorStateSubject; + } + + public Observable> getSensorSamplingRateObservable() + { + return sensorSamplingRateSubject; + } + + public Observable> getSensorNotificationObservable() + { + return sensorNotificationSubject; + } + + public Observable getNewDataObservable() { + return (Observable) newDataSubject; + } +} diff --git a/SensorLib/rxsensorlib/src/main/res/values/strings.xml b/SensorLib/rxsensorlib/src/main/res/values/strings.xml new file mode 100644 index 00000000..1e7011e0 --- /dev/null +++ b/SensorLib/rxsensorlib/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + RxSensorLib + diff --git a/SensorLib/rxsensorlib/src/test/java/de/fau/sensorlib/rx/ExampleUnitTest.java b/SensorLib/rxsensorlib/src/test/java/de/fau/sensorlib/rx/ExampleUnitTest.java new file mode 100644 index 00000000..bc138e39 --- /dev/null +++ b/SensorLib/rxsensorlib/src/test/java/de/fau/sensorlib/rx/ExampleUnitTest.java @@ -0,0 +1,19 @@ +package de.fau.sensorlib.rx; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest +{ + @Test + public void addition_isCorrect() + { + assertEquals(4, 2 + 2); + } +} diff --git a/SensorLib/settings.gradle b/SensorLib/settings.gradle index 7d3bf12b..e8f1e9ba 100644 --- a/SensorLib/settings.gradle +++ b/SensorLib/settings.gradle @@ -1,4 +1,4 @@ -include ':sensorlibutils', ':sensorlib', ':sls-tek', ':sls-fitnessshirt', ':sls-shimmer', ':sls-smartwatch', ':sls-simblee', ':sls-smartband2', ':sls-bitalino', ':sls-portabiles' +include ':sensorlibutils', ':sensorlib', ':sls-tek', ':sls-fitnessshirt', ':sls-shimmer', ':sls-smartwatch', ':sls-simblee', ':sls-smartband2', ':sls-bitalino', ':sls-portabiles', ':rxsensorlib' if (!fileTree(dir: 'sls-empatica/libs', include: 'empalink*.aar').isEmpty()) { include ':sls-empatica' }