diff --git a/packaging/android/AndroidManifest.xml b/packaging/android/AndroidManifest.xml
index 4bbbaaf7..d6469ea1 100644
--- a/packaging/android/AndroidManifest.xml
+++ b/packaging/android/AndroidManifest.xml
@@ -73,6 +73,13 @@
+
+
+
+
+
+
+
diff --git a/packaging/android/build.gradle b/packaging/android/build.gradle
index 69d802cd..957ca95f 100644
--- a/packaging/android/build.gradle
+++ b/packaging/android/build.gradle
@@ -30,6 +30,8 @@ dependencies {
compile 'com.google.android.gms:play-services-base:15.0.1'
compile 'com.google.firebase:firebase-messaging:18.0.0'
compile 'com.google.firebase.messaging.cpp:firebase_messaging_cpp@aar'
+ implementation 'org.reactivestreams:reactive-streams:1.0.3'
+ implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
}
apply plugin: 'com.google.gms.google-services'
diff --git a/packaging/android/src/io/guh/nymeaapp/NymeaAppHomeControlsService.java b/packaging/android/src/io/guh/nymeaapp/NymeaAppHomeControlsService.java
new file mode 100644
index 00000000..bb31d2b0
--- /dev/null
+++ b/packaging/android/src/io/guh/nymeaapp/NymeaAppHomeControlsService.java
@@ -0,0 +1,127 @@
+package io.guh.nymeaapp;
+
+import android.util.Log;
+import android.content.Intent;
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.content.Context;
+import android.provider.Settings.System;
+import android.os.Build;
+import android.service.controls.ControlsProviderService;
+import android.service.controls.actions.ControlAction;
+import android.service.controls.actions.BooleanAction;
+import android.service.controls.Control;
+import android.service.controls.DeviceTypes;
+
+import java.util.Random;
+import java.util.concurrent.Flow.Publisher;
+import java.util.function.Consumer;
+import java.util.List;
+import java.util.ArrayList;
+import io.reactivex.Flowable;
+import io.reactivex.processors.ReplayProcessor;
+import org.reactivestreams.FlowAdapters;
+
+public class NymeaAppHomeControlsService extends ControlsProviderService {
+
+ private ReplayProcessor updatePublisher;
+ private PendingIntent pi;
+
+ @Override
+ public Publisher createPublisherForAllAvailable() {
+ Context context = getBaseContext();
+ Intent i = new Intent();
+// PendingIntent pi = PendingIntent.getActivity(context, 1, i, PendingIntent.FLAG_UPDATE_CURRENT);
+ pi = PendingIntent.getActivity(context, 1, i, PendingIntent.FLAG_UPDATE_CURRENT);
+ List controls = new ArrayList<>();
+ Control control = new Control.StatelessBuilder("123", pi)
+ // Required: The name of the control
+ .setTitle("TestControl")
+ // Required: Usually the room where the control is located
+ .setSubtitle("TestSubtitle")
+ // Optional: Structure where the control is located, an example would be a house
+ .setStructure("TestLocation")
+ // Required: Type of device, i.e., thermostat, light, switch
+ .setDeviceType(DeviceTypes.TYPE_LIGHT) // For example, DeviceTypes.TYPE_THERMOSTAT
+ .build();
+ controls.add(control);
+ // Create more controls here if needed and add it to the ArrayList
+
+ // Uses the RxJava 2 library
+ return FlowAdapters.toFlowPublisher(Flowable.fromIterable(controls));
+ }
+
+
+ @Override
+ public Publisher createPublisherFor(List controlIds) {
+ Context context = getBaseContext();
+ /* Fill in details for the activity related to this device. On long press,
+ * this Intent will be launched in a bottomsheet. Please design the activity
+ * accordingly to fit a more limited space (about 2/3 screen height).
+ */
+ Intent i = new Intent();
+ PendingIntent pi = PendingIntent.getActivity(context, 1, i, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ updatePublisher = ReplayProcessor.create();
+
+ // For each controlId in controlIds
+
+ if (controlIds.contains(123)) {
+ Control control = new Control.StatefulBuilder("123", pi)
+ // Required: The name of the control
+ .setTitle("TestTitle")
+ // Required: Usually the room where the control is located
+ .setSubtitle("TestSubTitle")
+ // Optional: Structure where the control is located, an example would be a house
+ .setStructure("TestStructure")
+ // Required: Type of device, i.e., thermostat, light, switch
+ .setDeviceType(DeviceTypes.TYPE_LIGHT) // For example, DeviceTypes.TYPE_THERMOSTAT
+ // Required: Current status of the device
+ .setStatus(Control.STATUS_OK) // For example, Control.STATUS_OK
+ .build();
+
+ updatePublisher.onNext(control);
+ }
+ // Uses the Reactive Streams API
+ return FlowAdapters.toFlowPublisher(updatePublisher);
+ }
+
+ @Override
+ public void performControlAction(String controlId, ControlAction action, Consumer consumer) {
+ /* First, locate the control identified by the controlId. Once it is located, you can
+ * interpret the action appropriately for that specific device. For instance, the following
+ * assumes that the controlId is associated with a light, and the light can be turned on
+ * or off.
+ */
+ if (action instanceof BooleanAction) {
+
+ // Inform SystemUI that the action has been received and is being processed
+ consumer.accept(ControlAction.RESPONSE_OK);
+
+ BooleanAction bAction = (BooleanAction) action;
+ // In this example, action.getNewState() will have the requested action: true for “On”,
+ // false for “Off”.
+
+ /* This is where application logic/network requests would be invoked to update the state of
+ * the device.
+ * After updating, the application should use the publisher to update SystemUI with the new
+ * state.
+ */
+ Control control = new Control.StatefulBuilder("123", pi)
+ // Required: The name of the control
+ .setTitle("TestControl")
+ // Required: Usually the room where the control is located
+ .setSubtitle("TestSubTitle")
+ // Optional: Structure where the control is located, an example would be a house
+ .setStructure("TestStructure")
+ // Required: Type of device, i.e., thermostat, light, switch
+ .setDeviceType(DeviceTypes.TYPE_LIGHT) // For example, DeviceTypes.TYPE_THERMOSTAT
+ // Required: Current status of the device
+ .setStatus(Control.STATUS_OK) // For example, Control.STATUS_OK
+ .build();
+
+ // This is the publisher the application created during the call to createPublisherFor()
+ updatePublisher.onNext(control);
+ }
+ }
+}