Add support for using EventServer in remote d-pad
This commit is contained in:
commit
0563e80fe9
|
@ -91,4 +91,8 @@ public interface Settings {
|
|||
// Current host id
|
||||
public static final String KEY_PREF_CURRENT_HOST_ID = "current_host_id";
|
||||
public static final int DEFAULT_PREF_CURRENT_HOST_ID = -1;
|
||||
|
||||
public static final String KEY_PREF_CHECKED_EVENT_SERVER_CONNECTION = "checked_event_server_connection";
|
||||
public static final boolean DEFAULT_PREF_CHECKED_EVENT_SERVER_CONNECTION = false;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2009 Team XBMC
|
||||
* http://xbmc.org
|
||||
*
|
||||
* This Program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This Program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with XBMC Remote; see the file license. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
|
||||
/**
|
||||
* Remote control and keyboard strings, taken from xbmc/ButtonTranslator.cpp
|
||||
*
|
||||
* @author Team XBMC
|
||||
*/
|
||||
public final class ButtonCodes {
|
||||
/**
|
||||
* "KB" => standard keyboard map ( <keyboard> section )
|
||||
* "XG" => xbox gamepad map ( <gamepad> section )
|
||||
* "R1" => xbox remote map ( <remote> section )
|
||||
* "R2" => xbox universal remote map ( <universalremote> section )
|
||||
* "LI:devicename" => LIRC remote map where 'devicename' is the actual device's name
|
||||
*/
|
||||
public static final String MAP_KEYBOARD = "KB";
|
||||
public static final String MAP_GAMEPAD = "XG";
|
||||
public static final String MAP_REMOTE = "R1";
|
||||
public static final String MAP_UNIVERSAL_REMOTE = "R2";
|
||||
|
||||
public static final String REMOTE_LEFT = "left";
|
||||
public static final String REMOTE_RIGHT = "right";
|
||||
public static final String REMOTE_UP = "up";
|
||||
public static final String REMOTE_DOWN = "down";
|
||||
public static final String REMOTE_SELECT = "select";
|
||||
public static final String REMOTE_BACK = "back";
|
||||
public static final String REMOTE_MENU = "menu";
|
||||
public static final String REMOTE_INFO = "info";
|
||||
public static final String REMOTE_DISPLAY = "display";
|
||||
public static final String REMOTE_TITLE = "title";
|
||||
public static final String REMOTE_PLAY = "play";
|
||||
public static final String REMOTE_PAUSE = "pause";
|
||||
public static final String REMOTE_REVERSE = "reverse";
|
||||
public static final String REMOTE_FORWARD = "forward";
|
||||
public static final String REMOTE_SKIP_PLUS = "skipplus";
|
||||
public static final String REMOTE_SKIP_MINUS = "skipminus";
|
||||
public static final String REMOTE_STOP = "stop";
|
||||
public static final String REMOTE_0 = "zero";
|
||||
public static final String REMOTE_1 = "one";
|
||||
public static final String REMOTE_2 = "two";
|
||||
public static final String REMOTE_3 = "three";
|
||||
public static final String REMOTE_4 = "four";
|
||||
public static final String REMOTE_5 = "five";
|
||||
public static final String REMOTE_6 = "six";
|
||||
public static final String REMOTE_7 = "seven";
|
||||
public static final String REMOTE_8 = "eight";
|
||||
public static final String REMOTE_9 = "nine";
|
||||
// additional keys from the media center extender for xbox remote
|
||||
public static final String REMOTE_POWER = "power";
|
||||
public static final String REMOTE_MY_TV = "mytv";
|
||||
public static final String REMOTE_MY_MUSIC = "mymusic";
|
||||
public static final String REMOTE_MY_PICTURES = "mypictures";
|
||||
public static final String REMOTE_MY_VIDEOS = "myvideo";
|
||||
public static final String REMOTE_RECORD = "record";
|
||||
public static final String REMOTE_START = "start";
|
||||
public static final String REMOTE_VOLUME_PLUS = "volumeplus";
|
||||
public static final String REMOTE_VOLUME_MINUS = "volumeminus";
|
||||
public static final String REMOTE_CHANNEL_PLUS = "channelplus";
|
||||
public static final String REMOTE_CHANNEL_MINUS = "channelminus";
|
||||
public static final String REMOTE_PAGE_PLUS = "pageplus";
|
||||
public static final String REMOTE_PAGE_MINUS = "pageminus";
|
||||
public static final String REMOTE_MUTE = "mute";
|
||||
public static final String REMOTE_RECORDED_TV = "recordedtv";
|
||||
public static final String REMOTE_GUIDE = "guide";
|
||||
public static final String REMOTE_LIVE_TV = "livetv";
|
||||
public static final String REMOTE_STAR = "star";
|
||||
public static final String REMOTE_HASH = "hash";
|
||||
public static final String REMOTE_CLEAR = "clear";
|
||||
public static final String REMOTE_ENTER = "enter";
|
||||
public static final String REMOTE_XBOX = "xbox";
|
||||
|
||||
public static final String KEYBOARD_RETURN = "return";
|
||||
public static final String KEYBOARD_ENTER = "enter";
|
||||
public static final String KEYBOARD_ESCAPE = "escape";
|
||||
public static final String KEYBOARD_ESC = "esc";
|
||||
public static final String KEYBOARD_TAB = "tab";
|
||||
public static final String KEYBOARD_SPACE = "space";
|
||||
public static final String KEYBOARD_LEFT = "left";
|
||||
public static final String KEYBOARD_RIGHT = "right";
|
||||
public static final String KEYBOARD_UP = "up";
|
||||
public static final String KEYBOARD_DOWN = "down";
|
||||
public static final String KEYBOARD_INSERT = "insert";
|
||||
public static final String KEYBOARD_DELETE = "delete";
|
||||
public static final String KEYBOARD_HOME = "home";
|
||||
public static final String KEYBOARD_END = "end";
|
||||
public static final String KEYBOARD_F1 = "f1";
|
||||
public static final String KEYBOARD_F2 = "f2";
|
||||
public static final String KEYBOARD_F3 = "f3";
|
||||
public static final String KEYBOARD_F4 = "f4";
|
||||
public static final String KEYBOARD_F5 = "f5";
|
||||
public static final String KEYBOARD_F6 = "f6";
|
||||
public static final String KEYBOARD_F7 = "f7";
|
||||
public static final String KEYBOARD_F8 = "f8";
|
||||
public static final String KEYBOARD_F9 = "f9";
|
||||
public static final String KEYBOARD_F10 = "f10";
|
||||
public static final String KEYBOARD_F11 = "f11";
|
||||
public static final String KEYBOARD_F12 = "f12";
|
||||
public static final String KEYBOARD_NUMPAD_ZERO = "numpadzero";
|
||||
public static final String KEYBOARD_NUMPAD_1 = "numpadone";
|
||||
public static final String KEYBOARD_NUMPAD_2 = "numpadtwo";
|
||||
public static final String KEYBOARD_NUMPAD_3 = "numpadthree";
|
||||
public static final String KEYBOARD_NUMPAD_4 = "numpadfour";
|
||||
public static final String KEYBOARD_NUMPAD_5 = "numpadfive";
|
||||
public static final String KEYBOARD_NUMPAD_6 = "numpadsix";
|
||||
public static final String KEYBOARD_NUMPAD_7 = "numpadseven";
|
||||
public static final String KEYBOARD_NUMPAD_8 = "numpadeight";
|
||||
public static final String KEYBOARD_NUMPAD_9 = "numpadnine";
|
||||
public static final String KEYBOARD_NUMPAD_TIMES = "numpadtimes";
|
||||
public static final String KEYBOARD_NUMPAD_PLUS = "numpadplus";
|
||||
public static final String KEYBOARD_NUMPAD_MINUS = "numpadminus";
|
||||
public static final String KEYBOARD_NUMPAD_PERIOD = "numpadperiod";
|
||||
public static final String KEYBOARD_NUMPAD_DIVIDE = "numpaddivide";
|
||||
public static final String KEYBOARD_PAGEUP = "pageup";
|
||||
public static final String KEYBOARD_PAGEDOWN = "pagedown";
|
||||
public static final String KEYBOARD_PRINTSCREEN = "printscreen";
|
||||
public static final String KEYBOARD_BACKSPACE = "backspace";
|
||||
public static final String KEYBOARD_MENU = "menu";
|
||||
public static final String KEYBOARD_PAUSE = "pause";
|
||||
public static final String KEYBOARD_LEFTSHIFT = "leftshift";
|
||||
public static final String KEYBOARD_RIGHTSHIFT = "rightshift";
|
||||
public static final String KEYBOARD_LEFTCTRL = "leftctrl";
|
||||
public static final String KEYBOARD_RIGHTCTRL = "rightctrl";
|
||||
public static final String KEYBOARD_LEFTALT = "leftalt";
|
||||
public static final String KEYBOARD_RIGHTALT = "rightalt";
|
||||
public static final String KEYBOARD_LEFTWINDOWS = "leftwindows";
|
||||
public static final String KEYBOARD_RIGHTWINDOWS = "rightwindows";
|
||||
public static final String KEYBOARD_CAPSLOCK = "capslock";
|
||||
public static final String KEYBOARD_NUMLOCK = "numlock";
|
||||
public static final String KEYBOARD_SCROLLLOCK = "scrolllock";
|
||||
public static final String KEYBOARD_SEMICOLON = "semicolon";
|
||||
public static final String KEYBOARD_COLON = "colon";
|
||||
public static final String KEYBOARD_EQUALS = "equals";
|
||||
public static final String KEYBOARD_PLUS = "plus";
|
||||
public static final String KEYBOARD_COMMA = "comma";
|
||||
public static final String KEYBOARD_LESSTHAN = "lessthan";
|
||||
public static final String KEYBOARD_MINUS = "minus";
|
||||
public static final String KEYBOARD_UNDERLINE = "underline";
|
||||
public static final String KEYBOARD_PERIOD = "period";
|
||||
public static final String KEYBOARD_GREATERTHAN = "greaterthan";
|
||||
public static final String KEYBOARD_FORWARDSLASH = "forwardslash";
|
||||
public static final String KEYBOARD_QUESTIONMARK = "questionmark";
|
||||
public static final String KEYBOARD_LEFTQUOTE = "leftquote";
|
||||
public static final String KEYBOARD_TILDE = "tilde";
|
||||
public static final String KEYBOARD_OPENSQUAREBRACKET = "opensquarebracket";
|
||||
public static final String KEYBOARD_OPENBRACE = "openbrace";
|
||||
public static final String KEYBOARD_BACKSLASH = "backslash";
|
||||
public static final String KEYBOARD_PIPE = "pipe";
|
||||
public static final String KEYBOARD_CLOSESQUAREBRACKET = "closesquarebracket";
|
||||
public static final String KEYBOARD_CLOSEBRACE = "closebrace";
|
||||
public static final String KEYBOARD_QUOTE = "quote";
|
||||
public static final String KEYBOARD_DOUBLEQUOTE = "doublequote";
|
||||
public static final String KEYBOARD_LAUNCH_MAIL = "launch_mail";
|
||||
public static final String KEYBOARD_BROWSER_HOME = "browser_home";
|
||||
public static final String KEYBOARD_BROWSER_FAVORITES = "browser_favorites";
|
||||
public static final String KEYBOARD_BROWSER_REFRESH = "browser_refresh";
|
||||
public static final String KEYBOARD_BROWSER_SEARCH = "browser_search";
|
||||
public static final String KEYBOARD_LAUNCH_APP1_PC_ICON = "launch_app1_pc_icon";
|
||||
public static final String KEYBOARD_LAUNCH_MEDIA_SELECT = "launch_media_select";
|
||||
public static final String KEYBOARD_PLAY_PAUSE = "play_pause";
|
||||
public static final String KEYBOARD_STOP = "stop";
|
||||
public static final String KEYBOARD_VOLUME_UP = "volume_up";
|
||||
public static final String KEYBOARD_VOLUME_MUTE = "volume_mute";
|
||||
public static final String KEYBOARD_VOLUME_DOWN = "volume_down";
|
||||
public static final String KEYBOARD_PREV_TRACK = "prev_track";
|
||||
public static final String KEYBOARD_NEXT_TRACK = "next_track";
|
||||
|
||||
public static final String GAMEPAD_LEFT_ANALOG_TRIGGER = "leftanalogtrigger";
|
||||
public static final String GAMEPAD_RIGHT_ANALOG_TRIGGER = "rightanalogtrigger";
|
||||
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* 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()!
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class EventClient
|
||||
{
|
||||
private boolean hasIcon = false;
|
||||
private String deviceName;
|
||||
private PingThread oPingThread;
|
||||
private byte iconType = Packet.ICON_PNG;
|
||||
private byte[] iconData;
|
||||
private InetAddress hostAddress;
|
||||
private int 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(InetAddress hostAddress, int hostPort, String deviceName, String iconFile) throws IOException
|
||||
{
|
||||
byte iconType = Packet.ICON_PNG;
|
||||
// Assume png as icon type
|
||||
if(iconFile.toLowerCase().endsWith(".jpeg"))
|
||||
iconType = Packet.ICON_JPEG;
|
||||
if(iconFile.toLowerCase().endsWith(".jpg"))
|
||||
iconType = Packet.ICON_JPEG;
|
||||
if(iconFile.toLowerCase().endsWith(".gif"))
|
||||
iconType = Packet.ICON_GIF;
|
||||
|
||||
// Read the icon file to the byte array...
|
||||
FileInputStream iconFileStream = new FileInputStream(iconFile);
|
||||
byte[] iconData = new byte[iconFileStream.available()];
|
||||
iconFileStream.read(iconData);
|
||||
|
||||
hasIcon = true;
|
||||
|
||||
// Call start-Method...
|
||||
startClient(hostAddress, hostPort, deviceName, iconType, iconData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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(InetAddress hostAddress, int hostPort, String deviceName, byte iconType, byte[] iconData) throws IOException
|
||||
{
|
||||
hasIcon = true;
|
||||
startClient(hostAddress, hostPort, deviceName, iconType, iconData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(InetAddress hostAddress, int hostPort, String deviceName) throws IOException
|
||||
{
|
||||
hasIcon = false;
|
||||
byte iconType = Packet.ICON_NONE;
|
||||
byte[] iconData = null;
|
||||
startClient(hostAddress, hostPort, deviceName, iconType, iconData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
private void startClient(InetAddress hostAddress, int hostPort, String deviceName, byte iconType, byte[] iconData) throws IOException
|
||||
{
|
||||
// Save host address and port
|
||||
this.hostAddress = hostAddress;
|
||||
this.hostPort = hostPort;
|
||||
this.deviceName = deviceName;
|
||||
|
||||
this.iconType = iconType;
|
||||
this.iconData = iconData;
|
||||
|
||||
// Send Hello Packet...
|
||||
PacketHELO p;
|
||||
if(hasIcon)
|
||||
p = new PacketHELO(deviceName, iconType, iconData);
|
||||
else
|
||||
p = new PacketHELO(deviceName);
|
||||
|
||||
p.send(hostAddress, hostPort);
|
||||
|
||||
// Start Thread (for Ping packets...)
|
||||
oPingThread = new PingThread(hostAddress, hostPort, 20000);
|
||||
oPingThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the XBMC EventClient (especially the Ping-Thread)
|
||||
* @throws IOException
|
||||
*/
|
||||
public void stopClient() throws IOException
|
||||
{
|
||||
// Stop Ping-Thread...
|
||||
oPingThread.giveup();
|
||||
oPingThread.interrupt();
|
||||
|
||||
PacketBYE p = new PacketBYE();
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays a notification window in XBMC.
|
||||
* @param title Message title
|
||||
* @param message The actual message
|
||||
*/
|
||||
public void sendNotification(String title, String message) throws IOException
|
||||
{
|
||||
PacketNOTIFICATION p;
|
||||
if(hasIcon)
|
||||
p = new PacketNOTIFICATION(title, message, iconType, iconData);
|
||||
else
|
||||
p = new PacketNOTIFICATION(title, message);
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) throws IOException
|
||||
{
|
||||
PacketBUTTON p = new PacketBUTTON(code, repeat, down, queue, amount, axis);
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>"KB" => standard keyboard map ( <keyboard> section )</li>
|
||||
* <li>"XG" => xbox gamepad map ( <gamepad> section )</li>
|
||||
* <li>"R1" => xbox remote map ( <remote> section )</li>
|
||||
* <li>"R2" => xbox universal remote map ( <universalremote> section )</li>
|
||||
* <li>"LI:devicename" => LIRC remote map where 'devicename' 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) throws IOException
|
||||
{
|
||||
PacketBUTTON p = new PacketBUTTON(map_name, button_name, repeat, down, queue, amount, axis);
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mouse position in XBMC
|
||||
* @param x horitontal position ranging from 0 to 65535
|
||||
* @param y vertical position ranging from 0 to 65535
|
||||
*/
|
||||
public void sendMouse(int x, int y) throws IOException
|
||||
{
|
||||
PacketMOUSE p = new PacketMOUSE(x, y);
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a ping to the XBMC EventServer
|
||||
* @throws IOException
|
||||
*/
|
||||
public void ping() throws IOException
|
||||
{
|
||||
PacketPING p = new PacketPING();
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells XBMC to log the message to xbmc.log with the loglevel as specified.
|
||||
* @param loglevel the loglevel, 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) throws IOException
|
||||
{
|
||||
PacketLOG p = new PacketLOG(loglevel, logmessage);
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) throws IOException
|
||||
{
|
||||
PacketACTION p = new PacketACTION(actionmessage);
|
||||
p.send(hostAddress, hostPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a PingThread which tells XBMC EventServer that the Client is alive (this should
|
||||
* be done at least every 60 seconds!
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
class PingThread extends Thread
|
||||
{
|
||||
private InetAddress hostAddress;
|
||||
private int hostPort;
|
||||
private int sleepTime;
|
||||
private boolean giveup = false;
|
||||
|
||||
public PingThread(InetAddress hostAddress, int hostPort, int sleepTime)
|
||||
{
|
||||
super("XBMC EventClient Ping-Thread");
|
||||
this.hostAddress = hostAddress;
|
||||
this.hostPort = hostPort;
|
||||
this.sleepTime = sleepTime;
|
||||
}
|
||||
|
||||
public void giveup()
|
||||
{
|
||||
giveup = true;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while(!giveup)
|
||||
{
|
||||
try {
|
||||
PacketPING p = new PacketPING();
|
||||
p.send(hostAddress, hostPort);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(sleepTime);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright 2015 Synced Synapse. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.xbmc.kore.eventclient;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.*;
|
||||
import android.os.Process;
|
||||
|
||||
import org.xbmc.kore.host.HostInfo;
|
||||
import org.xbmc.kore.jsonrpc.ApiCallback;
|
||||
import org.xbmc.kore.jsonrpc.HostConnection;
|
||||
import org.xbmc.kore.jsonrpc.method.Application;
|
||||
import org.xbmc.kore.jsonrpc.type.ApplicationType;
|
||||
import org.xbmc.kore.utils.LogUtils;
|
||||
import org.xbmc.kore.utils.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* Class that establishes and maintains a connection to Kodi's EventServer
|
||||
* This class keeps pinging Kodi to keep the connection alive and contains
|
||||
* auxiliary methods that allow the sending of packets to Kodi.
|
||||
* Make sure to call quit() when done with it, so that it gracefully shuts down
|
||||
*/
|
||||
public class EventServerConnection {
|
||||
private static final String TAG = LogUtils.makeLogTag(EventServerConnection.class);
|
||||
|
||||
private static final int PING_INTERVAL = 45000; // ms
|
||||
private static final String DEVICE_NAME = "Kore Remote";
|
||||
|
||||
/**
|
||||
* Host to connect too
|
||||
*/
|
||||
private final HostInfo hostInfo;
|
||||
private InetAddress hostInetAddress = null;
|
||||
|
||||
// Handler on which packets will be posted, to send them asynchronously
|
||||
private Handler commHandler = null;
|
||||
private HandlerThread handlerThread = null;
|
||||
|
||||
private PacketPING packetPING = new PacketPING();
|
||||
private Runnable pingRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.LOGD(TAG, "Pinging EventServer");
|
||||
if (hostInetAddress != null) {
|
||||
try {
|
||||
packetPING.send(hostInetAddress, hostInfo.getEventServerPort());
|
||||
} catch (IOException exc) {
|
||||
LogUtils.LOGD(TAG, "Got an IOException when sending a PING Packet to Kodi's EventServer");
|
||||
}
|
||||
}
|
||||
commHandler.postDelayed(this, PING_INTERVAL);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface to notify users if the connection was successful
|
||||
*/
|
||||
public interface EventServerConnectionCallback {
|
||||
void OnConnectResult(boolean success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Starts the thread that keeps the connection alive. Make sure to call quit() when done.
|
||||
* @param hostInfo Host to connect to
|
||||
*/
|
||||
public EventServerConnection(final HostInfo hostInfo, final EventServerConnectionCallback callback) {
|
||||
this.hostInfo = hostInfo;
|
||||
|
||||
LogUtils.LOGD(TAG, "Starting EventServer Thread");
|
||||
// Handler thread that will keep pinging and send the requests to Kodi
|
||||
handlerThread = new HandlerThread("EventServerConnection", Process.THREAD_PRIORITY_DEFAULT);
|
||||
handlerThread.start();
|
||||
|
||||
// Get the HandlerThread's Looper and use it for our Handler
|
||||
commHandler = new Handler(handlerThread.getLooper());
|
||||
|
||||
// Now, get the host InetAddress in the background
|
||||
commHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
hostInetAddress = InetAddress.getByName(hostInfo.getAddress());
|
||||
} catch (UnknownHostException exc) {
|
||||
LogUtils.LOGD(TAG, "Got an UnknownHostException, disabling EventServer");
|
||||
hostInetAddress = null;
|
||||
}
|
||||
callback.OnConnectResult(hostInetAddress != null);
|
||||
}
|
||||
});
|
||||
|
||||
// Start pinging
|
||||
commHandler.postDelayed(pingRunnable, PING_INTERVAL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops the HandlerThread that is being used to send packets to Kodi
|
||||
*/
|
||||
public void quit() {
|
||||
LogUtils.LOGD(TAG, "Quiting EventServer handler thread");
|
||||
quitHandlerThread(handlerThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to Kodi's Event Server
|
||||
* Only sends the packet if connected, i.e. if quit() has not been not called
|
||||
* @param p Packet to send
|
||||
*/
|
||||
public void sendPacket(final Packet p) {
|
||||
if (!handlerThread.isAlive() || (hostInetAddress == null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LogUtils.LOGD(TAG, "Sending Packet");
|
||||
|
||||
commHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
p.send(hostInetAddress, hostInfo.getEventServerPort());
|
||||
} catch (IOException exc) {
|
||||
LogUtils.LOGD(TAG, "Got an IOException when sending a packet to Kodi's EventServer");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a connection to the EventServer and reports the result
|
||||
* @param hostInfo Host to connect to
|
||||
* @param callerCallback Callback on which to post the result
|
||||
* @param callerHandler Handler on which to post the callback call
|
||||
*/
|
||||
public static void testEventServerConnection(final HostInfo hostInfo,
|
||||
final EventServerConnectionCallback callerCallback,
|
||||
final Handler callerHandler) {
|
||||
final HandlerThread auxThread = new HandlerThread("EventServerConnectionTest", Process.THREAD_PRIORITY_DEFAULT);
|
||||
auxThread.start();
|
||||
|
||||
// Get the HandlerThread's Looper and use it for our Handler
|
||||
final Handler auxHandler = new Handler(auxThread.getLooper());
|
||||
|
||||
auxHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Get the InetAddress
|
||||
final InetAddress hostInetAddress;
|
||||
try {
|
||||
hostInetAddress = InetAddress.getByName(hostInfo.getAddress());
|
||||
} catch (UnknownHostException exc) {
|
||||
LogUtils.LOGD(TAG, "Couldn't get host InetAddress");
|
||||
reportTestResult(callerHandler, callerCallback, false);
|
||||
quitHandlerThread(auxThread);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a HELO packet
|
||||
Packet p = new PacketHELO(DEVICE_NAME);
|
||||
try {
|
||||
p.send(hostInetAddress, hostInfo.getEventServerPort());
|
||||
} catch (IOException exc) {
|
||||
LogUtils.LOGD(TAG, "Couldn't send HELO packet to host");
|
||||
reportTestResult(callerHandler, callerCallback, false);
|
||||
quitHandlerThread(auxThread);
|
||||
return;
|
||||
}
|
||||
|
||||
// The previous checks don't really test the connection, as this is UDP. Apart from checking if
|
||||
// any HostUnreachable ICMP message is returned (which may or may not happen), there's no direct way
|
||||
// to check if the messages were delivered, so the solution is to force something to happen on
|
||||
// Kodi and them read Kodi's state to check if it was applied.
|
||||
// We are going to get the mute status of Kodi via jsonrpc, change it via EventServer and check if
|
||||
// it was changed via jsonrpc, reverting it back afterwards
|
||||
final HostConnection auxHostConnection = new HostConnection(
|
||||
new HostInfo(hostInfo.getName(), hostInfo.getAddress(),
|
||||
HostConnection.PROTOCOL_HTTP, hostInfo.getHttpPort(), hostInfo.getTcpPort(),
|
||||
hostInfo.getUsername(), hostInfo.getPassword(), false, 0));
|
||||
final Application.GetProperties action = new Application.GetProperties(Application.GetProperties.MUTED);
|
||||
final Packet mutePacket = new PacketBUTTON(ButtonCodes.MAP_REMOTE, ButtonCodes.REMOTE_MUTE,
|
||||
false, true, true, (short) 0, (byte) 0);
|
||||
|
||||
// Get the initial mute status
|
||||
action.execute(auxHostConnection, new ApiCallback<ApplicationType.PropertyValue>() {
|
||||
@Override
|
||||
public void onSuccess(ApplicationType.PropertyValue result) {
|
||||
final boolean initialMuteStatus = result.muted;
|
||||
// Switch mute status
|
||||
try {
|
||||
mutePacket.send(hostInetAddress, hostInfo.getEventServerPort());
|
||||
} catch (IOException exc) {
|
||||
LogUtils.LOGD(TAG, "Couldn't send first MUTE packet to host");
|
||||
reportTestResult(callerHandler, callerCallback, false);
|
||||
quitHandlerThread(auxThread);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sleep a while to make sure the previous command was executed
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException exc) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// Now get the new status and compare
|
||||
action.execute(auxHostConnection, new ApiCallback<ApplicationType.PropertyValue>() {
|
||||
@Override
|
||||
public void onSuccess(ApplicationType.PropertyValue result) {
|
||||
// Report result (mute status is different)
|
||||
reportTestResult(callerHandler, callerCallback, initialMuteStatus != result.muted);
|
||||
|
||||
// Revert mute status
|
||||
try {
|
||||
mutePacket.send(hostInetAddress, hostInfo.getEventServerPort());
|
||||
} catch (IOException exc) {
|
||||
LogUtils.LOGD(TAG, "Couldn't revert MUTE status");
|
||||
}
|
||||
quitHandlerThread(auxThread);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String description) {
|
||||
LogUtils.LOGD(TAG, "Got an error on Application.GetProperties: " + description);
|
||||
reportTestResult(callerHandler, callerCallback, false);
|
||||
quitHandlerThread(auxThread);
|
||||
}
|
||||
}, auxHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String description) {
|
||||
LogUtils.LOGD(TAG, "Got an error on Application.GetProperties: " + description);
|
||||
reportTestResult(callerHandler, callerCallback, false);
|
||||
quitHandlerThread(auxThread);
|
||||
}
|
||||
}, auxHandler);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static void reportTestResult(final Handler callerHandler,
|
||||
final EventServerConnectionCallback callback,
|
||||
final boolean result) {
|
||||
callerHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.OnConnectResult(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private static void quitHandlerThread(HandlerThread handlerThread) {
|
||||
if (Utils.isJellybeanMR2OrLater()) {
|
||||
handlerThread.quitSafely();
|
||||
} else {
|
||||
handlerThread.quit();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
* <p>
|
||||
* Implementation of XBMC's UDP based input system.
|
||||
* A set of classes that abstract the various packets that the event server
|
||||
* currently supports. In addition, there's also a class, XBMCClient, that
|
||||
* provides functions that sends the various packets. Use XBMCClient if you
|
||||
* don't need complete control over packet structure.
|
||||
* </p>
|
||||
* <p>
|
||||
* The basic workflow involves:
|
||||
* <ol>
|
||||
* <li>Send a HELO packet</li>
|
||||
* <li>Send x number of valid packets</li>
|
||||
* <li>Send a BYE packet</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* <p>
|
||||
* IMPORTANT NOTE ABOUT TIMEOUTS:
|
||||
* A client is considered to be timed out if XBMC doesn't received a packet
|
||||
* at least once every 60 seconds. To "ping" XBMC with an empty packet use
|
||||
* PacketPING or XBMCClient.ping(). See the documentation for details.
|
||||
* </p>
|
||||
* <p>
|
||||
* Base class that implements a single event packet.
|
||||
* - Generic packet structure (maximum 1024 bytes per packet)
|
||||
* - Header is 32 bytes long, so 992 bytes available for payload
|
||||
* - large payloads can be split into multiple packets using H4 and H5
|
||||
* H5 should contain total no. of packets in such a case
|
||||
* - H6 contains length of P1, which is limited to 992 bytes
|
||||
* - if H5 is 0 or 1, then H4 will be ignored (single packet msg)
|
||||
* - H7 must be set to zeros for now
|
||||
* </p>
|
||||
* <pre>
|
||||
* -----------------------------
|
||||
* | -H1 Signature ("XBMC") | - 4 x CHAR 4B
|
||||
* | -H2 Version (eg. 2.0) | - 2 x UNSIGNED CHAR 2B
|
||||
* | -H3 PacketType | - 1 x UNSIGNED SHORT 2B
|
||||
* | -H4 Sequence number | - 1 x UNSIGNED LONG 4B
|
||||
* | -H5 No. of packets in msg | - 1 x UNSIGNED LONG 4B
|
||||
* | -H6 Payloadsize of packet | - 1 x UNSIGNED SHORT 2B
|
||||
* | -H7 Client's unique token | - 1 x UNSIGNED LONG 4B
|
||||
* | -H8 Reserved | - 10 x UNSIGNED CHAR 10B
|
||||
* |---------------------------|
|
||||
* | -P1 payload | -
|
||||
* -----------------------------
|
||||
* </pre>
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public abstract class Packet {
|
||||
|
||||
private byte[] sig;
|
||||
private byte[] payload = new byte[0];
|
||||
private byte minver;
|
||||
private byte majver;
|
||||
|
||||
private short packettype;
|
||||
|
||||
|
||||
private final static short MAX_PACKET_SIZE = 1024;
|
||||
private final static short HEADER_SIZE = 32;
|
||||
private final static short MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE;
|
||||
|
||||
protected final static byte PT_HELO = 0x01;
|
||||
protected final static byte PT_BYE = 0x02;
|
||||
protected final static byte PT_BUTTON = 0x03;
|
||||
protected final static byte PT_MOUSE = 0x04;
|
||||
protected final static byte PT_PING = 0x05;
|
||||
protected final static byte PT_BROADCAST = 0x06;
|
||||
protected final static byte PT_NOTIFICATION = 0x07;
|
||||
protected final static byte PT_BLOB = 0x08;
|
||||
protected final static byte PT_LOG = 0x09;
|
||||
protected final static byte PT_ACTION = 0x0A;
|
||||
protected final static byte PT_DEBUG = (byte)0xFF;
|
||||
|
||||
public final static byte ICON_NONE = 0x00;
|
||||
public final static byte ICON_JPEG = 0x01;
|
||||
public final static byte ICON_PNG = 0x02;
|
||||
public final static byte ICON_GIF = 0x03;
|
||||
|
||||
private static int uid = (int)(Math.random()*Integer.MAX_VALUE);
|
||||
|
||||
/**
|
||||
* This is an Abstract class and cannot be instanced. Please use one of the Packet implementation Classes
|
||||
* (PacketXXX).
|
||||
*
|
||||
* Implements an XBMC Event Client Packet. Type is to be specified at creation time, Payload can be added
|
||||
* with the various appendPayload methods. Packet can be sent through UDP-Socket with method "send".
|
||||
* @param packettype Type of Packet (PT_XXX)
|
||||
*/
|
||||
protected Packet(short packettype)
|
||||
{
|
||||
sig = new byte[] {'X', 'B', 'M', 'C' };
|
||||
minver = 0;
|
||||
majver = 2;
|
||||
this.packettype = packettype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a String to the payload (terminated with 0x00)
|
||||
* @param payload Payload as String
|
||||
*/
|
||||
protected void appendPayload(String payload)
|
||||
{
|
||||
byte[] payloadarr = payload.getBytes();
|
||||
int oldpayloadsize = this.payload.length;
|
||||
byte[] oldpayload = this.payload;
|
||||
this.payload = new byte[oldpayloadsize+payloadarr.length+1]; // Create new Array with more place (+1 for string terminator)
|
||||
System.arraycopy(oldpayload, 0, this.payload, 0, oldpayloadsize);
|
||||
System.arraycopy(payloadarr, 0, this.payload, oldpayloadsize, payloadarr.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a single Byte to the payload
|
||||
* @param payload Payload
|
||||
*/
|
||||
protected void appendPayload(byte payload)
|
||||
{
|
||||
appendPayload(new byte[] { payload });
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a Byte-Array to the payload
|
||||
* @param payloadarr Payload
|
||||
*/
|
||||
protected void appendPayload(byte[] payloadarr)
|
||||
{
|
||||
int oldpayloadsize = this.payload.length;
|
||||
byte[] oldpayload = this.payload;
|
||||
this.payload = new byte[oldpayloadsize+payloadarr.length];
|
||||
System.arraycopy(oldpayload, 0, this.payload, 0, oldpayloadsize);
|
||||
System.arraycopy(payloadarr, 0, this.payload, oldpayloadsize, payloadarr.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer to the payload
|
||||
* @param i Payload
|
||||
*/
|
||||
protected void appendPayload(int i) {
|
||||
appendPayload(intToByteArray(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a short to the payload
|
||||
* @param s Payload
|
||||
*/
|
||||
protected void appendPayload(short s) {
|
||||
appendPayload(shortToByteArray(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Number of Packets which will be sent with current Payload...
|
||||
* @return Number of Packets
|
||||
*/
|
||||
public int getNumPackets()
|
||||
{
|
||||
// return (payload.length + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE;
|
||||
return 1 + Math.max(payload.length - 1, 0) / MAX_PAYLOAD_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Header for a specific Packet in this sequence...
|
||||
* @param seq Current sequence number
|
||||
* @param maxseq Maximal sequence number
|
||||
* @param actpayloadsize Payloadsize of this packet
|
||||
* @return Byte-Array with Header information (currently 32-Byte long, see HEADER_SIZE)
|
||||
*/
|
||||
private byte[] getHeader(int seq, int maxseq, short actpayloadsize)
|
||||
{
|
||||
byte[] header = new byte[HEADER_SIZE];
|
||||
System.arraycopy(sig, 0, header, 0, 4);
|
||||
header[4] = majver;
|
||||
header[5] = minver;
|
||||
byte[] packettypearr = shortToByteArray(this.packettype);
|
||||
System.arraycopy(packettypearr, 0, header, 6, 2);
|
||||
byte[] seqarr = intToByteArray(seq);
|
||||
System.arraycopy(seqarr, 0, header, 8, 4);
|
||||
byte[] maxseqarr = intToByteArray(maxseq);
|
||||
System.arraycopy(maxseqarr, 0, header, 12, 4);
|
||||
byte[] payloadsize = shortToByteArray(actpayloadsize);
|
||||
System.arraycopy(payloadsize, 0, header, 16, 2);
|
||||
byte[] uid = intToByteArray(Packet.uid);
|
||||
System.arraycopy(uid, 0, header, 18, 4);
|
||||
byte[] reserved = new byte[10];
|
||||
System.arraycopy(reserved, 0, header, 22, 10);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the whole UDP-Message with Header and Payload of a specific Packet in sequence
|
||||
* @param seq Current sequence number
|
||||
* @return Byte-Array with UDP-Message
|
||||
*/
|
||||
private byte[] getUDPMessage(int seq)
|
||||
{
|
||||
int maxseq = getNumPackets();
|
||||
if(seq > maxseq)
|
||||
return null;
|
||||
|
||||
short actpayloadsize;
|
||||
|
||||
if(seq == maxseq)
|
||||
actpayloadsize = (short)((payload.length - 1) % MAX_PAYLOAD_SIZE + 1);
|
||||
else
|
||||
actpayloadsize = (short)MAX_PAYLOAD_SIZE;
|
||||
|
||||
byte[] pack = new byte[HEADER_SIZE+actpayloadsize];
|
||||
|
||||
System.arraycopy(getHeader(seq, maxseq, actpayloadsize), 0, pack, 0, HEADER_SIZE);
|
||||
System.arraycopy(payload, (seq-1)*MAX_PAYLOAD_SIZE, pack, HEADER_SIZE, actpayloadsize);
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this packet to the EventServer
|
||||
* @param adr Address of the EventServer
|
||||
* @param port Port of the EventServer
|
||||
* @throws IOException
|
||||
*/
|
||||
public void send(InetAddress adr, int port) throws IOException
|
||||
{
|
||||
int maxseq = getNumPackets();
|
||||
DatagramSocket s = new DatagramSocket();
|
||||
// For each Packet in Sequence...
|
||||
for(int seq=1;seq<=maxseq;seq++)
|
||||
{
|
||||
// Get Message and send them...
|
||||
byte[] pack = getUDPMessage(seq);
|
||||
DatagramPacket p = new DatagramPacket(pack, pack.length);
|
||||
p.setAddress(adr);
|
||||
p.setPort(port);
|
||||
s.send(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper Method to convert an integer to a Byte array
|
||||
* @param value
|
||||
* @return Byte-Array
|
||||
*/
|
||||
private static final byte[] intToByteArray(int value) {
|
||||
return new byte[] {
|
||||
(byte)(value >>> 24),
|
||||
(byte)(value >>> 16),
|
||||
(byte)(value >>> 8),
|
||||
(byte)value};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper Method to convert an short to a Byte array
|
||||
* @param value
|
||||
* @return Byte-Array
|
||||
*/
|
||||
private static final byte[] shortToByteArray(short value) {
|
||||
return new byte[] {
|
||||
(byte)(value >>> 8),
|
||||
(byte)value};
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent.
|
||||
* The idea is that this will be as in scripting/skining and keymapping, just triggered from afar.
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketACTION extends Packet {
|
||||
|
||||
public final static byte ACTION_EXECBUILTIN = 0x01;
|
||||
public final static byte ACTION_BUTTON = 0x02;
|
||||
|
||||
|
||||
/**
|
||||
* An ACTION packet 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 PacketACTION(String actionmessage)
|
||||
{
|
||||
super(PT_ACTION);
|
||||
byte actiontype = ACTION_EXECBUILTIN;
|
||||
appendPayload(actionmessage, actiontype);
|
||||
}
|
||||
|
||||
/**
|
||||
* An ACTION packet 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)
|
||||
* @param actiontype Actiontype (ACTION_EXECBUILTIN or ACTION_BUTTON)
|
||||
*/
|
||||
public PacketACTION(String actionmessage, byte actiontype)
|
||||
{
|
||||
super(PT_ACTION);
|
||||
appendPayload(actionmessage, actiontype);
|
||||
}
|
||||
|
||||
private void appendPayload(String actionmessage, byte actiontype)
|
||||
{
|
||||
appendPayload(actiontype);
|
||||
appendPayload(actionmessage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* A button packet send a key press or release event to XBMC
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketBUTTON extends Packet {
|
||||
|
||||
protected final static byte BT_USE_NAME = 0x01;
|
||||
protected final static byte BT_DOWN = 0x02;
|
||||
protected final static byte BT_UP = 0x04;
|
||||
protected final static byte BT_USE_AMOUNT = 0x08;
|
||||
protected final static byte BT_QUEUE = 0x10;
|
||||
protected final static byte BT_NO_REPEAT = 0x20;
|
||||
protected final static byte BT_VKEY = 0x40;
|
||||
protected final static byte BT_AXIS = (byte)0x80;
|
||||
protected final static byte BT_AXISSINGLE = (byte)0x100;
|
||||
|
||||
/**
|
||||
* A button packet send a key press or release event to XBMC
|
||||
* @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 PacketBUTTON(short code, boolean repeat, boolean down, boolean queue, short amount, byte axis)
|
||||
{
|
||||
super(PT_BUTTON);
|
||||
String map_name = "";
|
||||
String button_name = "";
|
||||
short flags = 0;
|
||||
appendPayload(code, map_name, button_name, repeat, down, queue, amount, axis, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* A button packet send a key press or release event to XBMC
|
||||
* @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>"KB" => standard keyboard map ( <keyboard> section )</li>
|
||||
* <li>"XG" => xbox gamepad map ( <gamepad> section )</li>
|
||||
* <li>"R1" => xbox remote map ( <remote> section )</li>
|
||||
* <li>"R2" => xbox universal remote map ( <universalremote> section )</li>
|
||||
* <li>"LI:devicename" => LIRC remote map where 'devicename' 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 PacketBUTTON(String map_name, String button_name, boolean repeat, boolean down, boolean queue, short amount, byte axis)
|
||||
{
|
||||
super(PT_BUTTON);
|
||||
short code = 0;
|
||||
short flags = BT_USE_NAME;
|
||||
appendPayload(code, map_name, button_name, repeat, down, queue, amount, axis, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends Payload for a Button Packet (this method is used by the different Constructors of this Packet)
|
||||
* @param code raw button code (default: 0)
|
||||
* @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>"KB" => standard keyboard map ( <keyboard> section )</li>
|
||||
* <li>"XG" => xbox gamepad map ( <gamepad> section )</li>
|
||||
* <li>"R1" => xbox remote map ( <remote> section )</li>
|
||||
* <li>"R2" => xbox universal remote map ( <universalremote> section )</li>
|
||||
* <li>"LI:devicename" => LIRC remote map where 'devicename' 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
|
||||
* @param flags Packet specific flags
|
||||
*/
|
||||
private void appendPayload(short code, String map_name, String button_name, boolean repeat, boolean down, boolean queue, short amount, byte axis, short flags)
|
||||
{
|
||||
if(amount>0)
|
||||
flags |= BT_USE_AMOUNT;
|
||||
else
|
||||
amount = 0;
|
||||
|
||||
if(down)
|
||||
flags |= BT_DOWN;
|
||||
else
|
||||
flags |= BT_UP;
|
||||
|
||||
if(!repeat)
|
||||
flags |= BT_NO_REPEAT;
|
||||
|
||||
if(queue)
|
||||
flags |= BT_QUEUE;
|
||||
|
||||
if(axis == 1)
|
||||
flags |= BT_AXISSINGLE;
|
||||
else if (axis == 2)
|
||||
flags |= BT_AXIS;
|
||||
|
||||
|
||||
appendPayload(code);
|
||||
appendPayload(flags);
|
||||
appendPayload(amount);
|
||||
appendPayload(map_name);
|
||||
appendPayload(button_name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* A BYE packet terminates the connection to XBMC.
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketBYE extends Packet
|
||||
{
|
||||
|
||||
/**
|
||||
* A BYE packet terminates the connection to XBMC.
|
||||
*/
|
||||
public PacketBYE()
|
||||
{
|
||||
super(PT_BYE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* A HELO packet establishes a valid connection to XBMC. It is the
|
||||
* first packet that should be sent.
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketHELO extends Packet {
|
||||
|
||||
|
||||
/**
|
||||
* A HELO packet establishes a valid connection to XBMC.
|
||||
* @param devicename Name of the device which connects to XBMC
|
||||
*/
|
||||
public PacketHELO(String devicename)
|
||||
{
|
||||
super(PT_HELO);
|
||||
this.appendPayload(devicename);
|
||||
this.appendPayload(ICON_NONE);
|
||||
this.appendPayload((short)0); // port no
|
||||
this.appendPayload(0); // reserved1
|
||||
this.appendPayload(0); // reserved2
|
||||
}
|
||||
|
||||
/**
|
||||
* A HELO packet establishes a valid connection to XBMC.
|
||||
* @param devicename Name of the device which connects to XBMC
|
||||
* @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF)
|
||||
* @param iconData The icon as a Byte-Array
|
||||
*/
|
||||
public PacketHELO(String devicename, byte iconType, byte[] iconData)
|
||||
{
|
||||
super(PT_HELO);
|
||||
this.appendPayload(devicename);
|
||||
this.appendPayload(iconType);
|
||||
this.appendPayload((short)0); // port no
|
||||
this.appendPayload(0); // reserved1
|
||||
this.appendPayload(0); // reserved2
|
||||
this.appendPayload(iconData); // reserved2
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* A LOG packet tells XBMC to log the message to xbmc.log with the loglevel as specified.
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketLOG extends Packet {
|
||||
|
||||
/**
|
||||
* A LOG packet tells XBMC to log the message to xbmc.log with the loglevel as specified.
|
||||
* @param loglevel the loglevel, 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 PacketLOG(byte loglevel, String logmessage)
|
||||
{
|
||||
super(PT_LOG);
|
||||
appendPayload(loglevel);
|
||||
appendPayload(logmessage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* A MOUSE packets sets the mouse position in XBMC
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketMOUSE extends Packet {
|
||||
|
||||
protected final static byte MS_ABSOLUTE = 0x01;
|
||||
|
||||
/**
|
||||
* A MOUSE packets sets the mouse position in XBMC
|
||||
* @param x horitontal position ranging from 0 to 65535
|
||||
* @param y vertical position ranging from 0 to 65535
|
||||
*/
|
||||
public PacketMOUSE(int x, int y)
|
||||
{
|
||||
super(PT_MOUSE);
|
||||
byte flags = 0;
|
||||
flags |= MS_ABSOLUTE;
|
||||
appendPayload(flags);
|
||||
appendPayload((short)x);
|
||||
appendPayload((short)y);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* This packet displays a notification window in XBMC. It can contain
|
||||
* a caption, a message and an icon.
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketNOTIFICATION extends Packet {
|
||||
|
||||
/**
|
||||
* This packet displays a notification window in XBMC.
|
||||
* @param title Message title
|
||||
* @param message The actual message
|
||||
* @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF)
|
||||
* @param iconData The icon as a Byte-Array
|
||||
*/
|
||||
public PacketNOTIFICATION(String title, String message, byte iconType, byte[] iconData)
|
||||
{
|
||||
super(PT_NOTIFICATION);
|
||||
appendPayload(title, message, iconType, iconData);
|
||||
}
|
||||
|
||||
/**
|
||||
* This packet displays a notification window in XBMC.
|
||||
* @param title Message title
|
||||
* @param message The actual message
|
||||
*/
|
||||
public PacketNOTIFICATION(String title, String message)
|
||||
{
|
||||
super(PT_NOTIFICATION);
|
||||
appendPayload(title, message, Packet.ICON_NONE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the payload to the packet...
|
||||
* @param title Message title
|
||||
* @param message The actual message
|
||||
* @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF)
|
||||
* @param iconData The icon as a Byte-Array
|
||||
*/
|
||||
private void appendPayload(String title, String message, byte iconType, byte[] iconData)
|
||||
{
|
||||
appendPayload(title);
|
||||
appendPayload(message);
|
||||
appendPayload(iconType);
|
||||
appendPayload(0); // reserved
|
||||
if(iconData!=null)
|
||||
appendPayload(iconData);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2013 Team XBMC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package org.xbmc.kore.eventclient;
|
||||
/**
|
||||
* XBMC Event Client Class
|
||||
*
|
||||
* A PING packet tells XBMC that the client is still alive. All valid
|
||||
* packets act as ping (not just this one). A client needs to ping
|
||||
* XBMC at least once in 60 seconds or it will time
|
||||
* @author Stefan Agner
|
||||
*
|
||||
*/
|
||||
public class PacketPING extends Packet {
|
||||
/**
|
||||
* A PING packet tells XBMC that the client is still alive.
|
||||
*/
|
||||
public PacketPING()
|
||||
{
|
||||
super(PT_PING);
|
||||
}
|
||||
}
|
|
@ -44,7 +44,12 @@ public class HostInfo {
|
|||
*/
|
||||
public static final int DEFAULT_WOL_PORT = 9;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Default EventServer port for Kodi
|
||||
*/
|
||||
public static final int DEFAULT_EVENT_SERVER_PORT = 9777;
|
||||
|
||||
/**
|
||||
* Internal id of the host
|
||||
*/
|
||||
private int id;
|
||||
|
@ -61,6 +66,9 @@ public class HostInfo {
|
|||
private int httpPort;
|
||||
private int tcpPort;
|
||||
|
||||
private boolean useEventServer;
|
||||
private int eventServerPort;
|
||||
|
||||
/**
|
||||
* Authentication information
|
||||
*/
|
||||
|
@ -93,7 +101,8 @@ public class HostInfo {
|
|||
* @param password Password for basic auth
|
||||
*/
|
||||
public HostInfo(int id, String name, String address, int protocol, int httpPort, int tcpPort,
|
||||
String username, String password, String macAddress, int wolPort) {
|
||||
String username, String password, String macAddress, int wolPort,
|
||||
boolean useEventServer, int eventServerPort) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
|
@ -108,6 +117,9 @@ public class HostInfo {
|
|||
this.macAddress = macAddress;
|
||||
this.wolPort = wolPort;
|
||||
|
||||
this.useEventServer = useEventServer;
|
||||
this.eventServerPort = eventServerPort;
|
||||
|
||||
// For performance reasons
|
||||
this.auxImageHttpAddress = getHttpURL() + "/image/";
|
||||
}
|
||||
|
@ -124,12 +136,13 @@ public class HostInfo {
|
|||
* @param password Password for basic auth
|
||||
*/
|
||||
public HostInfo(String name, String address, int protocol, int httpPort,
|
||||
int tcpPort, String username, String password) {
|
||||
int tcpPort, String username, String password,
|
||||
boolean useEventServer, int eventServerPort) {
|
||||
this(-1, name, address, protocol, httpPort, tcpPort, username,
|
||||
password, null, DEFAULT_WOL_PORT);
|
||||
password, null, DEFAULT_WOL_PORT, useEventServer, eventServerPort);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -177,7 +190,15 @@ public class HostInfo {
|
|||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
public boolean getUseEventServer() {
|
||||
return useEventServer;
|
||||
}
|
||||
|
||||
public int getEventServerPort() {
|
||||
return eventServerPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the protocol for this host info
|
||||
* @param protocol Protocol
|
||||
*/
|
||||
|
@ -188,6 +209,14 @@ public class HostInfo {
|
|||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the use of EventServer
|
||||
* @param useEventServer Whether to use EventServer
|
||||
*/
|
||||
public void setUseEventServer(boolean useEventServer) {
|
||||
this.useEventServer = useEventServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the host
|
||||
* @return HTTP URL eg. http://192.168.1.1:8080
|
||||
|
|
|
@ -142,9 +142,11 @@ public class HostManager {
|
|||
String password = cursor.getString(idx++);
|
||||
String macAddress = cursor.getString(idx++);
|
||||
int wolPort = cursor.getInt(idx++);
|
||||
boolean useEventServer = (cursor.getInt(idx++) != 0);
|
||||
int eventServerPort = cursor.getInt(idx++);
|
||||
|
||||
hosts.add(new HostInfo(id, name, address, protocol, httpPort, tcpPort,
|
||||
username, password, macAddress, wolPort));
|
||||
username, password, macAddress, wolPort, useEventServer, eventServerPort));
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
|
@ -307,9 +309,10 @@ public class HostManager {
|
|||
*/
|
||||
public HostInfo addHost(HostInfo hostInfo) {
|
||||
return addHost(hostInfo.getName(), hostInfo.getAddress(), hostInfo.getProtocol(),
|
||||
hostInfo.getHttpPort(), hostInfo.getTcpPort(),
|
||||
hostInfo.getUsername(), hostInfo.getPassword(),
|
||||
hostInfo.getMacAddress(), hostInfo.getWolPort());
|
||||
hostInfo.getHttpPort(), hostInfo.getTcpPort(),
|
||||
hostInfo.getUsername(), hostInfo.getPassword(),
|
||||
hostInfo.getMacAddress(), hostInfo.getWolPort(),
|
||||
hostInfo.getUseEventServer(), hostInfo.getEventServerPort());
|
||||
}
|
||||
|
||||
|
||||
|
@ -325,7 +328,8 @@ public class HostManager {
|
|||
* @return Newly created {@link org.xbmc.kore.host.HostInfo}
|
||||
*/
|
||||
public HostInfo addHost(String name, String address, int protocol, int httpPort, int tcpPort,
|
||||
String username, String password, String macAddress, int wolPort) {
|
||||
String username, String password, String macAddress, int wolPort,
|
||||
boolean useEventServer, int eventServerPort) {
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MediaContract.HostsColumns.NAME, name);
|
||||
|
@ -337,6 +341,8 @@ public class HostManager {
|
|||
values.put(MediaContract.HostsColumns.PASSWORD, password);
|
||||
values.put(MediaContract.HostsColumns.MAC_ADDRESS, macAddress);
|
||||
values.put(MediaContract.HostsColumns.WOL_PORT, wolPort);
|
||||
values.put(MediaContract.HostsColumns.USE_EVENT_SERVER, useEventServer);
|
||||
values.put(MediaContract.HostsColumns.EVENT_SERVER_PORT, eventServerPort);
|
||||
|
||||
Uri newUri = context.getContentResolver()
|
||||
.insert(MediaContract.Hosts.CONTENT_URI, values);
|
||||
|
@ -371,6 +377,8 @@ public class HostManager {
|
|||
values.put(MediaContract.HostsColumns.PASSWORD, newHostInfo.getPassword());
|
||||
values.put(MediaContract.HostsColumns.MAC_ADDRESS, newHostInfo.getMacAddress());
|
||||
values.put(MediaContract.HostsColumns.WOL_PORT, newHostInfo.getWolPort());
|
||||
values.put(MediaContract.HostsColumns.USE_EVENT_SERVER, newHostInfo.getUseEventServer());
|
||||
values.put(MediaContract.HostsColumns.EVENT_SERVER_PORT, newHostInfo.getEventServerPort());
|
||||
|
||||
context.getContentResolver()
|
||||
.update(MediaContract.Hosts.buildHostUri(hostId), values, null, null);
|
||||
|
|
|
@ -54,15 +54,17 @@ public class MediaContract {
|
|||
* Columns for table HOSTS
|
||||
*/
|
||||
public interface HostsColumns {
|
||||
public final static String NAME = "name";
|
||||
public final static String ADDRESS = "address";
|
||||
public final static String PROTOCOL = "protocol";
|
||||
public final static String HTTP_PORT = "http_port";
|
||||
public final static String TCP_PORT = "tcp_port";
|
||||
public final static String USERNAME = "username";
|
||||
public final static String PASSWORD = "password";
|
||||
public final static String MAC_ADDRESS = "mac_address";
|
||||
public final static String WOL_PORT = "wol_port";
|
||||
String NAME = "name";
|
||||
String ADDRESS = "address";
|
||||
String PROTOCOL = "protocol";
|
||||
String HTTP_PORT = "http_port";
|
||||
String TCP_PORT = "tcp_port";
|
||||
String USERNAME = "username";
|
||||
String PASSWORD = "password";
|
||||
String MAC_ADDRESS = "mac_address";
|
||||
String WOL_PORT = "wol_port";
|
||||
String USE_EVENT_SERVER = "use_event_server";
|
||||
String EVENT_SERVER_PORT = "event_server_port";
|
||||
}
|
||||
|
||||
public static class Hosts implements BaseColumns, SyncColumns, HostsColumns {
|
||||
|
@ -86,7 +88,7 @@ public class MediaContract {
|
|||
|
||||
public final static String[] ALL_COLUMNS = {
|
||||
_ID, UPDATED, NAME, ADDRESS, PROTOCOL, HTTP_PORT, TCP_PORT, USERNAME, PASSWORD,
|
||||
MAC_ADDRESS, WOL_PORT
|
||||
MAC_ADDRESS, WOL_PORT, USE_EVENT_SERVER, EVENT_SERVER_PORT
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -95,40 +97,40 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + MOVIEID
|
||||
*/
|
||||
public interface MoviesColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public final static String MOVIEID = "movieid";
|
||||
String HOST_ID = "host_id";
|
||||
String MOVIEID = "movieid";
|
||||
|
||||
public final static String FANART = "fanart";
|
||||
public final static String THUMBNAIL = "thumbnail";
|
||||
public final static String PLAYCOUNT = "playcount";
|
||||
public final static String TITLE = "title";
|
||||
public final static String FILE = "file";
|
||||
public final static String PLOT = "plot";
|
||||
public final static String DIRECTOR = "director";
|
||||
public final static String RUNTIME = "runtime";
|
||||
public final static String AUDIO_CHANNELS = "audio_channels";
|
||||
public final static String AUDIO_CODEC = "audio_coded";
|
||||
public final static String AUDIO_LANGUAGE = "audio_language";
|
||||
public final static String SUBTITLES_LANGUAGES = "subtitles_languages";
|
||||
public static final String VIDEO_ASPECT = "video_aspect";
|
||||
public static final String VIDEO_CODEC = "video_codec";
|
||||
public static final String VIDEO_HEIGHT = "video_height";
|
||||
public static final String VIDEO_WIDTH = "video_width";
|
||||
public static final String COUNTRIES = "countries";
|
||||
public static final String GENRES = "genres";
|
||||
public static final String IMDBNUMBER = "imdbnumber";
|
||||
public static final String MPAA = "mpaa";
|
||||
public static final String RATING = "rating";
|
||||
public static final String SET = "movie_set";
|
||||
public static final String SETID = "setid";
|
||||
public static final String STUDIOS = "studios";
|
||||
public static final String TAGLINE = "tagline";
|
||||
public static final String TOP250 = "top250";
|
||||
public static final String TRAILER = "trailer";
|
||||
public static final String VOTES = "votes";
|
||||
public static final String WRITERS = "writers";
|
||||
public static final String YEAR = "year";
|
||||
public static final String DATEADDED = "dateadded";
|
||||
String FANART = "fanart";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String PLAYCOUNT = "playcount";
|
||||
String TITLE = "title";
|
||||
String FILE = "file";
|
||||
String PLOT = "plot";
|
||||
String DIRECTOR = "director";
|
||||
String RUNTIME = "runtime";
|
||||
String AUDIO_CHANNELS = "audio_channels";
|
||||
String AUDIO_CODEC = "audio_coded";
|
||||
String AUDIO_LANGUAGE = "audio_language";
|
||||
String SUBTITLES_LANGUAGES = "subtitles_languages";
|
||||
String VIDEO_ASPECT = "video_aspect";
|
||||
String VIDEO_CODEC = "video_codec";
|
||||
String VIDEO_HEIGHT = "video_height";
|
||||
String VIDEO_WIDTH = "video_width";
|
||||
String COUNTRIES = "countries";
|
||||
String GENRES = "genres";
|
||||
String IMDBNUMBER = "imdbnumber";
|
||||
String MPAA = "mpaa";
|
||||
String RATING = "rating";
|
||||
String SET = "movie_set";
|
||||
String SETID = "setid";
|
||||
String STUDIOS = "studios";
|
||||
String TAGLINE = "tagline";
|
||||
String TOP250 = "top250";
|
||||
String TRAILER = "trailer";
|
||||
String VOTES = "votes";
|
||||
String WRITERS = "writers";
|
||||
String YEAR = "year";
|
||||
String DATEADDED = "dateadded";
|
||||
}
|
||||
|
||||
public static class Movies implements BaseColumns, SyncColumns, MoviesColumns {
|
||||
|
@ -174,13 +176,13 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + MOVIEID + NAME
|
||||
*/
|
||||
public interface MovieCastColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public final static String MOVIEID = "movieid";
|
||||
public final static String NAME = "name";
|
||||
String HOST_ID = "host_id";
|
||||
String MOVIEID = "movieid";
|
||||
String NAME = "name";
|
||||
|
||||
public final static String ORDER = "cast_order";
|
||||
public final static String ROLE = "role";
|
||||
public final static String THUMBNAIL = "thumbnail";
|
||||
String ORDER = "cast_order";
|
||||
String ROLE = "role";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
}
|
||||
|
||||
public static class MovieCast implements BaseColumns, SyncColumns, MovieCastColumns {
|
||||
|
@ -205,24 +207,24 @@ public class MediaContract {
|
|||
* For XBMC reference use HOST_ID + TVSHOWID
|
||||
*/
|
||||
public interface TVShowsColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public final static String TVSHOWID = "tvshowid";
|
||||
String HOST_ID = "host_id";
|
||||
String TVSHOWID = "tvshowid";
|
||||
|
||||
public static final String FANART = "fanart";
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
public static final String PLAYCOUNT = "playcount";
|
||||
public static final String TITLE = "title";
|
||||
public static final String DATEADDED = "dateadded";
|
||||
public static final String FILE = "file";
|
||||
public static final String PLOT = "plot";
|
||||
public static final String EPISODE = "episode";
|
||||
public static final String IMDBNUMBER = "imdbnumber";
|
||||
public static final String MPAA = "mpaa";
|
||||
public static final String PREMIERED = "premiered";
|
||||
public static final String RATING = "rating";
|
||||
public static final String STUDIO = "studio";
|
||||
public static final String WATCHEDEPISODES = "watchedepisodes";
|
||||
public static final String GENRES = "genres";
|
||||
String FANART = "fanart";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String PLAYCOUNT = "playcount";
|
||||
String TITLE = "title";
|
||||
String DATEADDED = "dateadded";
|
||||
String FILE = "file";
|
||||
String PLOT = "plot";
|
||||
String EPISODE = "episode";
|
||||
String IMDBNUMBER = "imdbnumber";
|
||||
String MPAA = "mpaa";
|
||||
String PREMIERED = "premiered";
|
||||
String RATING = "rating";
|
||||
String STUDIO = "studio";
|
||||
String WATCHEDEPISODES = "watchedepisodes";
|
||||
String GENRES = "genres";
|
||||
}
|
||||
|
||||
public static class TVShows implements BaseColumns, SyncColumns, TVShowsColumns {
|
||||
|
@ -266,13 +268,13 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + TVSHOWID + NAME
|
||||
*/
|
||||
public interface TVShowCastColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public final static String TVSHOWID = "tvshowid";
|
||||
public final static String NAME = "name";
|
||||
String HOST_ID = "host_id";
|
||||
String TVSHOWID = "tvshowid";
|
||||
String NAME = "name";
|
||||
|
||||
public final static String ORDER = "cast_order";
|
||||
public final static String ROLE = "role";
|
||||
public final static String THUMBNAIL = "thumbnail";
|
||||
String ORDER = "cast_order";
|
||||
String ROLE = "role";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
}
|
||||
|
||||
public static class TVShowCast implements BaseColumns, SyncColumns, TVShowCastColumns {
|
||||
|
@ -297,16 +299,16 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + TVSHOWID + SEASON
|
||||
*/
|
||||
public interface SeasonsColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public final static String TVSHOWID = "tvshowid";
|
||||
public static final String SEASON = "season";
|
||||
String HOST_ID = "host_id";
|
||||
String TVSHOWID = "tvshowid";
|
||||
String SEASON = "season";
|
||||
|
||||
public static final String LABEL = "label";
|
||||
public static final String FANART = "fanart";
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
public static final String EPISODE = "episode";
|
||||
public static final String SHOWTITLE = "showtitle";
|
||||
public static final String WATCHEDEPISODES = "watchedepisodes";
|
||||
String LABEL = "label";
|
||||
String FANART = "fanart";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String EPISODE = "episode";
|
||||
String SHOWTITLE = "showtitle";
|
||||
String WATCHEDEPISODES = "watchedepisodes";
|
||||
}
|
||||
|
||||
public static class Seasons implements BaseColumns, SyncColumns, SeasonsColumns {
|
||||
|
@ -350,34 +352,34 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + EPISODEID
|
||||
*/
|
||||
public interface EpisodesColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public static final String EPISODEID = "episodeid";
|
||||
String HOST_ID = "host_id";
|
||||
String EPISODEID = "episodeid";
|
||||
|
||||
public final static String TVSHOWID = "tvshowid";
|
||||
public static final String SEASON = "season";
|
||||
public static final String EPISODE = "episode";
|
||||
String TVSHOWID = "tvshowid";
|
||||
String SEASON = "season";
|
||||
String EPISODE = "episode";
|
||||
|
||||
public static final String FANART = "fanart";
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
public static final String PLAYCOUNT = "playcount";
|
||||
public static final String TITLE = "title";
|
||||
public static final String DATEADDED = "dateadded";
|
||||
public static final String FILE = "file";
|
||||
public static final String PLOT = "plot";
|
||||
public static final String DIRECTOR = "director";
|
||||
public static final String RUNTIME = "runtime";
|
||||
public static final String FIRSTAIRED = "firstaired";
|
||||
public static final String RATING = "rating";
|
||||
public static final String SHOWTITLE = "showtitle";
|
||||
public static final String WRITER = "writer";
|
||||
public final static String AUDIO_CHANNELS = "audio_channels";
|
||||
public final static String AUDIO_CODEC = "audio_coded";
|
||||
public final static String AUDIO_LANGUAGE = "audio_language";
|
||||
public final static String SUBTITLES_LANGUAGES = "subtitles_languages";
|
||||
public static final String VIDEO_ASPECT = "video_aspect";
|
||||
public static final String VIDEO_CODEC = "video_codec";
|
||||
public static final String VIDEO_HEIGHT = "video_height";
|
||||
public static final String VIDEO_WIDTH = "video_width";
|
||||
String FANART = "fanart";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String PLAYCOUNT = "playcount";
|
||||
String TITLE = "title";
|
||||
String DATEADDED = "dateadded";
|
||||
String FILE = "file";
|
||||
String PLOT = "plot";
|
||||
String DIRECTOR = "director";
|
||||
String RUNTIME = "runtime";
|
||||
String FIRSTAIRED = "firstaired";
|
||||
String RATING = "rating";
|
||||
String SHOWTITLE = "showtitle";
|
||||
String WRITER = "writer";
|
||||
String AUDIO_CHANNELS = "audio_channels";
|
||||
String AUDIO_CODEC = "audio_coded";
|
||||
String AUDIO_LANGUAGE = "audio_language";
|
||||
String SUBTITLES_LANGUAGES = "subtitles_languages";
|
||||
String VIDEO_ASPECT = "video_aspect";
|
||||
String VIDEO_CODEC = "video_codec";
|
||||
String VIDEO_HEIGHT = "video_height";
|
||||
String VIDEO_WIDTH = "video_width";
|
||||
}
|
||||
|
||||
public static class Episodes implements BaseColumns, SyncColumns, EpisodesColumns {
|
||||
|
@ -443,14 +445,14 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + ARTISTID
|
||||
*/
|
||||
public interface ArtistsColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public static final String ARTISTID = "artistid";
|
||||
String HOST_ID = "host_id";
|
||||
String ARTISTID = "artistid";
|
||||
|
||||
public static final String ARTIST = "artist";
|
||||
public final String DESCRIPTION = "description";
|
||||
public final String GENRE = "genre";
|
||||
public final String FANART = "fanart";
|
||||
public final String THUMBNAIL = "thumbnail";
|
||||
String ARTIST = "artist";
|
||||
String DESCRIPTION = "description";
|
||||
String GENRE = "genre";
|
||||
String FANART = "fanart";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
}
|
||||
|
||||
public static class Artists implements BaseColumns, SyncColumns, ArtistsColumns {
|
||||
|
@ -492,19 +494,19 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + ALBUMID
|
||||
*/
|
||||
public interface AlbumsColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public static final String ALBUMID = "albumid";
|
||||
String HOST_ID = "host_id";
|
||||
String ALBUMID = "albumid";
|
||||
|
||||
public static final String FANART = "fanart";
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
public static final String DISPLAYARTIST = "displayartist";
|
||||
public static final String RATING = "rating";
|
||||
public static final String TITLE = "title";
|
||||
public static final String YEAR = "year";
|
||||
public static final String ALBUMLABEL = "albumlabel";
|
||||
public static final String DESCRIPTION = "description";
|
||||
public static final String PLAYCOUNT = "playcount";
|
||||
public static final String GENRE = "genre";
|
||||
String FANART = "fanart";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String DISPLAYARTIST = "displayartist";
|
||||
String RATING = "rating";
|
||||
String TITLE = "title";
|
||||
String YEAR = "year";
|
||||
String ALBUMLABEL = "albumlabel";
|
||||
String DESCRIPTION = "description";
|
||||
String PLAYCOUNT = "playcount";
|
||||
String GENRE = "genre";
|
||||
}
|
||||
|
||||
public static class Albums implements BaseColumns, SyncColumns, AlbumsColumns {
|
||||
|
@ -565,15 +567,15 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + ALBUMID + SONGID
|
||||
*/
|
||||
public interface SongsColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public static final String ALBUMID = "albumid";
|
||||
public static final String SONGID = "songid";
|
||||
String HOST_ID = "host_id";
|
||||
String ALBUMID = "albumid";
|
||||
String SONGID = "songid";
|
||||
|
||||
public static final String DURATION = "duration";
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
public static final String FILE = "file";
|
||||
public static final String TRACK = "track";
|
||||
public static final String TITLE = "title";
|
||||
String DURATION = "duration";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String FILE = "file";
|
||||
String TRACK = "track";
|
||||
String TITLE = "title";
|
||||
}
|
||||
|
||||
public static class Songs implements BaseColumns, SyncColumns, SongsColumns {
|
||||
|
@ -615,11 +617,11 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + GENREID
|
||||
*/
|
||||
public interface AudioGenresColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public static final String GENREID = "genreid";
|
||||
String HOST_ID = "host_id";
|
||||
String GENREID = "genreid";
|
||||
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
public static final String TITLE = "title";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String TITLE = "title";
|
||||
}
|
||||
|
||||
public static class AudioGenres implements BaseColumns, SyncColumns, AudioGenresColumns {
|
||||
|
@ -661,9 +663,9 @@ public class MediaContract {
|
|||
* All Other IDs refer to XBMC Ids, not Internal ones
|
||||
*/
|
||||
public interface AlbumArtistsColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public static final String ALBUMID = "albumid";
|
||||
public static final String ARTISTID = "artistid";
|
||||
String HOST_ID = "host_id";
|
||||
String ALBUMID = "albumid";
|
||||
String ARTISTID = "artistid";
|
||||
}
|
||||
|
||||
public static class AlbumArtists implements BaseColumns, AlbumArtistsColumns {
|
||||
|
@ -691,9 +693,9 @@ public class MediaContract {
|
|||
* All Other IDs refer to XBMC Ids, not Internal ones
|
||||
*/
|
||||
public interface AlbumGenresColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public static final String ALBUMID = "albumid";
|
||||
public static final String GENREID = "genreid";
|
||||
String HOST_ID = "host_id";
|
||||
String ALBUMID = "albumid";
|
||||
String GENREID = "genreid";
|
||||
}
|
||||
|
||||
public static class AlbumGenres implements BaseColumns, AlbumGenresColumns {
|
||||
|
@ -721,51 +723,51 @@ public class MediaContract {
|
|||
* For XBMC reference/unique key use HOST_ID + MUSICVIDEOID
|
||||
*/
|
||||
public interface MusicVideosColumns {
|
||||
public final static String HOST_ID = "host_id";
|
||||
public final static String MUSICVIDEOID = "musicvideoid";
|
||||
String HOST_ID = "host_id";
|
||||
String MUSICVIDEOID = "musicvideoid";
|
||||
|
||||
// ItemType.DetailsBase
|
||||
//public static final String LABEL = "label";
|
||||
//String LABEL = "label";
|
||||
|
||||
// MediaType.DetailsBase
|
||||
public static final String FANART = "fanart";
|
||||
public static final String THUMBNAIL = "thumbnail";
|
||||
String FANART = "fanart";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
|
||||
// DetailsBase
|
||||
//public static final String ART = "art";
|
||||
public static final String PLAYCOUNT = "playcount";
|
||||
//String ART = "art";
|
||||
String PLAYCOUNT = "playcount";
|
||||
|
||||
// DetailsMedia
|
||||
public static final String TITLE = "title";
|
||||
String TITLE = "title";
|
||||
|
||||
// DetailsItem
|
||||
//public static final String DATEADDED = "dateadded";
|
||||
public static final String FILE = "file";
|
||||
//public static final String LASTPLAYED = "lastplayed";
|
||||
public static final String PLOT = "plot";
|
||||
//String DATEADDED = "dateadded";
|
||||
String FILE = "file";
|
||||
//String LASTPLAYED = "lastplayed";
|
||||
String PLOT = "plot";
|
||||
|
||||
// DetailsFile
|
||||
public static final String DIRECTOR = "director";
|
||||
//public static final String RESUME = "resume";
|
||||
public static final String RUNTIME = "runtime";
|
||||
//public static final String STREAMDETAILS = "streamdetails";
|
||||
public final static String AUDIO_CHANNELS = "audio_channels";
|
||||
public final static String AUDIO_CODEC = "audio_coded";
|
||||
public final static String AUDIO_LANGUAGE = "audio_language";
|
||||
public final static String SUBTITLES_LANGUAGES = "subtitles_languages";
|
||||
public static final String VIDEO_ASPECT = "video_aspect";
|
||||
public static final String VIDEO_CODEC = "video_codec";
|
||||
public static final String VIDEO_HEIGHT = "video_height";
|
||||
public static final String VIDEO_WIDTH = "video_width";
|
||||
String DIRECTOR = "director";
|
||||
//String RESUME = "resume";
|
||||
String RUNTIME = "runtime";
|
||||
//String STREAMDETAILS = "streamdetails";
|
||||
String AUDIO_CHANNELS = "audio_channels";
|
||||
String AUDIO_CODEC = "audio_coded";
|
||||
String AUDIO_LANGUAGE = "audio_language";
|
||||
String SUBTITLES_LANGUAGES = "subtitles_languages";
|
||||
String VIDEO_ASPECT = "video_aspect";
|
||||
String VIDEO_CODEC = "video_codec";
|
||||
String VIDEO_HEIGHT = "video_height";
|
||||
String VIDEO_WIDTH = "video_width";
|
||||
|
||||
// MusicVideo
|
||||
public static final String ALBUM = "album";
|
||||
public static final String ARTIST = "artist";
|
||||
public static final String GENRES = "genre";
|
||||
public static final String STUDIOS = "studio";
|
||||
public static final String TAG = "tag";
|
||||
public static final String TRACK = "track";
|
||||
public static final String YEAR = "year";
|
||||
String ALBUM = "album";
|
||||
String ARTIST = "artist";
|
||||
String GENRES = "genre";
|
||||
String STUDIOS = "studio";
|
||||
String TAG = "tag";
|
||||
String TRACK = "track";
|
||||
String YEAR = "year";
|
||||
}
|
||||
|
||||
public static class MusicVideos implements BaseColumns, SyncColumns, MusicVideosColumns {
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import org.xbmc.kore.host.HostInfo;
|
||||
import org.xbmc.kore.utils.LogUtils;
|
||||
|
||||
|
||||
|
@ -30,31 +31,32 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
private static final String TAG = LogUtils.makeLogTag(MediaDatabase.class);
|
||||
|
||||
private static final String DB_NAME = "xbmc.sqlite";
|
||||
private static final int DB_VERSION = 4;
|
||||
private static final int DB_VERSION_PRE_EVENT_SERVER = 4,
|
||||
DB_VERSION = 5;
|
||||
|
||||
/**
|
||||
* Tables exposed
|
||||
*/
|
||||
public interface Tables {
|
||||
public final static String HOSTS = "hosts";
|
||||
public final static String MOVIES = "movies";
|
||||
public final static String MOVIE_CAST = "movie_cast";
|
||||
public final static String TVSHOWS = "tvshows";
|
||||
public final static String TVSHOWS_CAST = "tvshows_cast";
|
||||
public final static String SEASONS = "seasons";
|
||||
public final static String EPISODES = "episodes";
|
||||
public final static String ARTISTS = "artists";
|
||||
public final static String ALBUMS = "albums";
|
||||
public final static String SONGS = "songs";
|
||||
public final static String AUDIO_GENRES = "audio_genres";
|
||||
public final static String ALBUM_ARTISTS = "album_artists";
|
||||
public final static String ALBUM_GENRES = "album_genres";
|
||||
public final static String MUSIC_VIDEOS = "music_videos";
|
||||
String HOSTS = "hosts";
|
||||
String MOVIES = "movies";
|
||||
String MOVIE_CAST = "movie_cast";
|
||||
String TVSHOWS = "tvshows";
|
||||
String TVSHOWS_CAST = "tvshows_cast";
|
||||
String SEASONS = "seasons";
|
||||
String EPISODES = "episodes";
|
||||
String ARTISTS = "artists";
|
||||
String ALBUMS = "albums";
|
||||
String SONGS = "songs";
|
||||
String AUDIO_GENRES = "audio_genres";
|
||||
String ALBUM_ARTISTS = "album_artists";
|
||||
String ALBUM_GENRES = "album_genres";
|
||||
String MUSIC_VIDEOS = "music_videos";
|
||||
|
||||
/**
|
||||
* Join to get Albums for an Artist
|
||||
*/
|
||||
public final static String ALBUMS_FOR_ARTIST_JOIN =
|
||||
String ALBUMS_FOR_ARTIST_JOIN =
|
||||
ALBUM_ARTISTS + " JOIN " + ALBUMS + " ON " +
|
||||
ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.HOST_ID + "=" + ALBUMS + "." + MediaContract.Albums.HOST_ID +
|
||||
" AND " +
|
||||
|
@ -63,7 +65,7 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
/**
|
||||
* Join to get Artists for an Album
|
||||
*/
|
||||
public final static String ARTISTS_FOR_ALBUM_JOIN =
|
||||
String ARTISTS_FOR_ALBUM_JOIN =
|
||||
ALBUM_ARTISTS + " JOIN " + ARTISTS + " ON " +
|
||||
ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.HOST_ID + "=" + ARTISTS + "." + MediaContract.Artists.HOST_ID +
|
||||
" AND " +
|
||||
|
@ -72,7 +74,7 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
/**
|
||||
* Join to get Album for a Genre
|
||||
*/
|
||||
public final static String ALBUMS_FOR_GENRE_JOIN =
|
||||
String ALBUMS_FOR_GENRE_JOIN =
|
||||
ALBUM_GENRES + " JOIN " + ALBUMS + " ON " +
|
||||
ALBUM_GENRES + "." + MediaContract.AlbumGenres.HOST_ID + "=" + ALBUMS + "." + MediaContract.Albums.HOST_ID +
|
||||
" AND " +
|
||||
|
@ -81,7 +83,7 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
/**
|
||||
* Join to get Genres for an Album
|
||||
*/
|
||||
public final static String GENRES_FOR_ALBUM_JOIN =
|
||||
String GENRES_FOR_ALBUM_JOIN =
|
||||
ALBUM_GENRES + " JOIN " + AUDIO_GENRES + " ON " +
|
||||
ALBUM_GENRES + "." + MediaContract.AlbumGenres.HOST_ID + "=" + AUDIO_GENRES + "." + MediaContract.AudioGenres.HOST_ID +
|
||||
" AND " +
|
||||
|
@ -89,13 +91,13 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
}
|
||||
|
||||
private interface References {
|
||||
final static String HOST_ID =
|
||||
String HOST_ID =
|
||||
"REFERENCES " + Tables.HOSTS + "(" + BaseColumns._ID + ")";
|
||||
final static String ALBUMID =
|
||||
String ALBUMID =
|
||||
"REFERENCES " + Tables.ALBUMS + "(" + MediaContract.AlbumsColumns.ALBUMID + ")";
|
||||
final static String ARTISTID =
|
||||
String ARTISTID =
|
||||
"REFERENCES " + Tables.ARTISTS + "(" + MediaContract.ArtistsColumns.ARTISTID + ")";
|
||||
final static String GENREID =
|
||||
String GENREID =
|
||||
"REFERENCES " + Tables.AUDIO_GENRES + "(" + MediaContract.AudioGenresColumns.GENREID + ")";
|
||||
}
|
||||
|
||||
|
@ -108,17 +110,19 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
|
||||
// Hosts
|
||||
db.execSQL("CREATE TABLE " + Tables.HOSTS + "(" +
|
||||
BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
MediaContract.SyncColumns.UPDATED + " INTEGER NOT NULL," +
|
||||
MediaContract.HostsColumns.NAME + " TEXT, " +
|
||||
MediaContract.HostsColumns.ADDRESS + " TEXT, " +
|
||||
MediaContract.HostsColumns.PROTOCOL + " INTEGER, " +
|
||||
MediaContract.HostsColumns.HTTP_PORT + " INTEGER, " +
|
||||
MediaContract.HostsColumns.TCP_PORT + " INTEGER, " +
|
||||
MediaContract.HostsColumns.USERNAME + " TEXT, " +
|
||||
MediaContract.HostsColumns.PASSWORD + " TEXT, " +
|
||||
MediaContract.HostsColumns.MAC_ADDRESS + " TEXT, " +
|
||||
MediaContract.HostsColumns.WOL_PORT + " INTEGER)"
|
||||
BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
MediaContract.SyncColumns.UPDATED + " INTEGER NOT NULL," +
|
||||
MediaContract.HostsColumns.NAME + " TEXT, " +
|
||||
MediaContract.HostsColumns.ADDRESS + " TEXT, " +
|
||||
MediaContract.HostsColumns.PROTOCOL + " INTEGER, " +
|
||||
MediaContract.HostsColumns.HTTP_PORT + " INTEGER, " +
|
||||
MediaContract.HostsColumns.TCP_PORT + " INTEGER, " +
|
||||
MediaContract.HostsColumns.USERNAME + " TEXT, " +
|
||||
MediaContract.HostsColumns.PASSWORD + " TEXT, " +
|
||||
MediaContract.HostsColumns.MAC_ADDRESS + " TEXT, " +
|
||||
MediaContract.HostsColumns.WOL_PORT + " INTEGER, " +
|
||||
MediaContract.HostsColumns.USE_EVENT_SERVER + " INTEGER, " +
|
||||
MediaContract.HostsColumns.EVENT_SERVER_PORT + " INTEGER)"
|
||||
);
|
||||
|
||||
// Movies
|
||||
|
@ -438,7 +442,20 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// For now just drop old tables and recreate
|
||||
|
||||
switch (oldVersion) {
|
||||
case DB_VERSION_PRE_EVENT_SERVER:
|
||||
// Add USE_EVENT_SERVER and EVENT_SERVER_PORT columns to HOSTS table
|
||||
db.execSQL("ALTER TABLE " + Tables.HOSTS +
|
||||
" ADD COLUMN " + MediaContract.HostsColumns.USE_EVENT_SERVER +
|
||||
" INTEGER DEFAULT 1;");
|
||||
db.execSQL("ALTER TABLE " + Tables.HOSTS +
|
||||
" ADD COLUMN " + MediaContract.HostsColumns.EVENT_SERVER_PORT +
|
||||
" INTEGER DEFAULT " + HostInfo.DEFAULT_EVENT_SERVER_PORT + ";");
|
||||
}
|
||||
}
|
||||
|
||||
private void resetDb(SQLiteDatabase db) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.HOSTS);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.MOVIES);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.MOVIE_CAST);
|
||||
|
@ -454,7 +471,7 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
db.execSQL("DROP TABLE IF EXISTS " + Tables.ALBUM_GENRES);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.MUSIC_VIDEOS);
|
||||
onCreate(db);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokens to move from prefix to suffix when sorting titles
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.xbmc.kore.ui;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
@ -34,7 +35,9 @@ import android.widget.Toast;
|
|||
|
||||
import org.xbmc.kore.R;
|
||||
import org.xbmc.kore.Settings;
|
||||
import org.xbmc.kore.eventclient.EventServerConnection;
|
||||
import org.xbmc.kore.host.HostConnectionObserver;
|
||||
import org.xbmc.kore.host.HostInfo;
|
||||
import org.xbmc.kore.host.HostManager;
|
||||
import org.xbmc.kore.jsonrpc.ApiCallback;
|
||||
import org.xbmc.kore.jsonrpc.HostConnection;
|
||||
|
@ -574,6 +577,7 @@ public class RemoteActivity extends BaseActivity
|
|||
public void playerOnPlay(PlayerType.GetActivePlayersReturnType getActivePlayerResult,
|
||||
PlayerType.PropertyValue getPropertiesResult,
|
||||
ListType.ItemsAll getItemResult) {
|
||||
checkEventServerAvailability();
|
||||
String imageUrl = (TextUtils.isEmpty(getItemResult.fanart)) ?
|
||||
getItemResult.thumbnail : getItemResult.fanart;
|
||||
if ((imageUrl != null) && !imageUrl.equals(lastImageUrl)) {
|
||||
|
@ -599,6 +603,7 @@ public class RemoteActivity extends BaseActivity
|
|||
}
|
||||
|
||||
public void playerOnStop() {
|
||||
checkEventServerAvailability();
|
||||
if (lastImageUrl != null) {
|
||||
setImageViewBackground(null);
|
||||
}
|
||||
|
@ -633,4 +638,30 @@ public class RemoteActivity extends BaseActivity
|
|||
viewPager.setCurrentItem(1);
|
||||
}
|
||||
|
||||
// TODO: Remove this method after deployment of version 1.5.0. The only objective of this is to facilitate the
|
||||
// transition to using EventServer, by checking if it is available, but this needs to be done only once.
|
||||
public void checkEventServerAvailability() {
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean checkedEventServerConnection =
|
||||
preferences.getBoolean(Settings.KEY_PREF_CHECKED_EVENT_SERVER_CONNECTION,
|
||||
Settings.DEFAULT_PREF_CHECKED_EVENT_SERVER_CONNECTION);
|
||||
if (!checkedEventServerConnection) {
|
||||
LogUtils.LOGD(TAG, "Checking EventServer connection implicitely");
|
||||
// Check if EventServer is available
|
||||
final HostInfo hostInfo = hostManager.getHostInfo();
|
||||
EventServerConnection.testEventServerConnection(
|
||||
hostInfo,
|
||||
new EventServerConnection.EventServerConnectionCallback() {
|
||||
@Override
|
||||
public void OnConnectResult(boolean success) {
|
||||
hostInfo.setUseEventServer(success);
|
||||
hostManager.editHost(hostInfo.getId(), hostInfo);
|
||||
}
|
||||
},
|
||||
new Handler());
|
||||
preferences.edit()
|
||||
.putBoolean(Settings.KEY_PREF_CHECKED_EVENT_SERVER_CONNECTION, true)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@ import android.content.res.ColorStateList;
|
|||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
@ -40,6 +40,10 @@ import android.widget.RelativeLayout;
|
|||
import android.widget.TextView;
|
||||
|
||||
import org.xbmc.kore.R;
|
||||
import org.xbmc.kore.eventclient.ButtonCodes;
|
||||
import org.xbmc.kore.eventclient.EventServerConnection;
|
||||
import org.xbmc.kore.eventclient.Packet;
|
||||
import org.xbmc.kore.eventclient.PacketBUTTON;
|
||||
import org.xbmc.kore.host.HostConnectionObserver;
|
||||
import org.xbmc.kore.host.HostInfo;
|
||||
import org.xbmc.kore.host.HostManager;
|
||||
|
@ -56,6 +60,8 @@ import org.xbmc.kore.utils.RepeatListener;
|
|||
import org.xbmc.kore.utils.UIUtils;
|
||||
import org.xbmc.kore.utils.Utils;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
import butterknife.OnClick;
|
||||
|
@ -128,6 +134,9 @@ public class RemoteFragment extends Fragment
|
|||
// Touch listener that provides touch feedbacl
|
||||
private View.OnTouchListener feedbackTouckListener;
|
||||
|
||||
// EventServer connection
|
||||
private EventServerConnection eventServerConnection = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -137,6 +146,8 @@ public class RemoteFragment extends Fragment
|
|||
buttonInAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.button_in);
|
||||
buttonOutAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.button_out);
|
||||
|
||||
createEventServerConnection();
|
||||
|
||||
feedbackTouckListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
|
@ -160,19 +171,30 @@ public class RemoteFragment extends Fragment
|
|||
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_remote, container, false);
|
||||
ButterKnife.inject(this, root);
|
||||
|
||||
// Setup repeat buttons
|
||||
setupRepeatButton(leftButton, new Input.Left());
|
||||
setupRepeatButton(rightButton, new Input.Right());
|
||||
setupRepeatButton(upButton, new Input.Up());
|
||||
setupRepeatButton(downButton, new Input.Down());
|
||||
if (hostManager.getHostInfo().getUseEventServer() &&
|
||||
(eventServerConnection != null)) {
|
||||
// Setup d-pad to use EventServer
|
||||
setupEventServerButton(leftButton, ButtonCodes.REMOTE_LEFT);
|
||||
setupEventServerButton(rightButton, ButtonCodes.REMOTE_RIGHT);
|
||||
setupEventServerButton(upButton, ButtonCodes.REMOTE_UP);
|
||||
setupEventServerButton(downButton, ButtonCodes.REMOTE_DOWN);
|
||||
//setupEventServerButton(selectButton, ButtonCodes.REMOTE_SELECT);
|
||||
} else {
|
||||
// Otherwise, use json-rpc
|
||||
setupRepeatButton(leftButton, new Input.Left());
|
||||
setupRepeatButton(rightButton, new Input.Right());
|
||||
setupRepeatButton(upButton, new Input.Up());
|
||||
setupRepeatButton(downButton, new Input.Down());
|
||||
}
|
||||
setupDefaultButton(selectButton, new Input.Select(), null);
|
||||
|
||||
setupNoRepeatButton(selectButton, new Input.Select(), null);
|
||||
setupNoRepeatButton(backButton, new Input.Back(), null);
|
||||
setupNoRepeatButton(infoButton,
|
||||
new Input.ExecuteAction(Input.ExecuteAction.INFO),
|
||||
new Input.ExecuteAction(Input.ExecuteAction.CODECINFO));
|
||||
setupNoRepeatButton(osdButton, new Input.ExecuteAction(Input.ExecuteAction.OSD), null);
|
||||
setupNoRepeatButton(contextButton, new Input.ExecuteAction(Input.ExecuteAction.CONTEXTMENU), null);
|
||||
// Other buttons
|
||||
setupDefaultButton(backButton, new Input.Back(), null);
|
||||
setupDefaultButton(infoButton,
|
||||
new Input.ExecuteAction(Input.ExecuteAction.INFO),
|
||||
new Input.ExecuteAction(Input.ExecuteAction.CODECINFO));
|
||||
setupDefaultButton(osdButton, new Input.ExecuteAction(Input.ExecuteAction.OSD), null);
|
||||
setupDefaultButton(contextButton, new Input.ExecuteAction(Input.ExecuteAction.CONTEXTMENU), null);
|
||||
|
||||
adjustRemoteButtons();
|
||||
|
||||
|
@ -185,17 +207,6 @@ public class RemoteFragment extends Fragment
|
|||
return root;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Select button callback
|
||||
// * @param v Clicked view
|
||||
// */
|
||||
// @OnClick(R.id.select)
|
||||
// public void onSelectClicked(View v) {
|
||||
// v.startAnimation(buttonInOutAnim);
|
||||
// Input.Select action = new Input.Select();
|
||||
// action.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
|
||||
// }
|
||||
|
||||
@TargetApi(21)
|
||||
private void adjustRemoteButtons() {
|
||||
Resources.Theme theme = getActivity().getTheme();
|
||||
|
@ -244,27 +255,47 @@ public class RemoteFragment extends Fragment
|
|||
public void onResume() {
|
||||
super.onResume();
|
||||
hostConnectionObserver.registerPlayerObserver(this, true);
|
||||
if (eventServerConnection == null)
|
||||
createEventServerConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
hostConnectionObserver.unregisterPlayerObserver(this);
|
||||
if (eventServerConnection != null) {
|
||||
eventServerConnection.quit();
|
||||
eventServerConnection = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void createEventServerConnection() {
|
||||
eventServerConnection = new EventServerConnection(
|
||||
hostManager.getHostInfo(),
|
||||
new EventServerConnection.EventServerConnectionCallback() {
|
||||
@Override
|
||||
public void OnConnectResult(boolean success) {
|
||||
if (!success) {
|
||||
LogUtils.LOGD(TAG, "Couldnt setup EventServer, disabling it");
|
||||
eventServerConnection = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupRepeatButton(View button, final ApiMethod<String> action) {
|
||||
button.setOnTouchListener(new RepeatListener(UIUtils.initialButtonRepeatInterval, UIUtils.buttonRepeatInterval,
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
action.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
|
||||
}
|
||||
}, buttonInAnim, buttonOutAnim));
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
action.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
|
||||
}
|
||||
}, buttonInAnim, buttonOutAnim));
|
||||
}
|
||||
|
||||
private void setupNoRepeatButton(View button,
|
||||
final ApiMethod<String> clickAction,
|
||||
final ApiMethod<String> longClickAction) {
|
||||
private void setupDefaultButton(View button,
|
||||
final ApiMethod<String> clickAction,
|
||||
final ApiMethod<String> longClickAction) {
|
||||
// Set animation
|
||||
button.setOnTouchListener(feedbackTouckListener);
|
||||
if (clickAction != null) {
|
||||
|
@ -286,6 +317,54 @@ public class RemoteFragment extends Fragment
|
|||
}
|
||||
}
|
||||
|
||||
private void setupEventServerButton(View button, final String action) {
|
||||
final Packet packet =
|
||||
new PacketBUTTON(ButtonCodes.MAP_REMOTE, action, false, true, true, (short)0, (byte)0);
|
||||
button.setOnTouchListener(new RepeatListener(UIUtils.initialButtonRepeatInterval, UIUtils.buttonRepeatInterval,
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
eventServerConnection.sendPacket(packet);
|
||||
}
|
||||
}, buttonInAnim, buttonOutAnim));
|
||||
}
|
||||
|
||||
|
||||
// private void setupEventServerButton(View button, final String action) {
|
||||
// short amount = 0;
|
||||
// byte axis = 0;
|
||||
// final Packet packetDown =
|
||||
// new PacketBUTTON(ButtonCodes.MAP_REMOTE, action, true, true, false, amount, axis);
|
||||
// final Packet packetUp =
|
||||
// new PacketBUTTON(ButtonCodes.MAP_REMOTE, action, false, false, false, amount, axis);
|
||||
//
|
||||
// // Set animation and packet
|
||||
// button.setOnTouchListener(new View.OnTouchListener() {
|
||||
// @Override
|
||||
// public boolean onTouch(View v, MotionEvent event) {
|
||||
// switch (event.getAction()) {
|
||||
// case MotionEvent.ACTION_DOWN:
|
||||
// buttonInAnim.setFillAfter(true);
|
||||
// v.startAnimation(buttonInAnim);
|
||||
// eventServerConnection.sendPacket(packetDown);
|
||||
// break;
|
||||
// case MotionEvent.ACTION_UP:
|
||||
// case MotionEvent.ACTION_CANCEL:
|
||||
// v.startAnimation(buttonOutAnim);
|
||||
// eventServerConnection.sendPacket(packetUp);
|
||||
// break;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// });
|
||||
// button.setOnClickListener(new View.OnClickListener() {
|
||||
// @Override
|
||||
// public void onClick(View v) {
|
||||
// // Nothing to do
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
/**
|
||||
* Default callback for methods that don't return anything
|
||||
*/
|
||||
|
|
|
@ -108,21 +108,16 @@ public class AddHostActivity extends BaseActivity
|
|||
|
||||
Bundle args = new Bundle();
|
||||
if (hostInfo != null) {
|
||||
args.putString(HostFragmentManualConfiguration.HOST_NAME,
|
||||
hostInfo.getName());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_ADDRESS,
|
||||
hostInfo.getAddress());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_HTTP_PORT,
|
||||
hostInfo.getHttpPort());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_TCP_PORT,
|
||||
hostInfo.getTcpPort());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_USERNAME,
|
||||
hostInfo.getUsername());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_PASSWORD,
|
||||
hostInfo.getPassword());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_PROTOCOL,
|
||||
hostInfo.getProtocol());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_NAME, hostInfo.getName());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_ADDRESS, hostInfo.getAddress());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_HTTP_PORT, hostInfo.getHttpPort());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_TCP_PORT, hostInfo.getTcpPort());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_USERNAME, hostInfo.getUsername());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_PASSWORD, hostInfo.getPassword());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_PROTOCOL, hostInfo.getProtocol());
|
||||
// Ignore Mac Address and Wol Port
|
||||
args.putBoolean(HostFragmentManualConfiguration.HOST_USE_EVENT_SERVER, hostInfo.getUseEventServer());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_EVENT_SERVER_PORT, hostInfo.getEventServerPort());
|
||||
|
||||
// Send this fragment straight to test
|
||||
args.putBoolean(HostFragmentManualConfiguration.GO_STRAIGHT_TO_TEST, true);
|
||||
|
|
|
@ -271,7 +271,7 @@ public class AddHostFragmentZeroconf extends Fragment {
|
|||
String hostAddress = addresses[0];
|
||||
int hostHttpPort = selectedServiceInfo.getPort();
|
||||
HostInfo selectedHostInfo = new HostInfo(hostName, hostAddress, HostConnection.PROTOCOL_TCP,
|
||||
hostHttpPort, HostInfo.DEFAULT_TCP_PORT, null, null);
|
||||
hostHttpPort, HostInfo.DEFAULT_TCP_PORT, null, null, true, HostInfo.DEFAULT_EVENT_SERVER_PORT);
|
||||
|
||||
listener.onAddHostZeroconfFoundHost(selectedHostInfo);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.xbmc.kore.R;
|
|||
import org.xbmc.kore.host.HostInfo;
|
||||
import org.xbmc.kore.host.HostManager;
|
||||
import org.xbmc.kore.ui.BaseActivity;
|
||||
import org.xbmc.kore.utils.LogUtils;
|
||||
|
||||
/**
|
||||
* Edits a host
|
||||
|
@ -61,21 +62,25 @@ public class EditHostActivity extends BaseActivity implements
|
|||
args.putString(HostFragmentManualConfiguration.HOST_NAME,
|
||||
selectedHostInfo.getName());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_ADDRESS,
|
||||
selectedHostInfo.getAddress());
|
||||
selectedHostInfo.getAddress());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_HTTP_PORT,
|
||||
selectedHostInfo.getHttpPort());
|
||||
selectedHostInfo.getHttpPort());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_TCP_PORT,
|
||||
selectedHostInfo.getTcpPort());
|
||||
selectedHostInfo.getTcpPort());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_USERNAME,
|
||||
selectedHostInfo.getUsername());
|
||||
selectedHostInfo.getUsername());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_PASSWORD,
|
||||
selectedHostInfo.getPassword());
|
||||
selectedHostInfo.getPassword());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_PROTOCOL,
|
||||
selectedHostInfo.getProtocol());
|
||||
selectedHostInfo.getProtocol());
|
||||
args.putString(HostFragmentManualConfiguration.HOST_MAC_ADDRESS,
|
||||
selectedHostInfo.getMacAddress());
|
||||
selectedHostInfo.getMacAddress());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_WOL_PORT,
|
||||
selectedHostInfo.getWolPort());
|
||||
selectedHostInfo.getWolPort());
|
||||
args.putBoolean(HostFragmentManualConfiguration.HOST_USE_EVENT_SERVER,
|
||||
selectedHostInfo.getUseEventServer());
|
||||
args.putInt(HostFragmentManualConfiguration.HOST_EVENT_SERVER_PORT,
|
||||
selectedHostInfo.getEventServerPort());
|
||||
editFragment.setArguments(args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.app.ProgressDialog;
|
|||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -32,6 +33,8 @@ import android.widget.EditText;
|
|||
import android.widget.Toast;
|
||||
|
||||
import org.xbmc.kore.R;
|
||||
import org.xbmc.kore.Settings;
|
||||
import org.xbmc.kore.eventclient.EventServerConnection;
|
||||
import org.xbmc.kore.host.HostInfo;
|
||||
import org.xbmc.kore.jsonrpc.ApiCallback;
|
||||
import org.xbmc.kore.jsonrpc.ApiException;
|
||||
|
@ -62,7 +65,9 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
HOST_PASSWORD = PREFIX + ".host_password",
|
||||
HOST_MAC_ADDRESS = PREFIX + ".host_mac_address",
|
||||
HOST_WOL_PORT = PREFIX + ".host_wol_port",
|
||||
HOST_PROTOCOL = PREFIX + ".host_protocol";
|
||||
HOST_PROTOCOL = PREFIX + ".host_protocol",
|
||||
HOST_USE_EVENT_SERVER = PREFIX + ".host_use_event_server",
|
||||
HOST_EVENT_SERVER_PORT = PREFIX + ".host_event_server_port";
|
||||
public static final String GO_STRAIGHT_TO_TEST = PREFIX + ".go_straight_to_test";
|
||||
|
||||
/**
|
||||
|
@ -86,6 +91,8 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
@InjectView(R.id.xbmc_mac_address) EditText xbmcMacAddressEditText;
|
||||
@InjectView(R.id.xbmc_wol_port) EditText xbmcWolPortEditText;
|
||||
@InjectView(R.id.xbmc_use_tcp) CheckBox xbmcUseTcpCheckbox;
|
||||
@InjectView(R.id.xbmc_use_event_server) CheckBox xbmcUseEventServerCheckbox;
|
||||
@InjectView(R.id.xbmc_event_server_port) EditText xbmcEventServerPortEditText;
|
||||
|
||||
// Handler for callbacks
|
||||
final Handler handler = new Handler();
|
||||
|
@ -104,6 +111,13 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
}
|
||||
});
|
||||
|
||||
xbmcUseEventServerCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
xbmcEventServerPortEditText.setEnabled(isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
// Check if we were given a host info
|
||||
String hostName = getArguments().getString(HOST_NAME);
|
||||
String hostAddress = getArguments().getString(HOST_ADDRESS);
|
||||
|
@ -114,6 +128,8 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
int hostProtocol = getArguments().getInt(HOST_PROTOCOL, HostConnection.PROTOCOL_TCP);
|
||||
String hostMacAddress = getArguments().getString(HOST_MAC_ADDRESS);
|
||||
int hostWolPort = getArguments().getInt(HOST_WOL_PORT, HostInfo.DEFAULT_WOL_PORT);
|
||||
boolean hostUseEventServer = getArguments().getBoolean(HOST_USE_EVENT_SERVER, true);
|
||||
int hostEventServerPort = getArguments().getInt(HOST_EVENT_SERVER_PORT, HostInfo.DEFAULT_EVENT_SERVER_PORT);
|
||||
|
||||
if (hostAddress != null) {
|
||||
xbmcNameEditText.setText(hostName);
|
||||
|
@ -133,6 +149,11 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
xbmcMacAddressEditText.setText(hostMacAddress);
|
||||
if (hostWolPort != HostInfo.DEFAULT_WOL_PORT)
|
||||
xbmcWolPortEditText.setText(String.valueOf(hostWolPort));
|
||||
|
||||
xbmcUseEventServerCheckbox.setChecked(hostUseEventServer);
|
||||
xbmcEventServerPortEditText.setEnabled(xbmcUseEventServerCheckbox.isChecked());
|
||||
if (hostEventServerPort != HostInfo.DEFAULT_EVENT_SERVER_PORT)
|
||||
xbmcEventServerPortEditText.setText(String.valueOf(hostEventServerPort));
|
||||
}
|
||||
|
||||
return root;
|
||||
|
@ -230,6 +251,15 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
// Ignoring this exception and keeping WoL port at the default value
|
||||
}
|
||||
|
||||
boolean xbmcUseEventServer = xbmcUseEventServerCheckbox.isChecked();
|
||||
aux = xbmcEventServerPortEditText.getText().toString();
|
||||
int xbmcEventServerPort;
|
||||
try {
|
||||
xbmcEventServerPort = TextUtils.isEmpty(aux) ? HostInfo.DEFAULT_EVENT_SERVER_PORT : Integer.valueOf(aux);
|
||||
} catch (NumberFormatException exc) {
|
||||
xbmcEventServerPort = -1;
|
||||
}
|
||||
|
||||
// Check Xbmc name and address
|
||||
if (TextUtils.isEmpty(xbmcName)) {
|
||||
Toast.makeText(getActivity(), R.string.wizard_no_name_specified, Toast.LENGTH_SHORT).show();
|
||||
|
@ -247,6 +277,10 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
Toast.makeText(getActivity(), R.string.wizard_invalid_tcp_port_specified, Toast.LENGTH_SHORT).show();
|
||||
xbmcTcpPortEditText.requestFocus();
|
||||
return;
|
||||
} else if (xbmcEventServerPort <= 0) {
|
||||
Toast.makeText(getActivity(), R.string.wizard_invalid_tcp_port_specified, Toast.LENGTH_SHORT).show();
|
||||
xbmcEventServerPortEditText.requestFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
// If username or password empty, set it to null
|
||||
|
@ -257,7 +291,9 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
|
||||
// Ok, let's try to ping the host
|
||||
final HostInfo checkedHostInfo = new HostInfo(xbmcName, xbmcAddress, xbmcProtocol,
|
||||
xbmcHttpPort, xbmcTcpPort, xbmcUsername, xbmcPassword);
|
||||
xbmcHttpPort, xbmcTcpPort,
|
||||
xbmcUsername, xbmcPassword,
|
||||
xbmcUseEventServer, xbmcEventServerPort);
|
||||
checkedHostInfo.setMacAddress(macAddress);
|
||||
checkedHostInfo.setWolPort(xbmcWolPort);
|
||||
|
||||
|
@ -288,9 +324,9 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
if (hostInfo.getProtocol() == HostConnection.PROTOCOL_TCP) {
|
||||
chainCallCheckTcpConnection(hostConnection, hostInfo);
|
||||
} else {
|
||||
// We're done
|
||||
// No TCP, check EventServer
|
||||
hostConnection.disconnect();
|
||||
hostConnectionChecked(hostInfo);
|
||||
chainCallCheckEventServerConnection(hostInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,8 +348,8 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
// Great, we managed to connect through HTTP and TCP
|
||||
LogUtils.LOGD(TAG, "Successfully connected to new host through TCP.");
|
||||
hostConnection.disconnect();
|
||||
// Notify connection checked through TCP
|
||||
hostConnectionChecked(hostInfo);
|
||||
// Check EventServer
|
||||
chainCallCheckEventServerConnection(hostInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -322,11 +358,39 @@ public class HostFragmentManualConfiguration extends Fragment {
|
|||
LogUtils.LOGD(TAG, "Couldn't connect to host through TCP. Message: " + description);
|
||||
hostConnection.disconnect();
|
||||
hostInfo.setProtocol(HostConnection.PROTOCOL_HTTP);
|
||||
hostConnectionChecked(hostInfo);
|
||||
// Check EventServer
|
||||
chainCallCheckEventServerConnection(hostInfo);
|
||||
}
|
||||
}, handler);
|
||||
}
|
||||
|
||||
private void chainCallCheckEventServerConnection(final HostInfo hostInfo) {
|
||||
if (hostInfo.getUseEventServer()) {
|
||||
EventServerConnection.testEventServerConnection(
|
||||
hostInfo,
|
||||
new EventServerConnection.EventServerConnectionCallback() {
|
||||
@Override
|
||||
public void OnConnectResult(boolean success) {
|
||||
|
||||
LogUtils.LOGD(TAG, "Check ES connection: " + success);
|
||||
if (success) {
|
||||
hostConnectionChecked(hostInfo);
|
||||
} else {
|
||||
hostInfo.setUseEventServer(false);
|
||||
hostConnectionChecked(hostInfo);
|
||||
}
|
||||
}
|
||||
},
|
||||
handler);
|
||||
} else {
|
||||
hostConnectionChecked(hostInfo);
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(getActivity())
|
||||
.edit()
|
||||
.putBoolean(Settings.KEY_PREF_CHECKED_EVENT_SERVER_CONNECTION, true)
|
||||
.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* The connection was checked, and hostInfo has all the correct parameters to communicate
|
||||
* with it
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/xbmc_name"
|
||||
android:layout_alignRight="@id/xbmc_name"
|
||||
android:layout_alignEnd="@id/xbmc_name"
|
||||
|
||||
android:inputType="number"
|
||||
android:ems="4"
|
||||
|
@ -79,7 +80,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/xbmc_http_port"
|
||||
android:layout_alignLeft="@id/xbmc_name"
|
||||
android:layout_alignStart="@id/xbmc_name"
|
||||
android:layout_toLeftOf="@id/xbmc_http_port"
|
||||
android:layout_toStartOf="@id/xbmc_http_port"
|
||||
|
||||
android:inputType="textNoSuggestions"
|
||||
android:hint="@string/wizard_xbmc_ip"/>
|
||||
|
@ -91,7 +94,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/xbmc_ip_address"
|
||||
android:layout_alignLeft="@id/xbmc_name"
|
||||
android:layout_alignStart="@id/xbmc_name"
|
||||
android:layout_alignRight="@id/xbmc_name"
|
||||
android:layout_alignEnd="@id/xbmc_name"
|
||||
|
||||
android:inputType="textNoSuggestions"
|
||||
android:hint="@string/wizard_xbmc_username"/>
|
||||
|
@ -103,7 +108,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/xbmc_username"
|
||||
android:layout_alignLeft="@id/xbmc_name"
|
||||
android:layout_alignStart="@id/xbmc_name"
|
||||
android:layout_alignRight="@id/xbmc_name"
|
||||
android:layout_alignEnd="@id/xbmc_name"
|
||||
|
||||
android:inputType="textPassword"
|
||||
android:hint="@string/wizard_xbmc_password"/>
|
||||
|
@ -124,6 +131,7 @@
|
|||
android:layout_below="@android:id/text1"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_alignRight="@id/xbmc_name"
|
||||
android:layout_alignEnd="@id/xbmc_name"
|
||||
android:inputType="number"
|
||||
android:ems="7"
|
||||
android:hint="@string/wizard_xbmc_tcp_port"/>
|
||||
|
@ -134,17 +142,46 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/xbmc_tcp_port"
|
||||
android:layout_alignLeft="@id/xbmc_name"
|
||||
android:layout_alignStart="@id/xbmc_name"
|
||||
android:layout_toLeftOf="@id/xbmc_tcp_port"
|
||||
android:layout_toStartOf="@id/xbmc_tcp_port"
|
||||
android:text="@string/wizard_xbmc_use_tcp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/xbmc_event_server_port"
|
||||
style="@style/TextAppearance.EditText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/xbmc_tcp_port"
|
||||
android:layout_alignLeft="@id/xbmc_tcp_port"
|
||||
android:layout_alignStart="@id/xbmc_tcp_port"
|
||||
android:layout_alignRight="@id/xbmc_tcp_port"
|
||||
android:layout_alignEnd="@id/xbmc_tcp_port"
|
||||
android:inputType="number"
|
||||
android:ems="7"
|
||||
android:hint="@string/wizard_xbmc_event_server_port"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/xbmc_use_event_server"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/xbmc_event_server_port"
|
||||
android:layout_alignLeft="@id/xbmc_name"
|
||||
android:layout_alignStart="@id/xbmc_name"
|
||||
android:layout_toLeftOf="@id/xbmc_event_server_port"
|
||||
android:layout_toStartOf="@id/xbmc_event_server_port"
|
||||
android:text="@string/wizard_xbmc_use_event_server"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/xbmc_wol_port"
|
||||
style="@style/TextAppearance.EditText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/xbmc_tcp_port"
|
||||
android:layout_alignLeft="@id/xbmc_tcp_port"
|
||||
android:layout_alignRight="@id/xbmc_tcp_port"
|
||||
android:layout_below="@+id/xbmc_event_server_port"
|
||||
android:layout_alignLeft="@id/xbmc_event_server_port"
|
||||
android:layout_alignStart="@id/xbmc_event_server_port"
|
||||
android:layout_alignRight="@id/xbmc_event_server_port"
|
||||
android:layout_alignEnd="@id/xbmc_event_server_port"
|
||||
android:inputType="number"
|
||||
android:hint="@string/wizard_xbmc_wol_port"/>
|
||||
|
||||
|
@ -155,7 +192,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/xbmc_wol_port"
|
||||
android:layout_alignLeft="@id/xbmc_name"
|
||||
android:layout_alignStart="@id/xbmc_name"
|
||||
android:layout_toLeftOf="@id/xbmc_wol_port"
|
||||
android:layout_toStartOf="@id/xbmc_wol_port"
|
||||
android:inputType="text"
|
||||
android:hint="@string/wizard_xbmc_mac_address"/>
|
||||
|
||||
|
|
|
@ -98,11 +98,14 @@
|
|||
<string name="wizard_xbmc_mac_address">MAC address</string>
|
||||
<string name="wizard_xbmc_wol_port">WoL port (9)</string>
|
||||
<string name="wizard_xbmc_use_tcp">Use TCP</string>
|
||||
<string name="wizard_xbmc_event_server_port">ES Port (9777)</string>
|
||||
<string name="wizard_xbmc_use_event_server">Use EventServer</string>
|
||||
|
||||
<string name="wizard_no_name_specified">Please specify a name for this media center, so you can identify it later.</string>
|
||||
<string name="wizard_no_address_specified">Please specify the address of this media center, so I can locate it.</string>
|
||||
<string name="wizard_invalid_http_port_specified">Please specify a valid HTTP port for this media center, so I can locate it.</string>
|
||||
<string name="wizard_invalid_tcp_port_specified">Please specify a valid TCP port for this media center, so I can locate it.</string>
|
||||
<string name="wizard_invalid_http_port_specified">Please specify a valid HTTP port for this media center.</string>
|
||||
<string name="wizard_invalid_tcp_port_specified">Please specify a valid TCP port for this media center.</string>
|
||||
<string name="wizard_invalid_es_port_specified">Please specify a valid EventServer port for this media center.</string>
|
||||
|
||||
<string name="wizard_connecting_to_xbmc_title">Connecting to %1$s…</string>
|
||||
<string name="wizard_connecting_to_xbmc_message">Please wait while I try to connect to your media center…</string>
|
||||
|
|
Loading…
Reference in New Issue