Hi all. I'm new to eventghost and at this forum.
I'm sorry if this has been posted before. But I tried searching and nothing came up.
I'd like do an Anrdoid program of sending events to evenghost on my PC. Network Event Sender works perfectly for me on my laptop communicating to my desktop PC via eventghost. Has anybody got a code for the Network Event Sender in Java for Android?
Basically I want to write an Android App for my old Android 2.2 cellphone which is just gathering dust inside my drawer. I tried searching for applications on the store (including Evenghost for android) but they don't function the way I want it. My old Froyo phone has a broken touchscreen and has a built-in hardware QWERTY keyboard, but still working. and most, if not all, apps on the playstore requires newer Android builds and a working touchscreen. Few developers, if not none at all, develops for Android 2.2 anymore. So, I decided to learn to program an app for my Android cp. I'm still new with android programming, but I already know the basics of Activity and catching hardware keypresses, etc. The only thing missing for me right now is how to send an event to evenghost on my PC for a specific hardware key on my phone.
So, is there someome who has an implementation of the Network Event Sender plugin in Java for Android? It would be nice if it's a Public Method in a Public Class so I can just run a method of something like Network_Event_Sender_Class.Send_Event(string EventName, string Payload, string IPAddress, integer PortNumber, string Password) or something like that.
Thanks in advance.
Notice: This forum has been recovered from an old backup, so some content, links, and dates may be outdated. The forum is currently read-only while we restore sign-in and registration functionality. Details
If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.
If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.
Network Event Sender Code in Java for Android
-
lspatricio
- Posts: 5
- Joined: Sat Jul 04, 2015 3:42 am
Re: Network Event Sender Code in Java for Android
I figured I would post this for all to see since I haven't been able to work on the EventGhost for Android app in some time. I would love to get the app updated to current standards, but I may just put the source somewhere and hopefully someone else can get something more functional.
Here's the basics for sending an event to EventGhost:
Basically:
1. Open a socket with the correct port
2. Open an input and output stream
3. write bytes 'quintessence' to EG host
4. listen for response, creating an md5 of response:serverpass
5. send the md5 bytes back
6. if you can an 'accept' back, you can send your payload
As for receiving events, I created a mini-EG service which responds just like the server does when you send an event.
If you are interested for more on that or have any other questions, let me know.
Here's the basics for sending an event to EventGhost:
Code: Select all
private static int Send(String server, String port, String password, String event, String payload) {
if (event == null) {
return STATUS_NO_EVENT;
}
// if settings, hosts, or specified current host is not available,
// return nothing
Socket telnetSocket = null;
DataOutputStream os = null;
DataInputStream is = null;
try {
telnetSocket = new Socket(server, Integer.valueOf(port));
telnetSocket.setSoTimeout(5000);
os = new DataOutputStream(telnetSocket.getOutputStream());
is = new DataInputStream(telnetSocket.getInputStream());
} catch (UnknownHostException unknown) {
unknown.printStackTrace();
return STATUS_ERROR_UNKNOWNHOST;
} catch (ConnectException ce) {
return STATUS_ERROR_CONNECTION_REFUSED;
} catch (SocketException se) {
return STATUS_ERROR_TIMED_OUT;
} catch (Exception e) {
e.printStackTrace();
return STATUS_ERROR_COMMUNICATION;
}
if (telnetSocket != null && os != null && is != null) {
try {
// send request to EG
os.writeBytes("quintessence\n\r");
String responseLine = null;
// get cookie response from EG
responseLine = new String(is.readLine());
String cookie = responseLine + ":" + password;
String md5 = MD5Hex.MD5Hex(cookie);
// send cookie authentication back to EG
os.writeBytes(md5 + "\n");
// get response from EG
String accept = new String(is.readLine());
if (accept.equals("accept")) {
// Send all payloads (split with |)
if (payload != null && payload.length() > 0) {
String[] list = payload.split("\\|");
for (int i = 0; i < list.length; i++) {
String p = list[i];
os.writeBytes("payload " + p + "\n");
}
}
os.writeBytes(event + "\n");
Log.i(TAG, "Sent Event: " + event + " with payload: " + payload);
}
// clean up
os.writeBytes("close\n");
os.close();
is.close();
telnetSocket.close();
} catch (IOException e) {
e.printStackTrace();
return STATUS_ERROR_COMMUNICATION;
}
return STATUS_OK;
} else {
return STATUS_ERROR_COMMUNICATION;
}
}
1. Open a socket with the correct port
2. Open an input and output stream
3. write bytes 'quintessence' to EG host
4. listen for response, creating an md5 of response:serverpass
5. send the md5 bytes back
6. if you can an 'accept' back, you can send your payload
As for receiving events, I created a mini-EG service which responds just like the server does when you send an event.
If you are interested for more on that or have any other questions, let me know.
-
lspatricio
- Posts: 5
- Joined: Sat Jul 04, 2015 3:42 am
Re: Network Event Sender Code in Java for Android
Thank you very much for sharing your code! I really appreciate it.liquid8 wrote:I figured I would post this for all to see since I haven't been able to work on the EventGhost for Android app in some time. I would love to get the app updated to current standards, but I may just put the source somewhere and hopefully someone else can get something more functional.
Basically:
1. Open a socket with the correct port
2. Open an input and output stream
3. write bytes 'quintessence' to EG host
4. listen for response, creating an md5 of response:serverpass
5. send the md5 bytes back
6. if you can an 'accept' back, you can send your payload
As for receiving events, I created a mini-EG service which responds just like the server does when you send an event.
If you are interested for more on that or have any other questions, let me know.
yes, I tried your Android Eventghost but I can't create a new layout because my touchscreen is broken. I would like to use the hardware keyboard and dpad to send events to PC Eventghost. I needed this code. Can't wait to go home from work and try this out!
Many thanks.
-
lspatricio
- Posts: 5
- Joined: Sat Jul 04, 2015 3:42 am
Re: Network Event Sender Code in Java for Android
Got it working! After an hour of googling around for MD5, I was able to get it to work. Thank you very much for your help! It has given my old cp a new life as a PC remote control and wifi keyboard!liquid8 wrote:I figured I would post this for all to see since I haven't been able to work on the EventGhost for Android app in some time. I would love to get the app updated to current standards, but I may just put the source somewhere and hopefully someone else can get something more functional.
Here's the basics for sending an event to EventGhost:
Basically:
1. Open a socket with the correct port
2. Open an input and output stream
3. write bytes 'quintessence' to EG host
4. listen for response, creating an md5 of response:serverpass
5. send the md5 bytes back
6. if you can an 'accept' back, you can send your payload
As for receiving events, I created a mini-EG service which responds just like the server does when you send an event.
If you are interested for more on that or have any other questions, let me know.
Yes, please, if you could share your mini-EG service which responds just like the server, I would appreciate it very much. Thanks!
Re: Network Event Sender Code in Java for Android
Some of this might not be the best code or as well commented as it should be
Also keep in mind this was written for older Android versions (when I was still learning things) so it could probably be cleaned up quite a bit. I would rip some of this out to simplify it, but it might be helpful if someone wants to create a full fledged service.
The server is a service which listens on (I believe the first) available network connection it can. It listens with a MultiServer Thread which spawns of ClientConnection threads when a new connection is initiated. The run() part of the ClientConnection thread is where it responds (i.e. a Network Event Receiver) to connections.
1. On connection initiated, listen for 'quintessence\r\n'
2. Create a 'cookie' and send that to the client
3. Wait for response from client - compare it to the token md5('cookie:serverpass') and see if what they send matches
4. If it's valid, send 'accept' and wait for the event and payload
The server is a service which listens on (I believe the first) available network connection it can. It listens with a MultiServer Thread which spawns of ClientConnection threads when a new connection is initiated. The run() part of the ClientConnection thread is where it responds (i.e. a Network Event Receiver) to connections.
1. On connection initiated, listen for 'quintessence\r\n'
2. Create a 'cookie' and send that to the client
3. Wait for response from client - compare it to the token md5('cookie:serverpass') and see if what they send matches
4. If it's valid, send 'accept' and wait for the event and payload
Code: Select all
package com.timhoeck.android.eventghost;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Random;
import com.timhoeck.android.providers.eventghost.DBProvider;
import com.timhoeck.android.eventghost.EventGhostIntent.OutgoingEvent;
import com.timhoeck.android.framework.SecurityHelper;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class EventGhostService extends Service {
private static final String TAG = "EventGhost";
private static final int NOTIFICATION_SERVER_STATUS = 1;
// Broadcasts that we act upon
private static final String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
public static final String WIFI_STATE_CHANGED = "android.net.wifi.WIFI_STATE_CHANGED";
// Wifi States
public static final int WIFI_STATE_DISABLED = 1;
public static final int WIFI_STATE_ENABLED = 3;
public static final int WIFI_STATE_UNKNOWN = 4;
private static final boolean USE_EMULATOR_DEV_ADDRESS = false;
private final IBinder mBinder = new LocalBinder();
private InetAddress serverInetAddress;
MultiServerThread server;
ServerSocket serverSocket;
String serverPassword = "EG4Android!";
int serverPort = 1024;
Context mContext;
public static boolean startServer(Context context) {
Log.i(TAG, "Starting Server");
Intent start = new Intent();
start.setClass(context, EventGhostService.class);
if (context.startService(start) == null) {
//service was started
return false;
} else {
//service was already running
return true;
}
}
public static void stopServer(Context context) {
Log.i(TAG, "Stopping Server");
Intent stop = new Intent();
stop.setClass(context, EventGhostService.class);
context.stopService(stop);
context.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0).edit().putString(PreferencesActivity.KEY_SERVER_DETAILS, PreferencesActivity.SERVER_DETAILS_DISABLED).commit();
dismissNotification(context);
}
@Override
public void onStart(Intent intent, int startId) {
mContext = this.getBaseContext();
super.onStart(intent, startId);
SharedPreferences settings = mContext.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0);
if (settings.getBoolean(PreferencesActivity.KEY_ENABLE_SERVER, PreferencesActivity.KEY_ENABLE_SERVER_DEFAULT)) {
try {
serverPort = Integer.valueOf(settings.getString(PreferencesActivity.KEY_SERVER_PORT, PreferencesActivity.KEY_SERVER_PORT_DEFAULT));
} catch (Exception e){
serverPort = 1024;
}
String pw = settings.getString(PreferencesActivity.KEY_SERVER_PASSWORD, null);
if (pw != null) serverPassword = SecurityHelper.decrypt(pw); else serverPassword = PreferencesActivity.KEY_SERVER_PASSWORD_DEFAULT;
//start our server
serverInetAddress = getServerAddress();
try {
if (serverInetAddress != null) {
//If we have an availabled address, create a server socket
serverSocket = new ServerSocket(serverPort);
//serverSocket = new ServerSocket(serverPort, 10, serverInetAddress);
server = new MultiServerThread();
server.start();
//Find all addresses (IPv4/IPv6) associated with this interface
NetworkInterface n = NetworkInterface.getByInetAddress(serverInetAddress);
Enumeration<InetAddress> ips = n.getInetAddresses();
String ipString = "";
while (ips.hasMoreElements()) {
InetAddress i = ips.nextElement();
ipString += i.getHostAddress();
if (ips.hasMoreElements()) ipString += " / ";
}
Log.i(TAG, "Attempting to Bind on " + serverPort + " at address: " + ipString);
String details = "Listening on " + ipString + ", port " + serverPort;
mContext.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0).edit().putString(PreferencesActivity.KEY_SERVER_DETAILS, details).commit();
serverNotification(mContext, details);
} else {
Log.e(TAG, "Could not start server, no available InetAddress");
mContext.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0).edit().putString(PreferencesActivity.KEY_SERVER_DETAILS, PreferencesActivity.SERVER_DETAILS_DISABLED).commit();
}
} catch (Exception e) {
e.printStackTrace();
Log.w(TAG, "Error starting server (already running?)");
mContext.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0).edit().putString(PreferencesActivity.KEY_SERVER_DETAILS, PreferencesActivity.SERVER_DETAILS_DISABLED).commit();
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "EventGhost Service destroyed");
if (serverSocket != null) {
try {
mContext.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0).edit().putString(PreferencesActivity.KEY_SERVER_DETAILS, PreferencesActivity.SERVER_DETAILS_DISABLED).commit();
serverSocket.close();
} catch (IOException e) {
Log.w(TAG, "Unable to close server socket");
}
}
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
EventGhostService getService() {
return EventGhostService.this;
}
}
/**
* Searches network interfaces for available inet address
* @return If using the Emulator, it returns the internal ip, otherwise it looks for
* the first interface that is not the loopback
*/
public static InetAddress getServerAddress() {
try {
Enumeration<NetworkInterface> ni = NetworkInterface
.getNetworkInterfaces();
if (USE_EMULATOR_DEV_ADDRESS) {
return InetAddress.getByName("10.0.2.15");
} else {
// Find the appropriate network interface to bind to
while (ni.hasMoreElements()) {
NetworkInterface n = ni.nextElement();
Log.i(TAG, "Found network: " + n.getDisplayName());
Log.d(TAG, " Details: " + n.toString());
// we aren't interested in binding to localhost
if (!n.getDisplayName().equals("lo")) {
Enumeration<InetAddress> in = n.getInetAddresses();
while (in.hasMoreElements()) {
InetAddress i = in.nextElement();
Log.i(TAG, " IP: " + i.getHostAddress());
return i;
}
} else {
//Log.d(TAG, "Ignoring network: " + n.getDisplayName());
}
}
}
} catch (Exception e) {}
return null;
}
public static class ServiceStarter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences settings = context.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0);
if (settings.getBoolean(PreferencesActivity.KEY_ENABLE_SERVER, PreferencesActivity.KEY_ENABLE_SERVER_DEFAULT)) {
if (intent.getAction().equals(BOOT_COMPLETED)) {
startServer(context);
} else if (intent.getAction().equals(WIFI_STATE_CHANGED)) {
stopServer(context);
Log.i(TAG, "Received Wifi State Change, waiting for new network");
serverNotification(context, "Disabled, waiting for network connection");
int state = intent.getIntExtra("wifi_state",
WIFI_STATE_UNKNOWN);
if (state == WIFI_STATE_ENABLED) {
new ConnectivityWait().execute(context, true);
} else if (state == WIFI_STATE_DISABLED) {
//Log.i(TAG, "Received Wifi State Disabled, waiting for new network");
new ConnectivityWait().execute(context, false);
}
}
}
}
}
private static void dismissNotification(Context context) {
NotificationManager mgr = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
mgr.cancel(NOTIFICATION_SERVER_STATUS);
}
private static void serverNotification(Context context, String text) {
NotificationManager mgr = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification();
notification.flags = Notification.FLAG_ONGOING_EVENT;
notification.icon = R.drawable.icon_24;
Intent eg = new Intent();
eg.setClass(context, PreferencesActivity.class);
PendingIntent pending = PendingIntent.getActivity(context, 0, eg, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(context, "EventGhost Server", text, pending);
mgr.notify(NOTIFICATION_SERVER_STATUS, notification);
}
// Since WIFI_STATE_CHANGED doesn't confirm that the new network is active,
// we wait for it.
private static class ConnectivityWait extends
AsyncTask<Object, Integer, Object> {
@Override
protected Object doInBackground(Object... info) {
Context context = (Context) info[0];
boolean state = (Boolean) info[1];
return waitForConnectivity(context, state);
}
protected void onPostExecute(Object... result) {
// WHY ARE YOU NOT WORKING?!
Log.i(TAG, "ConnectivityWait finished");
}
}
private static boolean waitForConnectivity(Context context, boolean wifiState) {
try {
ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = null;
String currentNetwork = null;
int sleepTime = 0;
do {
Thread.sleep(3000);
sleepTime += 3000;
info = connMgr.getActiveNetworkInfo();
currentNetwork = info.getTypeName();
if (wifiState && currentNetwork.equals("WIFI")) break;
if (!wifiState && currentNetwork.equals("MOBILE")) break;
//Log.i(TAG, "Current Network: " + currentNetwork + ", Time: " + sleepTime / 1000 + "secs");
} while (sleepTime < 120000);
if (sleepTime < 120000) {
//we found a network, attempt to restart
Log.i(TAG, "Restarting Service due to Wifi change");
startServer(context);
} else {
serverNotification(context, "Disabled, timed out waiting for network");
context.getSharedPreferences(PreferencesActivity.PREFS_SETTINGS, 0).edit().putBoolean(PreferencesActivity.KEY_ENABLE_SERVER, false).commit();
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static void restartServer(Context context) {
// restart server
stopServer(context);
startServer(context);
}
/***
* The MultiServerThread waits for incoming connections.
* When one arrives, it spawns a ClientConnection thread to handle that connection.
* @author thoeck
*
*/
public class MultiServerThread extends Thread {
public void run() {
boolean listening = true;
try {
Log.i(TAG, "Listening on " + serverInetAddress.getHostAddress()
+ ":" + serverPort);
while (listening) {
new ClientConnection(serverSocket.accept(), serverPassword)
.start();
}
} catch (Exception e) {
e.printStackTrace();
Log.w(TAG, "MultiServerThread closed");
try {
serverSocket.close();
} catch (Exception e2) {
Log.w(TAG, "Unable to close server socket");
}
}
}
}
/***
* A new ClientConnection class is created each time a connection is initiated
* by a client to the server:port.
* @author thoeck
*
*/
public class ClientConnection extends Thread {
private Socket client;
private String serverPassword;
public ClientConnection(Socket client, String serverPassword) {
this.client = client;
this.serverPassword = serverPassword;
}
public void run() {
try {
client.setKeepAlive(true);
client.setSoTimeout(5000);
DataInputStream in = new DataInputStream(client
.getInputStream());
DataOutputStream out = null;
byte[] ping = new byte[14];
in.read(ping);
String str = new String(ping);
// Get Incoming Request from EventGhost
//Clients use the string 'quintessence' to initiate authentication with the server
if (str.equals("quintessence\n\r")) {
//EventGhost Servers send a generated authentication 'cookie' to the client
Random gen = new Random();
String cookie = String.valueOf(gen.nextInt(65536));
String token = cookie + ":" + serverPassword;
String expected = MD5Hex.MD5Hex(token);
out = new DataOutputStream(client.getOutputStream());
out.writeBytes(cookie + "\n");
//To authenticate, the EventGhost client will send a response to the cookie,
//which contains the cookie, plus the password to validate the password
String passResponse = new String(in.readLine());
String serverhost = client.getInetAddress().getHostAddress();
if (passResponse.equals(expected)) {
//password is valid
out.writeBytes("accept\n");
//wait for the event/payload
String line = new String(in.readLine());
//Log.d(TAG, "Got line: " + line);
String event;
String payload;
//if there is a payload, it's received first
if (line.startsWith("payload ")) {
payload = line.replace("payload ", "");
event = new String(in.readLine());
} else {
payload = null;
event = line;
}
//Log.i(TAG, "Received Event: " + event + ", sending GENERATE_EVENT broadcast");
//TODO FromApp shouldn't be server host
OutgoingEvent sendEvent = new OutgoingEvent()
.setEvent(event)
.setPayload(payload)
.setFromApp(serverhost);
EventGhostIntent.generateEvent(mContext, sendEvent);
} else {
//password is invalid
Log.w(TAG, "Cookie incorrect for connection");
LogsActivity.addLogEntry(mContext, DBProvider.LogValues.TYPE_EVENT_INCOMING, "N/A", "N/A", serverhost, "Invalid Password from Server", false);
//Log.w(TAG, "Expected:" + expected);
}
} else {
//If we didn't get 'quintessence', the connection was not initiated properly by the client
//Log.w(TAG, "Invalid authentication method");
//Log.w(TAG, "Expected: quintessence");
}
//notify the client we are closing the connection
if (out != null) {
out.writeBytes("close\n");
out.close();
}
//close the server connection
in.close();
} catch (Exception e) {
//something didn't go right
e.printStackTrace();
Log.w(TAG, "Error communicating with client");
} finally {
//close out the client connection
try {
client.close();
} catch (Exception e2) {
Log.w(TAG, "Unable to close server socket");
}
}
}
}
}
-
lspatricio
- Posts: 5
- Joined: Sat Jul 04, 2015 3:42 am
Re: Network Event Sender Code in Java for Android
Thanks for the fast reply!liquid8 wrote:Some of this might not be the best code or as well commented as it should beAlso keep in mind this was written for older Android versions (when I was still learning things) so it could probably be cleaned up quite a bit. I would rip some of this out to simplify it, but it might be helpful if someone wants to create a full fledged service.
The server is a service which listens on (I believe the first) available network connection it can. It listens with a MultiServer Thread which spawns of ClientConnection threads when a new connection is initiated. The run() part of the ClientConnection thread is where it responds (i.e. a Network Event Receiver) to connections.
1. On connection initiated, listen for 'quintessence\r\n'
2. Create a 'cookie' and send that to the client
3. Wait for response from client - compare it to the token md5('cookie:serverpass') and see if what they send matches
4. If it's valid, send 'accept' and wait for the event and payload