Skip to content

Instantly share code, notes, and snippets.

@Tolriq
Created August 18, 2012 17:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tolriq/3388636 to your computer and use it in GitHub Desktop.
Save Tolriq/3388636 to your computer and use it in GitHub Desktop.
EventClient
package org.leetzone.android.yatselibs.client.xbmceden;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Stack;
import org.leetzone.android.utils.Logger;
import org.leetzone.android.yatselibs.client.xbmceden.eventclient.Packet;
import org.leetzone.android.yatselibs.client.xbmceden.eventclient.PacketACTION;
import org.leetzone.android.yatselibs.client.xbmceden.eventclient.PacketBUTTON;
import org.leetzone.android.yatselibs.client.xbmceden.eventclient.PacketLOG;
import org.leetzone.android.yatselibs.client.xbmceden.eventclient.PacketMOUSE;
import org.leetzone.android.yatselibs.client.xbmceden.eventclient.PacketNOTIFICATION;
import org.leetzone.android.yatselibs.client.xbmceden.eventclient.PacketPING;
/**
* XBMC Event Client Class
*
* Implements an XBMC-Client. This class can be used to implement your own
* application which should act as a Input device for XBMC. Also starts a
* Ping-Thread, which tells the XBMC EventServer that the client is alive.
* Therefore if you close your application you SHOULD call stopClient()!
*
* 03.09.2009 freezy changed class name and member variables
*
* @author Stefan Agner
*/
public class EventClient {
private final static String TAG = "Xbmc-EventClient";
private boolean mHasIcon = false;
private byte mIconType = Packet.ICON_NONE;
private byte[] mIconData;
// private InetAddress mHostAddress;
private String mHostName;
private int mHostPort;
private final PacketQueue mPacketQueue = new PacketQueue();
private final Thread mPacketSenderThread = new Thread(new packetSenderManager());
public void Stop() {
try {
synchronized (mPacketQueue.packetRefs) {
mPacketQueue.packetRefs.clear();
}
mPacketSenderThread.interrupt();
} catch (Exception e) {
}
}
private void SendPacket(Packet p, String host, int port) {
PacketData packetdata = new PacketData();
packetdata.packet = p;
packetdata.host = host;
packetdata.port = port;
synchronized (mPacketQueue.packetRefs) {
mPacketQueue.packetRefs.push(packetdata);
mPacketQueue.packetRefs.notifyAll();
}
// Start thread if it's not started yet
if (mPacketSenderThread.getState() == Thread.State.NEW)
mPacketSenderThread.start();
}
/**
* Starts a XBMC EventClient without an icon.
*
* @param hostAddress
* Address of the Host running XBMC
* @param hostPort
* Port of the Host running XBMC (default 9777)
* @param deviceName
* Name of the Device
* @throws IOException
*/
public EventClient(String hostName, int hostPort) {
Logger.Verbose(TAG, "EventClient(" + hostName + ", " + hostPort + ")");
setHost(hostName, hostPort);
}
/**
* Starts a XBMC EventClient.
*
* @param hostAddress
* Address of the Host running XBMC
* @param hostPort
* Port of the Host running XBMC (default 9777)
* @param deviceName
* Name of the Device
* @param iconFile
* Path to the Iconfile (PNG, JPEG or GIF)
* @throws IOException
*/
public EventClient(String hostName, int hostPort, String iconFile) {
Logger.Verbose(TAG, "EventClient(" + hostName + ", " + hostPort + ", " + ", " + iconFile
+ ")");
setIcon(iconFile);
setHost(hostName, hostPort);
}
/**
* Starts a XBMC EventClient.
*
* @param hostAddress
* Address of the Host running XBMC
* @param hostPort
* Port of the Host running XBMC (default 9777)
* @param deviceName
* Name of the Device
* @param iconType
* Type of the icon file (see Packet.ICON_PNG, Packet.ICON_JPEG
* or Packet.ICON_GIF)
* @param iconData
* The icon itself as a Byte-Array
* @throws IOException
*/
public EventClient(String hostName, int hostPort, byte iconType, byte[] iconData) {
Logger.Verbose(TAG, "EventClient(" + hostName + ", " + hostPort + ", " + iconType + ", "
+ iconData + ")");
setIcon(iconType, iconData);
setHost(hostName, hostPort);
}
public void setHost(String host, int port) {
if (host != null) {
Logger.Verbose(TAG, "Setting mHostName = " + host);
mHostName = host;
mHostPort = port;
} else {
Logger.Error(TAG, "Setting null host!");
mHostName = null;
}
}
/**
* Sets the icon using a path name to a image file (png, jpg or gif).
*
* @param iconPath
* Path to icon
*/
public void setIcon(String iconPath) {
byte iconType = Packet.ICON_PNG;
// Assume png as icon type
if (iconPath.toLowerCase().endsWith(".jpeg"))
iconType = Packet.ICON_JPEG;
if (iconPath.toLowerCase().endsWith(".jpg"))
iconType = Packet.ICON_JPEG;
if (iconPath.toLowerCase().endsWith(".gif"))
iconType = Packet.ICON_GIF;
// Read the icon file to the byte array...
FileInputStream iconFileStream;
byte[] iconData;
try {
iconFileStream = new FileInputStream(iconPath);
iconData = new byte[iconFileStream.available()];
iconFileStream.read(iconData);
iconFileStream.close();
} catch (IOException e) {
mHasIcon = false;
return;
}
mHasIcon = true;
setIcon(iconType, iconData);
}
/**
* Sets the icon from raw data
*
* @param iconType
* Type of the icon file (see Packet.ICON_PNG, Packet.ICON_JPEG
* or Packet.ICON_GIF)
* @param iconData
* The icon itself as a Byte-Array
*/
public void setIcon(byte iconType, byte[] iconData) {
mIconType = iconType;
mIconData = iconData;
}
/**
* Displays a notification window in XBMC.
*
* @param title
* Message title
* @param message
* The actual message
*/
public void sendNotification(String title, String message) {
PacketNOTIFICATION p;
if (mHasIcon)
p = new PacketNOTIFICATION(title, message, mIconType, mIconData);
else
p = new PacketNOTIFICATION(title, message);
SendPacket(p, mHostName, mHostPort);
}
public void sendNotification(String title, String message, byte icontype, byte[] icondata) {
PacketNOTIFICATION p = new PacketNOTIFICATION(title, message, icontype, icondata);
SendPacket(p, mHostName, mHostPort);
}
/**
* Sends a Button event
*
* @param code
* Raw button code (default: 0)
* @param repeat
* This key press should repeat until released (default: 1) Note
* that queued pressed cannot repeat.
* @param down
* If this is 1, it implies a press event, 0 implies a release
* event. (default: 1)
* @param queue
* A queued key press means that the button event is executed
* just once after which the next key press is processed. It can
* be used for macros. Currently there is no support for time
* delays between queued presses. (default: 0)
* @param amount
* Unimplemented for now; in the future it will be used for
* specifying magnitude of analog key press events
* @param axis
*/
public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount,
byte axis) {
Logger.Verbose(TAG, "sendButton(" + code + ", " + (repeat ? "rep, " : "nonrep, ")
+ (down ? "down)" : "up)"));
PacketBUTTON p = new PacketBUTTON(code, repeat, down, queue, amount, axis);
SendPacket(p, mHostName, mHostPort);
}
public void sendvKey(short code) {
Logger.Verbose(TAG, "sendvKey(" + code + ")");
PacketBUTTON p = new PacketBUTTON(code);
SendPacket(p, mHostName, mHostPort);
}
/**
* Sends a Button event
*
* @param map_name
* A combination of map_name and button_name refers to a mapping
* in the user's Keymap.xml or Lircmap.xml. map_name can be one
* of the following:
* <ul>
* <li><code>KB</code> - Standard keyboard map (
* <code>&lt;keyboard&gt;</code> section)</li>
* <li><code>XG</code> - Xbox gamepad map (
* <code>&lt;gamepad&gt;</code> section)</li>
* <li><code>R1</code> - Xbox remote map (
* <code>&lt;remote&gt;</code> section)</li>
* <li><code>R2</code> - Xbox universal remote map (
* <code>&lt;universalremote&gt;</code> section)</li>
* <li><code>LI:devicename</code> - LIRC remote map where
* <code>devicename</code> is the actual device's name</li>
* </ul>
* @param button_name
* A button name defined in the map specified in map_name. For
* example, if map_name is "KB" refering to the <keyboard>
* section in Keymap.xml then, valid button_names include
* "printscreen", "minus", "x", etc.
* @param repeat
* This key press should repeat until released (default: 1) Note
* that queued pressed cannot repeat.
* @param down
* If this is 1, it implies a press event, 0 implies a release
* event. (default: 1)
* @param queue
* A queued key press means that the button event is executed
* just once after which the next key press is processed. It can
* be used for macros. Currently there is no support for time
* delays between queued presses. (default: 0)
* @param amount
* Unimplemented for now; in the future it will be used for
* specifying magnitude of analog key press events
* @param axis
*/
public void sendButton(String map_name, String button_name, boolean repeat, boolean down,
boolean queue, short amount, byte axis) {
Logger.Verbose(TAG, "sendButton(" + map_name + ", \"" + button_name + "\", "
+ (repeat ? "rep, " : "nonrep, ") + (down ? "down)" : "up)"));
ping();
PacketBUTTON p = new PacketBUTTON(map_name, button_name, repeat, down, queue, amount, axis);
SendPacket(p, mHostName, mHostPort);
}
/**
* Sets the mouse position in XBMC
*
* @param x
* Horizontal position ranging from 0 to 65535
* @param y
* Vertical position ranging from 0 to 65535
*/
public void sendMouse(int x, int y) {
PacketMOUSE p = new PacketMOUSE(x, y);
SendPacket(p, mHostName, mHostPort);
}
/**
* Sends a ping to the XBMC EventServer
*
* @throws IOException
*/
public void ping() {
PacketPING p = new PacketPING();
SendPacket(p, mHostName, mHostPort);
}
/**
* Tells XBMC to log the message to xbmc.log with the loglevel as specified.
*
* @param loglevel
* The log level, follows XBMC standard.
* <ul>
* <li>0 = DEBUG</li>
* <li>1 = INFO</li>
* <li>2 = NOTICE</li>
* <li>3 = WARNING</li>
* <li>4 = ERROR</li>
* <li>5 = SEVERE</li>
* </ul>
* @param logmessage
* The message to log
*/
public void sendLog(byte loglevel, String logmessage) {
PacketLOG p = new PacketLOG(loglevel, logmessage);
SendPacket(p, mHostName, mHostPort);
}
/**
* Tells XBMC to do the action specified, based on the type it knows were it
* needs to be sent.
*
* @param actionmessage
* Actionmessage (as in scripting/skinning)
*/
public void sendAction(String actionmessage) {
PacketACTION p = new PacketACTION(actionmessage);
SendPacket(p, mHostName, mHostPort);
}
private class PacketQueue {
private Stack<PacketData> packetRefs = new Stack<PacketData>();
}
private class PacketData {
Packet packet;
String host;
int port;
}
private class packetSenderManager implements Runnable {
@Override
public void run() {
try {
while (true) {
if (mPacketQueue.packetRefs.size() == 0) {
synchronized (mPacketQueue.packetRefs) {
mPacketQueue.packetRefs.wait();
}
}
if (mPacketQueue.packetRefs.size() != 0) {
PacketData packetdata;
synchronized (mPacketQueue.packetRefs) {
packetdata = mPacketQueue.packetRefs.pop();
}
InetAddress addr;
try {
addr = InetAddress.getByName(packetdata.host);
} catch (Exception e) {
Logger.Warning(TAG, "Error sending packet host not set or resolved");
continue;
}
packetdata.packet.send(addr, packetdata.port);
}
if (Thread.interrupted())
break;
}
} catch (InterruptedException e) {
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment