diff --git a/.gitignore b/.gitignore index 39fb081a42a86ccf8f9cf99dbccc8bdf7c828bce..8f91cf5abd77cade2fc4eb3afdbec4d51127a988 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /local.properties /.idea/workspace.xml /.idea/libraries +/.idea/caches .DS_Store /build /captures diff --git a/.idea/gradle.xml b/.idea/gradle.xml index a222710944c3e3cea29acf6bb51a30f68f1c63d3..16fa2b3c5d53cf4c6c7bec6efafab8e2c72ad41f 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -8,6 +8,7 @@ <option name="modules"> <set> <option value="$PROJECT_DIR$" /> + <option value="$PROJECT_DIR$/common" /> <option value="$PROJECT_DIR$/mobile" /> <option value="$PROJECT_DIR$/wear" /> </set> diff --git a/.idea/misc.xml b/.idea/misc.xml index 39638799269d0193201b39e5276d8236659f97fe..75dac502959ec4f6e5232282499067f85aa716f5 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -24,7 +24,7 @@ </value> </option> </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <output url="file://$PROJECT_DIR$/build/classes" /> </component> <component name="ProjectType"> diff --git a/.idea/modules.xml b/.idea/modules.xml index 9fda6ea429bd6a9ab717a9db9f33c1082935fcf1..dd960f626537f5b1241cfced3d78b39a9b011bea 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,6 +3,7 @@ <component name="ProjectModuleManager"> <modules> <module fileurl="file://$PROJECT_DIR$/SensorSharing.iml" filepath="$PROJECT_DIR$/SensorSharing.iml" /> + <module fileurl="file://$PROJECT_DIR$/common/common.iml" filepath="$PROJECT_DIR$/common/common.iml" /> <module fileurl="file://$PROJECT_DIR$/mobile/mobile.iml" filepath="$PROJECT_DIR$/mobile/mobile.iml" /> <module fileurl="file://$PROJECT_DIR$/wear/wear.iml" filepath="$PROJECT_DIR$/wear/wear.iml" /> </modules> diff --git a/common/.gitignore b/common/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9 --- /dev/null +++ b/common/.gitignore @@ -0,0 +1 @@ +/build diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..8e95a6bf671e9eef5dc252ba417278bf1aa0e0e4 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 26 + + + + defaultConfig { + minSdkVersion 24 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'com.android.support:appcompat-v7:26.1.0' + 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' +} diff --git a/common/proguard-rules.pro b/common/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..f1b424510da51fd82143bc74a0a801ae5a1e2fcd --- /dev/null +++ b/common/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/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6c2827bfabd31dfdb9e5dccdb4fedbf371ef5ce --- /dev/null +++ b/common/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="de.tudresden.inf.st.sensorsharing.common" /> diff --git a/common/src/main/java/de/tudresden/inf/st/sensorsharing/common/Constants.java b/common/src/main/java/de/tudresden/inf/st/sensorsharing/common/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..6387ae001403b0b9d9dfb4e850050ab9a5151f32 --- /dev/null +++ b/common/src/main/java/de/tudresden/inf/st/sensorsharing/common/Constants.java @@ -0,0 +1,14 @@ +package de.tudresden.inf.st.sensorsharing.common; + +public class Constants { + + public static final String BASE_KEY = "/wearable/sensors/"; + public static final int BASE_KEY_LENGTH = BASE_KEY.length(); + public static final String SUB_KEY_BRIGHTNESS = "brightness"; + public static final String KEY_BRIGHTNESS = BASE_KEY + SUB_KEY_BRIGHTNESS; + public static final String SUB_KEY_LINEAR_ACCELERATION = "acceleration"; + public static final String KEY_LINEAR_ACCELERATION = BASE_KEY + SUB_KEY_LINEAR_ACCELERATION; + public static final String SUB_KEY_ROTATION_VECTOR = "rotation"; + public static final String KEY_ROTATION_VECTOR = BASE_KEY + SUB_KEY_ROTATION_VECTOR; + +} diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..7a37b56a6fd804a782d862f76d0e1834a0cbd15c --- /dev/null +++ b/common/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="app_name">sensorsharing.common</string> +</resources> diff --git a/gradlew.bat b/gradlew.bat index 8a0b282aa6885fb573c106b3551f7275c5f17e8e..aec99730b4e8fcd90b57a0e8e01544fea7c31a89 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/mobile/build.gradle b/mobile/build.gradle index ce3d9a77ad537af575dae3195228686c3f7bc2f1..7f69ade1beed0a3c67099189c0a053a86d0bf33d 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -23,6 +23,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.0' + implementation project(':common') + // jUnit testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' diff --git a/mobile/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java b/mobile/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java index 7dea7bf3da9849fcc0ca467259cc3465857491f3..ff668a9ac5a53c47717976c73435da8069233b4d 100644 --- a/mobile/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java +++ b/mobile/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java @@ -31,30 +31,40 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.util.Arrays; + +import static de.tudresden.inf.st.sensorsharing.common.Constants.BASE_KEY; +import static de.tudresden.inf.st.sensorsharing.common.Constants.BASE_KEY_LENGTH; +import static de.tudresden.inf.st.sensorsharing.common.Constants.SUB_KEY_BRIGHTNESS; +import static de.tudresden.inf.st.sensorsharing.common.Constants.SUB_KEY_LINEAR_ACCELERATION; +import static de.tudresden.inf.st.sensorsharing.common.Constants.SUB_KEY_ROTATION_VECTOR; public class MainActivity extends AppCompatActivity implements SensorEventListener, MessageClient.OnMessageReceivedListener { private static final String TAG = "SensorSharing"; - private static final String WEAR_SENSORS = "/wearable/sensors"; - private static final String KEY_BRIGHTNESS = "brightness"; - private static final String MQTT_TOPIC_POLAR = "sensors/polar/brightness"; + private static final String MQTT_TOPIC_POLAR_BASE = "sensors/polar/"; + private static final String MQTT_TOPIC_POLAR_BRIGHTNESS = MQTT_TOPIC_POLAR_BASE + "brightness"; + private static final String MQTT_TOPIC_POLAR_ACCELERATION = MQTT_TOPIC_POLAR_BASE + "acceleration"; + private static final String MQTT_TOPIC_POLAR_ROTATION = MQTT_TOPIC_POLAR_BASE + "rotation"; private static final String MQTT_TOPIC_SAMSUNG = "sensors/samsung/brightness"; private static final int MQTT_DEFAULT_QOS = 0; private static final Charset MQTT_CHARSET = Charset.forName("UTF-8"); private SensorManager mSensorManager; private Sensor mLight; - private float mWearBrightness = -1f; private TextView mValueWearBrightness; private MqttAndroidClient mqttAndroidClient; + private int counter = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + System.setProperty("log.tag." + TAG, "INFO"); + // setup sensor manager and light sensor mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (mSensorManager == null) { @@ -112,12 +122,12 @@ public class MainActivity extends AppCompatActivity implements IMqttToken token = mqttAndroidClient.connect(options, null, new IMqttActionListener() { @Override public void onSuccess(IMqttToken asyncActionToken) { - Log.i(TAG, "Connected to " + serverURI); + Log.i(TAG, "Successfully connected to " + serverURI); } @Override public void onFailure(IMqttToken asyncActionToken, Throwable exception) { - Log.e(TAG, "Connection to " + serverURI + " failed"); + Log.e(TAG, "Connection to " + serverURI + " failed", exception); } }); @@ -138,7 +148,11 @@ public class MainActivity extends AppCompatActivity implements String stringValue = String.valueOf(lightValue); TextView textView = findViewById(R.id.value_own_brightness); textView.setText(stringValue); - sendUpdateOfSmartphone(stringValue); + if (++counter >= 5) { + // only send every 5th change + counter = 0; + sendUpdateOfSmartphone(stringValue); + } } @Override @@ -162,23 +176,57 @@ public class MainActivity extends AppCompatActivity implements @Override public void onMessageReceived(@NonNull MessageEvent messageEvent) { - if (WEAR_SENSORS.equals(messageEvent.getPath())) { - // TODO how do we know, whether this is brightness value or not? - mWearBrightness = ByteBuffer.wrap(messageEvent.getData()).getFloat(); - final String stringValue = Float.toString(mWearBrightness); + String path = messageEvent.getPath(); + if (path == null) return; + if (path.startsWith(BASE_KEY)) { + final String updatedValue; + String topic; + final TextView textViewToUpdate; + + switch (path.substring(BASE_KEY_LENGTH)) { + case SUB_KEY_BRIGHTNESS: + float mWearBrightness = ByteBuffer.wrap(messageEvent.getData()).getFloat(); + updatedValue = Float.toString(mWearBrightness); + textViewToUpdate = mValueWearBrightness; + topic = MQTT_TOPIC_POLAR_BRIGHTNESS; + break; + case SUB_KEY_LINEAR_ACCELERATION: + float[] accelerationData = new float[3]; + writeFloatArray(ByteBuffer.wrap(messageEvent.getData()), accelerationData); + updatedValue = Arrays.toString(accelerationData); + textViewToUpdate = findViewById(R.id.value_wear_acceleration); + topic = MQTT_TOPIC_POLAR_ACCELERATION; + break; + case SUB_KEY_ROTATION_VECTOR: + float[] rotationData = new float[3]; + writeFloatArray(ByteBuffer.wrap(messageEvent.getData()), rotationData); + updatedValue = Arrays.toString(rotationData); + textViewToUpdate = findViewById(R.id.value_wear_rotation); + topic = MQTT_TOPIC_POLAR_ROTATION; + break; + default: + throw new IllegalArgumentException("Unknown path: " + path); + } runOnUiThread(new Runnable() { @Override public void run() { setChecked(true); - mValueWearBrightness.setText(stringValue); + textViewToUpdate.setText(updatedValue); + } }); - sendUpdateOfWearable(stringValue); + sendUpdateOfWearable(topic, updatedValue); + } + } + + private void writeFloatArray(ByteBuffer input, float[] output) { + for (int i = 0; i < output.length; i++) { + output[i] = input.getFloat(); } } - private void sendUpdateOfWearable(String newValue) { - sendUpdate(MQTT_TOPIC_POLAR, newValue); + private void sendUpdateOfWearable(String topic, String newValue) { + sendUpdate(topic, newValue); } private void sendUpdateOfSmartphone(String newValue) { @@ -191,7 +239,7 @@ public class MainActivity extends AppCompatActivity implements return; } if (!mqttAndroidClient.isConnected()) { - Log.d(TAG, "mqtt client not connected"); +// Log.v(TAG, "mqtt client not connected"); return; } // send to MQTT diff --git a/mobile/src/main/res/layout/activity_main.xml b/mobile/src/main/res/layout/activity_main.xml index b6225fade947925920c954d7fcfdc53bd8daf48e..5a1653cb16917c87d0540c8c74d5ee4b9e3ea90b 100644 --- a/mobile/src/main/res/layout/activity_main.xml +++ b/mobile/src/main/res/layout/activity_main.xml @@ -6,26 +6,66 @@ android:layout_height="match_parent" tools:context="de.tudresden.inf.st.sensorsharing.MainActivity"> + <TextView + android:id="@+id/separator_own" + style="?android:attr/listSeparatorTextViewStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:background="@android:color/darker_gray" + android:text="@string/text_separator_smartphone_values" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/separator_wear" + style="?android:attr/listSeparatorTextViewStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:background="@android:color/darker_gray" + android:text="@string/text_separator_wear_values" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/label_own_brightness" /> + + <TextView + android:id="@+id/separator_mqtt" + style="?android:attr/listSeparatorTextViewStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:background="@android:color/darker_gray" + android:text="@string/text_separator_mqtt_settings" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/label_wear_rotation" /> + <TextView android:id="@+id/label_server_uri" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="16dp" + android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="@string/text_mqtt_server_uri" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/checkBox" /> + app:layout_constraintTop_toBottomOf="@+id/separator_mqtt" /> <TextView android:id="@+id/label_own_brightness" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="16dp" - android:layout_marginTop="16dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" android:text="@string/text_own_brightness" app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/separator_own" /> <TextView android:id="@+id/label_wear_brightness" @@ -35,17 +75,37 @@ android:layout_marginTop="8dp" android:text="@string/text_wear_brightness" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/label_own_brightness" /> + app:layout_constraintTop_toBottomOf="@+id/checkBox" /> + + <TextView + android:id="@+id/label_wear_acceleration" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:text="@string/text_wear_acceleration" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/label_wear_brightness" /> + + <TextView + android:id="@+id/label_wear_rotation" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:text="@string/text_wear_rotation" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/label_wear_acceleration" /> <TextView android:id="@+id/value_own_brightness" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginTop="16dp" + android:layout_marginStart="12dp" + android:layout_marginTop="8dp" android:text="@android:string/unknownName" app:layout_constraintStart_toEndOf="@+id/label_own_brightness" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/separator_own" /> <TextView android:id="@+id/value_wear_brightness" @@ -55,7 +115,27 @@ android:layout_marginTop="8dp" android:text="@android:string/unknownName" app:layout_constraintStart_toEndOf="@+id/label_wear_brightness" - app:layout_constraintTop_toBottomOf="@+id/value_own_brightness" /> + app:layout_constraintTop_toBottomOf="@+id/checkBox" /> + + <TextView + android:id="@+id/value_wear_acceleration" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:text="@android:string/unknownName" + app:layout_constraintStart_toEndOf="@+id/label_wear_acceleration" + app:layout_constraintTop_toBottomOf="@+id/label_wear_brightness" /> + + <TextView + android:id="@+id/value_wear_rotation" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:text="@android:string/unknownName" + app:layout_constraintStart_toEndOf="@+id/label_wear_rotation" + app:layout_constraintTop_toBottomOf="@+id/label_wear_acceleration" /> <CheckBox android:id="@+id/checkBox" @@ -68,7 +148,7 @@ android:duplicateParentState="false" android:text="@string/text_connected" app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintTop_toBottomOf="@+id/label_wear_brightness" /> + app:layout_constraintTop_toBottomOf="@+id/separator_wear" /> <EditText android:id="@+id/value_server_uri" @@ -77,10 +157,10 @@ android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:ems="10" - android:inputType="text" + android:inputType="text|textUri" android:text="@string/default_mqtt_server_uri" app:layout_constraintStart_toEndOf="@+id/label_server_uri" - app:layout_constraintTop_toBottomOf="@+id/checkBox" /> + app:layout_constraintTop_toBottomOf="@+id/separator_mqtt" /> <Button android:id="@+id/button" @@ -93,6 +173,6 @@ android:text="@android:string/ok" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/value_server_uri" - app:layout_constraintTop_toBottomOf="@+id/checkBox" /> + app:layout_constraintTop_toBottomOf="@+id/separator_mqtt" /> </android.support.constraint.ConstraintLayout> diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 6ee756bc5e98d4942560f50611d09d121ffe0640..081b270ba0d08d638dcdedfe2afa2946397689cd 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -2,7 +2,12 @@ <string name="app_name">SensorSharing</string> <string name="text_own_brightness">Own Brightness</string> <string name="text_wear_brightness">Wear Brightness</string> + <string name="text_wear_acceleration">Wear Acceleration</string> + <string name="text_wear_rotation">Wear Rotation</string> <string name="text_connected">Connected</string> <string name="text_mqtt_server_uri">MQTT Server URI</string> - <string name="default_mqtt_server_uri">172.22.1.152</string> + <string name="default_mqtt_server_uri">tcp://10.8.0.119</string> + <string name="text_separator_smartphone_values">Smartphone Values</string> + <string name="text_separator_wear_values">Wear Values</string> + <string name="text_separator_mqtt_settings">MQTT Settings</string> </resources> diff --git a/settings.gradle b/settings.gradle index 6a4e79fc9b377828287f04f4b5a516fb86bcfa6d..b48dd9b195357697854a16815f480a5bafc67d94 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':mobile', ':wear' +include ':mobile', ':wear', ':common' diff --git a/wear/build.gradle b/wear/build.gradle index 0bdbccb03084b911851ff81b97c42a6f16ded560..5f5d0fdbf2f0a806d137349124cf1d10e0a2d03a 100644 --- a/wear/build.gradle +++ b/wear/build.gradle @@ -19,6 +19,9 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation project(':common') + implementation 'com.google.android.support:wearable:2.2.0' implementation 'com.google.android.gms:play-services-wearable:11.8.0' implementation 'com.android.support:percent:26.1.0' diff --git a/wear/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java b/wear/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java index 3a0e35a7604e0f3165853f157f5eea8d0b815f72..c6e71f471b180c17b4fad8173994fbcec3eb33f9 100644 --- a/wear/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java +++ b/wear/src/main/java/de/tudresden/inf/st/sensorsharing/MainActivity.java @@ -6,41 +6,37 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.wearable.activity.WearableActivity; +import android.util.Log; import android.view.View; import android.widget.TextView; -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.PendingResult; -import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; -import com.google.android.gms.tasks.Tasks; -import com.google.android.gms.wearable.DataApi; -import com.google.android.gms.wearable.DataClient; import com.google.android.gms.wearable.MessageClient; import com.google.android.gms.wearable.Node; -import com.google.android.gms.wearable.PutDataMapRequest; -import com.google.android.gms.wearable.PutDataRequest; import com.google.android.gms.wearable.Wearable; import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; +import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutionException; +import java.util.Locale; + +import static de.tudresden.inf.st.sensorsharing.common.Constants.KEY_BRIGHTNESS; +import static de.tudresden.inf.st.sensorsharing.common.Constants.KEY_LINEAR_ACCELERATION; +import static de.tudresden.inf.st.sensorsharing.common.Constants.KEY_ROTATION_VECTOR; public class MainActivity extends WearableActivity implements SensorEventListener { - private static final String WEAR_SENSORS = "/wearable/sensors"; - private static final String KEY_BRIGHTNESS = "brightness"; + private static final String TAG = "SensorSharing"; + private SensorManager mSensorManager; private Sensor mLight; private float mLightValue; + private Sensor mLinearAcceleration; + private float[] mLinearAccelerationValues; + private Sensor mRotationVector; + private float[] mRotationVectorValues; @Override protected void onCreate(Bundle savedInstanceState) { @@ -50,40 +46,86 @@ public class MainActivity extends WearableActivity implements SensorEventListene // setup sensor manager and light sensor mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (mSensorManager == null) { - TextView textView = findViewById(R.id.value_my_brightness); + TextView textView = findViewById(R.id.brightness_value); textView.setText(R.string.error_sensormanager_null); return; } + + // log available sensors + List<Sensor> allSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL); + StringBuilder sb = new StringBuilder(); + for (Sensor sensor : allSensors) { + sb.append(sensor.getName()).append(":").append(sensor.getStringType()).append(";"); + } + Log.i(TAG, "Available sensors: " + sb.toString()); + + // initialize sensors mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + mLinearAcceleration = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); + mRotationVector = mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR); + + // initialize sensor values + mLinearAccelerationValues = new float[3]; + mRotationVectorValues = new float[3]; - // Enables Always-on + // enables Always-on setAmbientEnabled(); } @Override public void onSensorChanged(SensorEvent sensorEvent) { - mLightValue = sensorEvent.values[0]; - TextView textView = findViewById(R.id.value_my_brightness); - textView.setText(String.valueOf(mLightValue)); + TextView textView; + switch(sensorEvent.sensor.getType()) { + case Sensor.TYPE_LIGHT: + mLightValue = sensorEvent.values[0]; + textView = findViewById(R.id.brightness_value); + textView.setText(String.valueOf(mLightValue)); + // a bit hacky: only send updates when brightness sensor changes + sendCurrentValueToAllConnectedNodes(); + break; + case Sensor.TYPE_LINEAR_ACCELERATION: + mLinearAccelerationValues = sensorEvent.values; + textView = findViewById(R.id.acceleration_value); + textView.setText(formatArray3(mLinearAccelerationValues)); + break; + case Sensor.TYPE_GAME_ROTATION_VECTOR: + mRotationVectorValues = sensorEvent.values; + textView = findViewById(R.id.rotation_value); + textView.setText(formatArray3(mRotationVectorValues)); + break; + } + } - // TODO here we should send the new value to the handheld - sendCurrentValueToAllConnectedNodes(); + private String formatArray3(float[] a) { + return String.format(Locale.getDefault(), "%.2f:%.2f:%.2f", a[0], a[1], a[2]); } private void sendCurrentValueToAllConnectedNodes() { Task<List<Node>> nodesTask = Wearable.getNodeClient(this).getConnectedNodes(); final MessageClient messageClient = Wearable.getMessageClient(this); - final byte[] data = ByteBuffer.allocate(4).putFloat(mLightValue).array(); nodesTask.addOnSuccessListener(new OnSuccessListener<List<Node>>() { @Override public void onSuccess(List<Node> nodes) { + final byte[] brightnessData = ByteBuffer.allocate(4).putFloat(mLightValue).array(); + final byte[] accelerationData = floatArray2ByteArray(mLinearAccelerationValues); + final byte[] rotationData = floatArray2ByteArray(mRotationVectorValues); for (Node node : nodes) { - messageClient.sendMessage(node.getId(), WEAR_SENSORS, data); + messageClient.sendMessage(node.getId(), KEY_BRIGHTNESS, brightnessData); + messageClient.sendMessage(node.getId(), KEY_LINEAR_ACCELERATION, accelerationData); + messageClient.sendMessage(node.getId(), KEY_ROTATION_VECTOR, rotationData); } } }); } + private byte[] floatArray2ByteArray(float[] input) { + ByteBuffer buffer = ByteBuffer.allocate(4 * input.length); + for (float value : input) { + buffer.putFloat(value); + } + return buffer.array(); + } + @Override public void onAccuracyChanged(Sensor sensor, int i) { // ignore accuracy changes @@ -92,7 +134,9 @@ public class MainActivity extends WearableActivity implements SensorEventListene @Override protected void onResume() { super.onResume(); - mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_FASTEST); + mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL); + mSensorManager.registerListener(this, mLinearAcceleration, SensorManager.SENSOR_DELAY_NORMAL); + mSensorManager.registerListener(this, mRotationVector, SensorManager.SENSOR_DELAY_NORMAL); } @Override diff --git a/wear/src/main/res/layout/activity_main.xml b/wear/src/main/res/layout/activity_main.xml index c705f9814e486b4f3af4ab7728f1b880e54dcd42..65aecaad378b51eb87aa2117aba2aa93430486b7 100644 --- a/wear/src/main/res/layout/activity_main.xml +++ b/wear/src/main/res/layout/activity_main.xml @@ -17,9 +17,43 @@ app:boxedEdges="all"> <TextView - android:id="@+id/value_my_brightness" + android:id="@+id/brightness_value" android:layout_width="wrap_content" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + android:layout_gravity="top|end" /> + + <TextView + android:id="@+id/brightness_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|start" + android:text="@string/text_brightness" /> + + <TextView + android:id="@+id/acceleration_value" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center|end" /> + + <TextView + android:id="@+id/acceleration_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center|start" + android:text="@string/text_acceleration" /> + + <TextView + android:id="@+id/rotation_value" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|end" /> + + <TextView + android:id="@+id/rotation_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|start" + android:text="@string/text_rotation" /> </FrameLayout> </android.support.wear.widget.BoxInsetLayout> diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml index 19145364f3f5d8924e0dad2d8a8adb37182132cf..876cafdad169210741470f8d573f95893b2f5757 100644 --- a/wear/src/main/res/values/strings.xml +++ b/wear/src/main/res/values/strings.xml @@ -5,6 +5,8 @@ values-round/strings.xml for round devices. --> <string name="hello_world">Hello Square World!</string> - <string name="text_my_brightness">My brightness</string> + <string name="text_brightness">Bri</string> + <string name="text_acceleration">Acc</string> + <string name="text_rotation">Rot</string> <string name="error_sensormanager_null">Could not fetch sensor manager</string> </resources>