// --------------------------------------------------------------------------- // jWebSocket - Copyright (c) 2010 jwebsocket.org // --------------------------------------------------------------------------- // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 3 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 Lesser General Public License for // more details. // You should have received a copy of the GNU Lesser General Public License along // with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>. // --------------------------------------------------------------------------- package org.jwebsocket.android.library; import java.util.Properties; import org.jwebsocket.api.WebSocketClientEvent; import org.jwebsocket.api.WebSocketClientTokenListener; import org.jwebsocket.api.WebSocketPacket; import org.jwebsocket.client.token.BaseTokenClient; import org.jwebsocket.kit.WebSocketException; import org.jwebsocket.token.Token; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Log; import android.widget.Toast; /** * jWebSocket android service that runs in a different process than the * application. Because it runs in another process, the client code using this * process must use IPC to interact with it. Please follow the sample * application to see the usage of this service. * <p> * Note that the most applications do not need to deal with the complexity shown * here. If your application simply has a service running in its own process, * the {@code JWC} is a simpler way to interact with it. * </p> * * @author puran */ public class JWSAndroidRemoteService extends Service { /** * This is the list of callbacks that have been registered with the service. */ final RemoteCallbackList<IJWSAndroidRemoteServiceCallback> jwsCallbackList = new RemoteCallbackList<IJWSAndroidRemoteServiceCallback>(); private final static int MT_OPENED = 0; private final static int MT_PACKET = 1; private final static int MT_CLOSED = 2; private final static int MT_TOKEN = 3; private final static int MT_ERROR = -1; private final static String CONFIG_FILE = "jWebSocket"; private static String jwsURL = "ws://jwebsocket.org:8787"; private static BaseTokenClient tokenClient; @Override public void onCreate() { tokenClient = new BaseTokenClient(); Properties lProps = new Properties(); try { lProps.load(openFileInput(CONFIG_FILE)); } catch (Exception ex) { Toast.makeText(getApplicationContext(), ex.getClass().getSimpleName() + ":" + ex.getMessage(), Toast.LENGTH_SHORT).show(); } jwsURL = (String) lProps.getProperty("url", "http://jwebsocket.org:8787/"); } /** * Handler used to invoke the callback methods based on the remote interface operations. */ private final Handler jwsHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MT_ERROR: broadCastMessageToCallback(msg); break; case MT_OPENED: broadCastMessageToCallback(msg); default: super.handleMessage(msg); } } }; /** * Broadcast the given message to all the callback listeners * @param message the message object */ private void broadCastMessageToCallback(Message message) { final int N = jwsCallbackList.beginBroadcast(); for (int i = 0; i < N; i++) { try { String error = (String) message.obj; jwsCallbackList.getBroadcastItem(i).onError(error); } catch (RemoteException e) { // The RemoteCallbackList will take care of removing // the dead object for us. } } jwsCallbackList.finishBroadcast(); } /** * This is the actual <tt>jWebSocket</tt> {@code BaseTokenClient} based * implementation of the remote {@code JWSAndroidRemoteService} interface. * Note that no exception thrown by the remote process can be sent back to the * client. */ private final IJWSAndroidRemoteService.Stub mBinder = new IJWSAndroidRemoteService.Stub() { private void handleException(String tag, String error, Throwable e) { Log.e(tag, error, e); Message errorMsg = Message.obtain(jwsHandler, MT_ERROR, e.getMessage()); jwsHandler.sendMessage(errorMsg); } @Override public void open() throws RemoteException { try { tokenClient.open(jwsURL); } catch (WebSocketException e) { handleException("OPEN", "Error opening jWebSocket connection", e); } } @Override public void close() throws RemoteException { try { tokenClient.close(); } catch (WebSocketException e) { handleException("CLOSE", "Error closing jWebSocket connection", e); } } @Override public void disconnect() throws RemoteException { try { tokenClient.disconnect(); } catch (WebSocketException e) { handleException("DISCONNECT", "Error disconnecting from the jWebSocket server", e); } } @Override public void send(String data) throws RemoteException { try { tokenClient.send(data, "UTF-8"); } catch (WebSocketException e) { handleException("SEND", "Error sending data to the jWebSocket server", e); } } @Override public void sendText(String target, String data) throws RemoteException { try { tokenClient.sendText(target, data); } catch (WebSocketException e) { handleException("SENDTEXT", "Error sending text data to the jWebSocket server", e); } } @Override public void broadcastText(String data) throws RemoteException { try { tokenClient.broadcastText(data); } catch (WebSocketException e) { handleException("BROADCAST", "Error broadcasting data to the jWebSocket server", e); } } @Override public void sendToken(ParcelableToken token) throws RemoteException { try { tokenClient.sendToken(token.getToken()); } catch (WebSocketException e) { handleException("SENDTOKEN", "Error sending token data to the jWebSocket server", e); } } @Override public void saveFile(String fileName, String scope, boolean notify, byte[] data) throws RemoteException { try { tokenClient.saveFile(data, fileName, scope, notify); } catch (WebSocketException e) { handleException("FILESAVE", "Error saving file to jWebSocket server", e); } } @Override public String getUsername() throws RemoteException { return tokenClient.getUsername(); } @Override public void login(String aUsername, String aPassword) throws RemoteException { try { tokenClient.login(aUsername, aPassword); } catch (WebSocketException e) { handleException("LOGIN", "Error login to jWebSocket server", e); } } @Override public void logout() throws RemoteException { try { tokenClient.logout(); } catch (WebSocketException e) { handleException("LOGOUT", "Error logout from jWebSocket server", e); } } @Override public void ping(boolean echo) throws RemoteException { //TODO://fix this either display a notification or something visible to the user try { tokenClient.ping(echo); } catch (WebSocketException e) { handleException("PING", "Error ping operation to jWebSocket server", e); } } @Override public void getConnections() throws RemoteException { //TODO: implement this it should return something.. //need a fix in TokenClient itself } @Override public boolean isAuthenticated() throws RemoteException { return tokenClient.isAuthenticated(); } @Override public void registerCallback(IJWSAndroidRemoteServiceCallback cb) throws RemoteException { jwsCallbackList.register(cb); } @Override public void unregisterCallback(IJWSAndroidRemoteServiceCallback cb) throws RemoteException { jwsCallbackList.unregister(cb); } }; /** * When binding to the service, we return an interface to our messenger for * sending messages to the service. */ @Override public IBinder onBind(Intent intent) { if (IJWSAndroidRemoteService.class.getName().equals(intent.getAction())) { return mBinder; } return null; } /** * Token listener to receives the callback event from jWebSocket token client */ class Listener implements WebSocketClientTokenListener { public void processOpened(WebSocketClientEvent aEvent) { Message lMsg = new Message(); lMsg.what = MT_OPENED; jwsHandler.sendMessage(lMsg); } public void processPacket(WebSocketClientEvent aEvent, WebSocketPacket aPacket) { Message lMsg = new Message(); lMsg.what = MT_PACKET; lMsg.obj = aPacket; jwsHandler.sendMessage(lMsg); } public void processToken(WebSocketClientEvent aEvent, Token aToken) { Message lMsg = new Message(); lMsg.what = MT_TOKEN; lMsg.obj = aToken; jwsHandler.sendMessage(lMsg); } public void processClosed(WebSocketClientEvent aEvent) { Message lMsg = new Message(); lMsg.what = MT_CLOSED; jwsHandler.sendMessage(lMsg); } } }