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..3160a4e9
--- /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 androidx.appcompat.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/build.gradle b/SensorLib/build.gradle
index 7f4d55e7..179c1744 100644
--- a/SensorLib/build.gradle
+++ b/SensorLib/build.gradle
@@ -6,7 +6,7 @@ buildscript {
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.3.0'
+ classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
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..5667010f
--- /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 "androidx.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 'androidx.appcompat:appcompat:1.0.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.1.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
+ 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..840d227c
--- /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 androidx.test.InstrumentationRegistry;
+import androidx.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