Send signal when wifi status change.

This commit is contained in:
Sergio Martínez Portela 2020-05-28 15:12:19 +02:00
parent d0f4a82043
commit af28ef0a3c
9 changed files with 237 additions and 5 deletions

View File

@ -7,10 +7,13 @@
android:glEsVersion="0x00020000" android:glEsVersion="0x00020000"
android:required="true" /> android:required="true" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- For Programaker bridge --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- For Programaker bridge -->
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application <application
android:allowBackup="true" android:allowBackup="true"

View File

@ -5,12 +5,14 @@ import android.provider.Settings;
import com.codigoparallevar.minicards.ConfigManager; import com.codigoparallevar.minicards.ConfigManager;
import com.codigoparallevar.minicards.bridge.blocks.DefaultAndroidBlocks; import com.codigoparallevar.minicards.bridge.blocks.DefaultAndroidBlocks;
import com.codigoparallevar.minicards.bridge.helpers.StatusStreamer;
import com.programaker.bridge.ProgramakerBridge; import com.programaker.bridge.ProgramakerBridge;
import com.programaker.bridge.ProgramakerBridgeConfiguration; import com.programaker.bridge.ProgramakerBridgeConfiguration;
public class ProgramakerAndroidBridge { public class ProgramakerAndroidBridge {
private static final String LogTag = "PM Android Bridge"; private static final String LogTag = "PM Android Bridge";
private ProgramakerBridge bridgeRunner = null; private ProgramakerBridge bridgeRunner = null;
private StatusStreamer statusStreamer = null;
// Static // Static
public static ProgramakerAndroidBridge configure(Context ctx, String userId, String bridgeId) { public static ProgramakerAndroidBridge configure(Context ctx, String userId, String bridgeId) {
@ -43,9 +45,13 @@ public class ProgramakerAndroidBridge {
this.bridgeRunner = new ProgramakerBridge(this.bridgeId, this.userId, configuration, onReady, onComplete); this.bridgeRunner = new ProgramakerBridge(this.bridgeId, this.userId, configuration, onReady, onComplete);
this.bridgeRunner.run(); this.bridgeRunner.run();
this.statusStreamer = new StatusStreamer(this.ctx, this.bridgeRunner);
this.statusStreamer.run();
} }
public void stop() { public void stop() {
bridgeRunner.stop(); bridgeRunner.stop();
this.statusStreamer.stop();
} }
} }

View File

@ -5,7 +5,6 @@ import com.programaker.bridge.ProgramakerBridgeConfigurationBlock;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
public class BridgeBlockListBuilder { public class BridgeBlockListBuilder {
private final LinkedList<ProgramakerBridgeConfigurationBlock> blockList; private final LinkedList<ProgramakerBridgeConfigurationBlock> blockList;
@ -25,6 +24,18 @@ public class BridgeBlockListBuilder {
return this.addOperation(new OperationBlockDefinition(id, message, arguments, operation)); return this.addOperation(new OperationBlockDefinition(id, message, arguments, operation));
} }
public BridgeBlockListBuilder addTrigger(String id, String message,
List<BlockArgumentDefinition> arguments,
String key) {
return this.addTrigger(new TriggerBlockDefinition(id, message, arguments, key));
}
private BridgeBlockListBuilder addTrigger(TriggerBlockDefinition block) {
this.blockList.add(block);
return this;
}
private BridgeBlockListBuilder addOperation(ProgramakerBridgeConfigurationBlock block) { private BridgeBlockListBuilder addOperation(ProgramakerBridgeConfigurationBlock block) {
this.blockList.add(block); this.blockList.add(block);

View File

@ -53,8 +53,8 @@ public class DefaultAndroidBlocks {
notificationManager.createNotificationChannel(vibrationChannel); notificationManager.createNotificationChannel(vibrationChannel);
} }
// OPERATIONS
return new BridgeBlockListBuilder() BridgeBlockListBuilder builder = new BridgeBlockListBuilder()
// Notifications // Notifications
.addOperation( .addOperation(
"notifications_new", "notifications_new",
@ -109,7 +109,6 @@ public class DefaultAndroidBlocks {
pattern[i * 2] = VIBRATION_ACTIVE_TIME; pattern[i * 2] = VIBRATION_ACTIVE_TIME;
pattern[i * 2 + 1] = VIBRATION_REST_TIME; pattern[i * 2 + 1] = VIBRATION_REST_TIME;
} }
// pattern[0] = 0; // Start immediately
Notification notif = new NotificationCompat Notification notif = new NotificationCompat
.Builder(ctx, ProgramakerBridgeService.BridgeUserVibrationNotificationChannel) .Builder(ctx, ProgramakerBridgeService.BridgeUserVibrationNotificationChannel)
@ -145,5 +144,22 @@ public class DefaultAndroidBlocks {
} }
) )
; ;
// Signal blocks
builder
.addTrigger(
"on_wifi_connected",
"When WIFI connects",
Collections.emptyList(),// TODO: Save content to variable
"on_wifi_connected"
)
.addTrigger(
"on_wifi_disconnected",
"When WIFI connection is lost",
Collections.emptyList(),
"on_wifi_disconnected"
);
return builder;
} }
} }

View File

@ -13,7 +13,7 @@ import org.json.JSONObject;
import java.util.List; import java.util.List;
class OperationBlockDefinition implements ProgramakerBridgeConfigurationBlock { class OperationBlockDefinition implements ProgramakerBridgeConfigurationBlock {
private final static String LogTag = "PM OpBlockDefinition"; private final static String LogTag = "PM OpBlockDef";
private final String id; private final String id;
private final String message; private final String message;

View File

@ -0,0 +1,67 @@
package com.codigoparallevar.minicards.bridge.blocks;
import android.util.Log;
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 TriggerBlockDefinition implements ProgramakerBridgeConfigurationBlock {
private final static String LogTag = "PM TriggerBlockDef";
private final String id;
private final String message;
private final List<BlockArgumentDefinition> args;
private final String key;
public TriggerBlockDefinition(String id, String message, List<BlockArgumentDefinition> args,
String key) {
this.id = id;
this.message = message;
this.args = args;
this.key = key;
}
@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("arguments", arguments);
obj.put("save_to", JSONObject.NULL);
obj.put("expected_value", JSONObject.NULL);
obj.put("block_type", "trigger");
obj.put("key", this.key);
obj.put("subkey", 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 void call(@NotNull List<?> arguments) throws Exception {
throw new IllegalArgumentException("Non executable block");
}
}

View File

@ -0,0 +1,78 @@
package com.codigoparallevar.minicards.bridge.helpers;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import com.programaker.bridge.ProgramakerBridge;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class StatusStreamer {
private final Context ctx;
private final ProgramakerBridge bridge;
private WifiNetworkCallbackReceiver networkCallback = null;
public StatusStreamer(Context ctx, ProgramakerBridge bridge) {
this.ctx = ctx;
this.bridge = bridge;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.networkCallback = new WifiNetworkCallbackReceiver(this);
}
}
public void run() {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
return;
}
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
ConnectivityManager connManager = (ConnectivityManager) this.ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
assert connManager != null;
connManager.registerNetworkCallback(builder.build(), this.networkCallback);
}
public void stop() {
ConnectivityManager connManager = (ConnectivityManager) this.ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
assert connManager != null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connManager.unregisterNetworkCallback(this.networkCallback);
}
}
public void onWifiNetworkConnected(Network network) {
WifiManager wifiManager = (WifiManager) this.ctx.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo;
wifiInfo = wifiManager.getConnectionInfo();
String ssid = "";
if (wifiInfo.getSupplicantState() == SupplicantState.COMPLETED) {
// This might not return the SSID in case the user has not granted location permissions to the app
// see: https://stackoverflow.com/a/54446042
ssid = wifiInfo.getSSID();
}
Map<String, String> data = new HashMap<>();
data.put("ssid", ssid);
this.bridge.sendSignal("on_wifi_connected", new JSONObject(data));
}
public void onWifiNetworkDisconnected() {
this.bridge.sendSignal("on_wifi_disconnected", new JSONObject());
}
}

View File

@ -0,0 +1,34 @@
package com.codigoparallevar.minicards.bridge.helpers;
import android.net.ConnectivityManager;
import android.net.Network;
import android.os.Build;
import androidx.annotation.RequiresApi;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
class WifiNetworkCallbackReceiver extends ConnectivityManager.NetworkCallback {
private final StatusStreamer streamer;
public WifiNetworkCallbackReceiver(StatusStreamer statusStreamer) {
this.streamer = statusStreamer;
}
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
this.streamer.onWifiNetworkConnected(network);
}
@Override
public void onUnavailable() {
super.onUnavailable();
this.streamer.onWifiNetworkDisconnected();
}
@Override
public void onLost(Network network) {
super.onLost(network);
this.streamer.onWifiNetworkDisconnected();
}
}

View File

@ -173,4 +173,21 @@ class ProgramakerBridge(
fun stop() { fun stop() {
webSocket?.close(1000, null) webSocket?.close(1000, null)
} }
fun sendSignal(key: String, content: JSONObject) {
if (webSocket == null) {
Log.w(LogTag, "Cannot send signal (key=$key) on closed channel")
return
}
webSocket!!.send(JSONObject(hashMapOf(
"type" to "NOTIFICATION",
"key" to key,
"subkey" to JSONObject.NULL,
"to_user" to JSONObject.NULL,
"value" to content,
"content" to content
)
).toString())
}
} }