nymea-app/androidservice/java/io/guh/nymeaapp/NymeaAppServiceConnection.java

282 lines
11 KiB
Java

package io.guh.nymeaapp;
import java.util.List;
import java.util.ArrayList;
import java.util.UUID;
import java.util.HashMap;
import android.util.Log;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.ServiceConnection;
import android.content.ComponentName;
import android.content.Context;
import android.service.controls.Control;
import android.service.controls.DeviceTypes;
import io.reactivex.processors.ReplayProcessor;
import org.json.*;
// Helper class to establish a connection to the NymeaAppService and interact
// with that using IBinder and ServiceBroadcastListener
public class NymeaAppServiceConnection implements ServiceConnection {
private static final String TAG = "nymea-app: NymeaAppServiceConnection";
private IBinder m_service;
private Context m_context;
private boolean m_connected = false;
private HashMap<UUID, NymeaHost> m_nymeaHosts = new HashMap<UUID, NymeaHost>();
public NymeaAppServiceConnection(Context context) {
super();
m_context = context;
}
final public boolean connected() {
return m_connected;
}
public void onConnectedChanged(boolean connected) {};
final public boolean isReady(UUID nymeaId) {
return m_nymeaHosts.get(nymeaId).isReady;
}
public void onReadyChanged(UUID nymeaId, boolean ready) {}
public final HashMap<UUID, NymeaHost> getHosts() {
return m_nymeaHosts;
}
final public Thing getThing(UUID thingId) {
for (HashMap.Entry<UUID, NymeaHost> entry : m_nymeaHosts.entrySet()) {
Thing thing = entry.getValue().things.get(thingId);
if (thing != null) {
return thing;
}
}
return null;
}
final public UUID hostForThing(UUID thingId) {
for (HashMap.Entry<UUID, NymeaHost> entry : m_nymeaHosts.entrySet()) {
Thing thing = entry.getValue().things.get(thingId);
if (thing != null) {
return entry.getKey();
}
}
return null;
}
public void onError() {}
public void onUpdate(UUID nymeaId, UUID thingId) {}
final public void executeAction(UUID nymeaId, UUID thingId, UUID actionTypeId, String paramValue) {
try {
JSONObject params = new JSONObject();
params.put("nymeaId", nymeaId.toString());
params.put("thingId", thingId.toString());
params.put("actionTypeId", actionTypeId.toString());
JSONArray actionParams = new JSONArray();
JSONObject param = new JSONObject();
param.put("paramTypeId", actionTypeId.toString());
param.put("value", paramValue);
actionParams.put(param);
params.put("params", actionParams);
Parcel parcel = createRequest("ExecuteAction", params);
Parcel retParcel = Parcel.obtain();
m_service.transact(1, parcel, retParcel, 0);
} catch (Exception e) {
Log.d(TAG, "Error calling executeAction on NymeaAppService");
}
}
@Override public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "Connected to NymeaAppService");
m_service = service;
registerServiceBroadcastReceiver();
try {
Parcel parcel = createRequest("GetInstances");
Parcel retParcel = Parcel.obtain();
m_service.transact(1, parcel, retParcel, 0);
JSONObject reply = new JSONObject(retParcel.readString());
Log.d(TAG, "Instaces received: " + reply.toString());
JSONArray instances = reply.getJSONArray("instances");
for (int i = 0; i < instances.length(); i++) {
JSONObject instanceMap = instances.getJSONObject(i);
NymeaHost nymeaHost = new NymeaHost();
nymeaHost.id = UUID.fromString(instanceMap.getString("id"));
nymeaHost.name = instanceMap.getString("name");
nymeaHost.isReady = instanceMap.getBoolean("isReady");
m_nymeaHosts.put(nymeaHost.id, nymeaHost);
}
} catch (JSONException e) {
Log.d(TAG, "Error while processing JSON in communication with NymeaAppService: " + e.toString());
onError();
return;
} catch (RemoteException e) {
Log.d(TAG, "Error communicating with NymeaAppService: " + e.toString());
onError();
return;
}
m_connected = true;
onConnectedChanged(m_connected);
}
@Override public void onServiceDisconnected(ComponentName arg0) {
m_service = null;
for (int i = 0; i < m_nymeaHosts.size(); i++) {
m_nymeaHosts.get(i).isReady = false;
}
m_connected = false;
onConnectedChanged(m_connected);
}
public void registerServiceBroadcastReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(NymeaAppService.NYMEA_APP_BROADCAST);
m_context.registerReceiver(serviceMessageReceiver, intentFilter);
Log.d(TAG, "Registered broadcast receiver");
}
private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (NymeaAppService.NYMEA_APP_BROADCAST.equals(intent.getAction())) {
String payload = intent.getStringExtra("data");
try {
processBroadcast(payload);
} catch(JSONException e) {
Log.d(TAG, "Error parsing broadcast JSON: " + e.toString());
}
}
}
};
private void processBroadcast(String payload) throws JSONException
{
JSONObject data = new JSONObject(payload);
JSONObject params = data.getJSONObject("params");
// Log.d(TAG, "Broadcast received from NymeaAppService: " + data.getString("notification"));
Log.d(TAG, params.toString());
if (data.getString("notification").equals("ThingStateChanged")) {
UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
UUID thingId = UUID.fromString(params.getString("thingId"));
UUID stateTypeId = UUID.fromString(params.getString("stateTypeId"));
String value = params.getString("value");
// Log.d(TAG, "Thing state changed: " + thingId + " stateTypeId: " + stateTypeId + " value: " + value);
Thing thing = getThing(thingId);
if (thing != null) {
thing.stateById(stateTypeId).value = value;
onUpdate(nymeaId, thingId);
} else {
Log.d(TAG, "Got a state change notification for a thing we don't know!");
}
}
if (data.getString("notification").equals("ReadyStateChanged")) {
UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
NymeaHost host = m_nymeaHosts.get(nymeaId);
host.isReady = params.getBoolean("isReady");
if (host.isReady) {
Log.d(TAG, "Host is ready. Fetching things...");
fetchThings(nymeaId);
} else {
Log.d(TAG, "Host is not ready yet...");
}
}
}
private void fetchThings(UUID nymeaId) {
Log.d(TAG, "Fetching things");
String thingsList;
try {
JSONObject params = new JSONObject();
params.put("nymeaId", nymeaId.toString());
Parcel parcel = createRequest("GetThings", params);
Parcel retParcel = Parcel.obtain();
m_service.transact(1, parcel, retParcel, 0);
thingsList = retParcel.readString();
} catch (Exception e) {
Log.d(TAG, "Error fetching things from NymeaAppService: " + e.toString());
onError();
return;
}
try {
JSONObject result = new JSONObject(thingsList);
for (int i = 0; i < result.getJSONArray("things").length(); i++) {
JSONObject entry = result.getJSONArray("things").getJSONObject(i);
Thing thing = new Thing();
thing.id = UUID.fromString(entry.getString("id"));
thing.name = entry.getString("name");
thing.className = entry.getString("className");
JSONArray ifaces = entry.getJSONArray("interfaces");
for (int j = 0; j < ifaces.length(); j++) {
thing.interfaces.add(ifaces.get(j));
}
JSONArray states = entry.getJSONArray("states");
for (int j = 0; j < states.length(); j++) {
JSONObject stateMap = states.getJSONObject(j);
State s = new State();
s.typeId = UUID.fromString(stateMap.getString("stateTypeId"));
s.name = stateMap.getString("name");
s.displayName = stateMap.getString("displayName");
s.value = stateMap.getString("value");
thing.states.add(s);
}
JSONArray actions = entry.getJSONArray("actions");
for (int j = 0; j < actions.length(); j++) {
JSONObject actionMap = actions.getJSONObject(j);
Action a = new Action();
a.typeId = UUID.fromString(actionMap.getString("actionTypeId"));
a.name = actionMap.getString("name");
a.displayName = actionMap.getString("displayName");
thing.actions.add(a);
}
m_nymeaHosts.get(nymeaId).things.put(thing.id, thing);
}
} catch (Exception e) {
Log.d(TAG, "Error parsing JSON from NymeaAppService: " + e.toString());
Log.d(TAG, thingsList);
m_service = null;
onError();
return;
}
Log.d(TAG, "Things fetched: " + m_nymeaHosts.get(nymeaId).things.size());
m_nymeaHosts.get(nymeaId).isReady = true;
onReadyChanged(nymeaId, true);
}
private Parcel createRequest(String method) throws JSONException {
return createRequest(method, null);
}
private Parcel createRequest(String method, JSONObject params) throws JSONException {
Parcel ret = Parcel.obtain();
JSONObject payload = new JSONObject();
payload.put("method", method);
if (params != null) {
payload.put("params", params);
}
Log.d(TAG, "Parcel payload: " + payload.toString());
ret.writeString(payload.toString());
return ret;
}
}