Add support for getters.

As example getters for wifi connection (boolean) and wifi SSID (string) were
added.
This commit is contained in:
Sergio Martínez Portela 2020-05-28 17:35:11 +02:00
parent af28ef0a3c
commit a4aff44818
11 changed files with 208 additions and 25 deletions

View File

@ -1,6 +1,6 @@
package com.codigoparallevar.minicards.bridge.blocks; package com.codigoparallevar.minicards.bridge.blocks;
import com.codigoparallevar.minicards.types.functional.Consumer; import com.codigoparallevar.minicards.types.functional.Function;
import com.programaker.bridge.ProgramakerBridgeConfigurationBlock; import com.programaker.bridge.ProgramakerBridgeConfigurationBlock;
import java.util.LinkedList; import java.util.LinkedList;
@ -20,10 +20,26 @@ public class BridgeBlockListBuilder {
public BridgeBlockListBuilder addOperation(String id, String message, public BridgeBlockListBuilder addOperation(String id, String message,
List<BlockArgumentDefinition> arguments, List<BlockArgumentDefinition> arguments,
Consumer<List<? extends Object>> operation) { Function<List<?>, Void> operation) {
return this.addOperation(new OperationBlockDefinition(id, message, arguments, operation)); return this.addOperation(new OperationBlockDefinition(id, message, arguments, operation));
} }
private BridgeBlockListBuilder addOperation(ProgramakerBridgeConfigurationBlock block) {
this.blockList.add(block);
return this;
}
public BridgeBlockListBuilder addGetter(String id, String message,
List<BlockArgumentDefinition> arguments,
Function<List<?>, ?> operation) {
return this.addGetter(new GetterBlockDefinition(id, message, arguments, operation));
}
private BridgeBlockListBuilder addGetter(ProgramakerBridgeConfigurationBlock block) {
this.blockList.add(block);
return this;
}
public BridgeBlockListBuilder addTrigger(String id, String message, public BridgeBlockListBuilder addTrigger(String id, String message,
List<BlockArgumentDefinition> arguments, List<BlockArgumentDefinition> arguments,
String key) { String key) {
@ -35,10 +51,4 @@ public class BridgeBlockListBuilder {
return this; return this;
} }
private BridgeBlockListBuilder addOperation(ProgramakerBridgeConfigurationBlock block) {
this.blockList.add(block);
return this;
}
} }

View File

@ -4,6 +4,9 @@ import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build; import android.os.Build;
import android.os.VibrationEffect; import android.os.VibrationEffect;
import android.os.Vibrator; import android.os.Vibrator;
@ -80,6 +83,8 @@ public class DefaultAndroidBlocks {
int notificationId = notificationRandom.nextInt(); int notificationId = notificationRandom.nextInt();
notificationManager.notify(notificationId, notif); notificationManager.notify(notificationId, notif);
return null;
} }
) )
.addOperation( .addOperation(
@ -88,6 +93,8 @@ public class DefaultAndroidBlocks {
Collections.emptyList(), Collections.emptyList(),
(List<?> params) -> { (List<?> params) -> {
notificationManager.cancelAll(); notificationManager.cancelAll();
return null;
} }
) )
.addOperation( .addOperation(
@ -141,21 +148,59 @@ public class DefaultAndroidBlocks {
// Remove notification // Remove notification
notificationManager.cancel(notificationId); notificationManager.cancel(notificationId);
}).start(); }).start();
return null;
} }
) )
; ;
// GETTERS
builder.addGetter(
"wifi_is_connected",
"Is WIFI connected?",
Collections.emptyList(),
(List<?> params) -> {
WifiManager wifiManager = (WifiManager) ctx.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
assert wifiManager != null;
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo == null) {
return false;
}
return wifiInfo.getSupplicantState() == SupplicantState.COMPLETED;
})
.addGetter(
"wifi_get_ssid",
"Get WIFI SSID",
Collections.emptyList(),
(List<?> params) -> {
WifiManager wifiManager = (WifiManager) ctx.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
assert wifiManager != null;
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo == null) {
return null;
}
if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) {
return null;
}
return wifiInfo.getSSID();
});
// Signal blocks // Signal blocks
builder builder
.addTrigger( .addTrigger(
"on_wifi_connected", "on_wifi_connected",
"When WIFI connects", "When WIFI connection is ESTABLISHED",
Collections.emptyList(),// TODO: Save content to variable Collections.emptyList(),// TODO: Save content to variable
"on_wifi_connected" "on_wifi_connected"
) )
.addTrigger( .addTrigger(
"on_wifi_disconnected", "on_wifi_disconnected",
"When WIFI connection is lost", "When WIFI connection is LOST",
Collections.emptyList(), Collections.emptyList(),
"on_wifi_disconnected" "on_wifi_disconnected"
); );

View File

@ -0,0 +1,65 @@
package com.codigoparallevar.minicards.bridge.blocks;
import android.util.Log;
import com.codigoparallevar.minicards.types.functional.Function;
import com.programaker.bridge.ProgramakerBridgeConfigurationBlock;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
class GetterBlockDefinition implements ProgramakerBridgeConfigurationBlock {
private final static String LogTag = "PM GetterBlockDef";
private final String id;
private final String message;
private final List<BlockArgumentDefinition> args;
private final Function<List<?>, ?> operation;
public GetterBlockDefinition(String id, String message, List<BlockArgumentDefinition> args, Function<List<?>, ?> operation) {
this.id = id;
this.message = message;
this.args = args;
this.operation = operation;
}
@NotNull
@Override
public JSONObject serialize() {
JSONObject obj = new JSONObject();
try {
JSONArray arguments = new JSONArray();
for (BlockArgumentDefinition arg : this.args) {
arguments.put(arg.serialize());
}
obj.put("id", this.id);
obj.put("function_name", this.id);
obj.put("message", this.message);
obj.put("block_type", "getter");
obj.put("block_result_type", JSONObject.NULL); // TODO: Properly declare type
obj.put("arguments", arguments);
obj.put("save_to", JSONObject.NULL);
} catch (JSONException ex) {
Log.e(LogTag, "Error serializing block definition: " + ex, ex);
}
return obj;
}
@NotNull
@Override
public String getFunctionName() {
return this.id;
}
@Override
public Object call(@NotNull List<?> arguments) throws Exception {
return this.operation.apply(arguments);
}
}

View File

@ -2,7 +2,7 @@ package com.codigoparallevar.minicards.bridge.blocks;
import android.util.Log; import android.util.Log;
import com.codigoparallevar.minicards.types.functional.Consumer; import com.codigoparallevar.minicards.types.functional.Function;
import com.programaker.bridge.ProgramakerBridgeConfigurationBlock; import com.programaker.bridge.ProgramakerBridgeConfigurationBlock;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -18,9 +18,9 @@ class OperationBlockDefinition implements ProgramakerBridgeConfigurationBlock {
private final String id; private final String id;
private final String message; private final String message;
private final List<BlockArgumentDefinition> args; private final List<BlockArgumentDefinition> args;
private final Consumer<List<?>> operation; private final Function<List<?>, Void> operation;
public OperationBlockDefinition(String id, String message, List<BlockArgumentDefinition> args, Consumer<List<? extends Object>> operation) { public OperationBlockDefinition(String id, String message, List<BlockArgumentDefinition> args, Function<List<?>, Void> operation) {
this.id = id; this.id = id;
this.message = message; this.message = message;
this.args = args; this.args = args;
@ -59,7 +59,7 @@ class OperationBlockDefinition implements ProgramakerBridgeConfigurationBlock {
} }
@Override @Override
public void call(@NotNull List<?> arguments) throws Exception { public Object call(@NotNull List<?> arguments) throws Exception {
this.operation.apply(arguments); return this.operation.apply(arguments);
} }
} }

View File

@ -61,7 +61,7 @@ class TriggerBlockDefinition implements ProgramakerBridgeConfigurationBlock {
} }
@Override @Override
public void call(@NotNull List<?> arguments) throws Exception { public Object call(@NotNull List<?> arguments) throws Exception {
throw new IllegalArgumentException("Non executable block"); throw new IllegalArgumentException("Non executable block");
} }
} }

View File

@ -0,0 +1,5 @@
package com.codigoparallevar.minicards.types.functional;
public interface Function<T, U> {
U apply(T param) throws Exception;
}

View File

@ -1,6 +1,10 @@
package com.codigoparallevar.minicards.utils; package com.codigoparallevar.minicards.utils;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.List; import java.util.List;
@ -8,6 +12,8 @@ import java.util.Map;
public class Serializations { public class Serializations {
private static final String LogTag = "Serialization";
public static JSONArray serialize(List<Map<String,String>> data) { public static JSONArray serialize(List<Map<String,String>> data) {
JSONArray array = new JSONArray(); JSONArray array = new JSONArray();
for (Map<String, String> dict : data) { for (Map<String, String> dict : data) {
@ -16,4 +22,54 @@ public class Serializations {
return array; return array;
} }
@NotNull
public static Object blindSerialize(Object obj) {
if (obj == null) {
return JSONObject.NULL;
}
// No serialization needed
else if (obj.getClass().isPrimitive() ||
obj instanceof String ||
obj instanceof JSONObject ||
obj instanceof JSONArray) {
return obj;
}
try {
return _blindSerialize(obj);
}
catch (Exception ex) {
Log.w(LogTag, "Error serialization: " + obj, ex);
return obj;
}
}
private static Object _blindSerialize(Object obj) throws JSONException {
if (obj instanceof Map) {
Map<?,?> objMap = (Map<?,?>) obj;
JSONObject map = new JSONObject();
for (Map.Entry<?,?> entry : objMap.entrySet()) {
map.put(entry.getKey().toString(), blindSerialize(entry.getValue()));
}
return map;
}
else if (obj instanceof Iterable) {
Iterable objIt = (Iterable) obj;
JSONArray arr = new JSONArray();
for (Object val : objIt) {
arr.put(blindSerialize(val));
}
return arr;
}
else {
// Unknown case
return obj;
}
}
} }

View File

@ -1,6 +1,7 @@
package com.programaker.bridge package com.programaker.bridge
import android.util.Log import android.util.Log
import com.codigoparallevar.minicards.utils.Serializations
import com.google.gson.Gson import com.google.gson.Gson
import okhttp3.* import okhttp3.*
import okio.ByteString import okio.ByteString
@ -113,9 +114,9 @@ class ProgramakerBridge(
val arguments = value.get("arguments") as List<*> val arguments = value.get("arguments") as List<*>
try { try {
config.callFunction(functionName, arguments) var result = config.callFunction(functionName, arguments)
result = Serializations.blindSerialize(result)
val result = JSONObject.NULL
webSocket.send( webSocket.send(
JSONObject( JSONObject(
hashMapOf( hashMapOf(

View File

@ -36,9 +36,10 @@ class ProgramakerBridgeConfiguration(
return wrapper.toString() return wrapper.toString()
} }
fun callFunction(functionName: String, arguments: List<*>) { fun callFunction(functionName: String, arguments: List<*>): Any {
for (block in blocks) { for (block in blocks) {
if (block.getFunctionName() == functionName) { val blockFunction = block.getFunctionName()
if (blockFunction != null && blockFunction == functionName) {
return block.call(arguments) return block.call(arguments)
} }
} }

View File

@ -3,9 +3,9 @@ package com.programaker.bridge
import org.json.JSONObject import org.json.JSONObject
interface ProgramakerBridgeConfigurationBlock { interface ProgramakerBridgeConfigurationBlock {
fun serialize() : JSONObject; fun serialize() : JSONObject
fun getFunctionName(): String; fun getFunctionName(): String
@Throws(Exception::class) @Throws(Exception::class)
fun call(arguments: List<*>) fun call(arguments: List<*>): Any
} }

View File

@ -19,9 +19,9 @@
<string name="back_to_deck">Back to card Deck</string> <string name="back_to_deck">Back to card Deck</string>
<string name="go_back">Go back</string> <string name="go_back">Go back</string>
<string name="bridge_service_not_started">Programaker bridge not started</string> <string name="bridge_service_not_started">Programaker bridge not started</string>
<string name="bridge_service_starting">Programaker bridge starting</string> <string name="bridge_service_starting">Programaker bridge connecting...</string>
<string name="bridge_service_online">Programaker bridge online</string> <string name="bridge_service_online">Programaker bridge online</string>
<string name="bridge_service_failed_restarting">Programaker bridge failed, restarting...</string> <string name="bridge_service_failed_restarting">Programaker bridge reconnecting...</string>
<string name="bridge_service_failed_stopping">Programaker bridge stopped</string> <string name="bridge_service_failed_stopping">Programaker bridge stopped</string>
<string name="stop_bridge">Stop bridge</string> <string name="stop_bridge">Stop bridge</string>
<string name="start_bridge">Start bridge</string> <string name="start_bridge">Start bridge</string>