diff --git a/build.gradle b/build.gradle index 1a3d812308d49457ea04cd40dacb56edffcd19a5..23dfc1e976272296d22feaf33b5dde0e48dca640 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,9 @@ buildscript { repositories { google() jcenter() + maven { + url "https://repo.eclipse.org/content/repositories/paho-snapshots/" + } } dependencies { classpath 'com.android.tools.build:gradle:3.1.2' diff --git a/mobile/build.gradle b/mobile/build.gradle index 335b6ab74ab8c101a86ace8d8d413ab7f5018319..ce3d9a77ad537af575dae3195228686c3f7bc2f1 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -21,10 +21,18 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' - implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support.constraint:constraint-layout:1.1.0' + + // jUnit testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + + // MQTT + implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' + implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1' + + // Wear services wearApp project(':wear') - implementation 'com.google.android.gms:play-services-wearable:+' + implementation 'com.google.android.gms:play-services-wearable:15.0.1' } diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml index d34b0c5443fe5bec25bbc57b5f340bf9988e4697..272b896b69836ba597b58aaae714087061ef1c35 100644 --- a/mobile/src/main/AndroidManifest.xml +++ b/mobile/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ package="de.tudresden.inf.st.sensorsharing"> <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <application android:allowBackup="true" @@ -17,6 +20,7 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <service android:name="org.eclipse.paho.android.service.MqttService" /> </application> </manifest> \ No newline at end of file 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 07e42994f5d27644870fda6d7ec9cb7e69b087be..7dea7bf3da9849fcc0ca467259cc3465857491f3 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 @@ -8,7 +8,10 @@ import android.hardware.SensorManager; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; import android.widget.CheckBox; +import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; @@ -16,18 +19,36 @@ import com.google.android.gms.wearable.MessageClient; import com.google.android.gms.wearable.MessageEvent; import com.google.android.gms.wearable.Wearable; +import org.eclipse.paho.android.service.MqttAndroidClient; +import org.eclipse.paho.android.service.MqttService; +import org.eclipse.paho.client.mqttv3.IMqttActionListener; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.IMqttToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; + import java.nio.ByteBuffer; +import java.nio.charset.Charset; 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_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; @Override protected void onCreate(Bundle savedInstanceState) { @@ -44,6 +65,66 @@ public class MainActivity extends AppCompatActivity implements mValueWearBrightness = findViewById(R.id.value_wear_brightness); setChecked(false); + connectMqtt(null); + } + + public void connectMqtt(View view) { + // disconnect if there is a connected client + if (mqttAndroidClient != null && mqttAndroidClient.isConnected()) { + try { + mqttAndroidClient.disconnect(); + } catch (MqttException e) { + Toast.makeText(MainActivity.this, + "Could not disconnect from running broker. Continue.", + Toast.LENGTH_LONG).show(); + } + } + + // setup new mqtt client + EditText valueServerURI = findViewById(R.id.value_server_uri); + final String serverURI = valueServerURI.getText().toString(); + Toast.makeText(MainActivity.this, "Connecting to " + serverURI, + Toast.LENGTH_LONG).show(); + mqttAndroidClient = new MqttAndroidClient(this, serverURI, + "SensorSharing-mobile"); + mqttAndroidClient.setCallback(new MqttCallback() { + @Override + public void connectionLost(Throwable cause) { + Toast.makeText(MainActivity.this, "Connection to MQTT broker lost", + Toast.LENGTH_LONG).show(); + } + + @Override + public void messageArrived(String topic, MqttMessage message) { + + } + + @Override + public void deliveryComplete(IMqttDeliveryToken token) { + + } + }); + MqttConnectOptions options = new MqttConnectOptions(); + options.setCleanSession(false); + options.setAutomaticReconnect(true); + options.setConnectionTimeout(5); + try { + IMqttToken token = mqttAndroidClient.connect(options, null, new IMqttActionListener() { + @Override + public void onSuccess(IMqttToken asyncActionToken) { + Log.i(TAG, "Connected to " + serverURI); + } + + @Override + public void onFailure(IMqttToken asyncActionToken, Throwable exception) { + Log.e(TAG, "Connection to " + serverURI + " failed"); + } + }); + + } catch (MqttException e) { + Toast.makeText(this, "Connection to " + serverURI + " failed", + Toast.LENGTH_LONG).show(); + } } private void setChecked(boolean checked) { @@ -54,8 +135,10 @@ public class MainActivity extends AppCompatActivity implements @Override public void onSensorChanged(SensorEvent sensorEvent) { float lightValue = sensorEvent.values[0]; + String stringValue = String.valueOf(lightValue); TextView textView = findViewById(R.id.value_own_brightness); - textView.setText(String.valueOf(lightValue)); + textView.setText(stringValue); + sendUpdateOfSmartphone(stringValue); } @Override @@ -66,7 +149,7 @@ public class MainActivity extends AppCompatActivity implements @Override protected void onResume() { super.onResume(); - mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_FASTEST); + mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_UI); Wearable.getMessageClient(this).addListener(this); } @@ -82,13 +165,41 @@ public class MainActivity extends AppCompatActivity implements 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); runOnUiThread(new Runnable() { @Override public void run() { - mValueWearBrightness.setText(Float.toString(mWearBrightness)); + setChecked(true); + mValueWearBrightness.setText(stringValue); } }); + sendUpdateOfWearable(stringValue); + } + } + + private void sendUpdateOfWearable(String newValue) { + sendUpdate(MQTT_TOPIC_POLAR, newValue); + } + + private void sendUpdateOfSmartphone(String newValue) { + sendUpdate(MQTT_TOPIC_SAMSUNG, newValue); + } + private void sendUpdate(String topic, String newValue) { + if (mqttAndroidClient == null) { + Log.d(TAG, "mqtt client is null"); + return; + } + if (!mqttAndroidClient.isConnected()) { + Log.d(TAG, "mqtt client not connected"); + return; + } + // send to MQTT + try { + mqttAndroidClient.publish(topic, newValue.getBytes(MQTT_CHARSET), + MQTT_DEFAULT_QOS, false); + } catch (MqttException e) { + Log.d(TAG, "mqtt message publish failed", e); } } } diff --git a/mobile/src/main/res/layout/activity_main.xml b/mobile/src/main/res/layout/activity_main.xml index a7a0235eb63b6d0451e228193dd0f7ba08104e1c..b6225fade947925920c954d7fcfdc53bd8daf48e 100644 --- a/mobile/src/main/res/layout/activity_main.xml +++ b/mobile/src/main/res/layout/activity_main.xml @@ -6,6 +6,17 @@ android:layout_height="match_parent" tools:context="de.tudresden.inf.st.sensorsharing.MainActivity"> + <TextView + android:id="@+id/label_server_uri" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + 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" /> + <TextView android:id="@+id/label_own_brightness" android:layout_width="wrap_content" @@ -59,4 +70,29 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/label_wear_brightness" /> + <EditText + android:id="@+id/value_server_uri" + android:layout_width="128dp" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:ems="10" + android:inputType="text" + android:text="@string/default_mqtt_server_uri" + app:layout_constraintStart_toEndOf="@+id/label_server_uri" + app:layout_constraintTop_toBottomOf="@+id/checkBox" /> + + <Button + android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:onClick="connectMqtt" + android:text="@android:string/ok" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/value_server_uri" + app:layout_constraintTop_toBottomOf="@+id/checkBox" /> + </android.support.constraint.ConstraintLayout> diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 3e623985759557618f56c2fe758e3e95e05d0030..6ee756bc5e98d4942560f50611d09d121ffe0640 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -3,4 +3,6 @@ <string name="text_own_brightness">Own Brightness</string> <string name="text_wear_brightness">Wear Brightness</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> </resources> 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 85433f5c3123f77f1aea5197bf2e31994560063d..3a0e35a7604e0f3165853f157f5eea8d0b815f72 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 @@ -9,6 +9,7 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.wearable.activity.WearableActivity; +import android.view.View; import android.widget.TextView; import com.google.android.gms.common.api.GoogleApiClient; @@ -99,4 +100,7 @@ public class MainActivity extends WearableActivity implements SensorEventListene super.onPause(); mSensorManager.unregisterListener(this); } + + public void connectMqtt(View view) { + } }