/******************************************************************************* * Code contributed to the webinos project * * 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. * * Copyright 2011-2012 Paddy Byers * ******************************************************************************/ package org.webinos.android.app.wrt.channel; import java.util.ArrayList; import java.util.HashMap; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; public class WebinosSocketService extends Service { private static final String TAG = "org.webinos.android.app.wrt.channel.WebinosSocketServer"; private static WebinosSocketService theService; private static ArrayList<LaunchListener> listeners = new ArrayList<LaunchListener>(); private Messenger messenger; private HashMap<String, ClientConnection> clients = new HashMap<String, ClientConnection>(); private ConnectionListener connectionListener; public interface LaunchListener { public void onLaunch(WebinosSocketService service); } public interface ConnectionListener { public void onConnection(ClientConnection client); } public static WebinosSocketService getInstance(LaunchListener listener) { WebinosSocketService result; synchronized(listeners) { result = theService; if(result == null && listener != null) { listeners.add(listener); } } return result; } public interface ClientListener { public void onMessage(String message); public void onClose(String reason); public void onError(String reason); } public static class ClientConnection { public int id; public String installId; public String instanceId; public Messenger messenger; public ClientListener listener; } @Override public void onCreate() { theService = this; messenger = new Messenger(new IncomingHandler()); synchronized(listeners) { theService = this; for(LaunchListener listener : listeners) { listener.onLaunch(this); listeners.remove(listener); } } super.onCreate(); } public void setConnectionListener(ConnectionListener listener) { connectionListener = listener; } private void removeClient(String clientKey, String reason) { ClientConnection client = clients.get(clientKey); if(client != null) { if(client.listener != null) client.listener.onClose(reason); clients.remove(clientKey); } } private class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { ClientConnection client; Log.v(TAG, "handleMessage: msg: " + msg.toString()); int clientId = ProtocolConstants.whatToId(msg.what); switch (ProtocolConstants.whatToMsg(msg.what)) { case ProtocolConstants.MSG_REGISTER: Log.v(TAG, "IncomingHander: register"); break; case ProtocolConstants.MSG_UNREGISTER: Log.v(TAG, "IncomingHander: unregister"); break; case ProtocolConstants.MSG_CONNECT: Log.v(TAG, "IncomingHander: connect"); /* construct new ClientConnection */ client = new ClientConnection(); Bundle bundle = (Bundle)msg.obj; client.installId = bundle.getString("installId"); client.instanceId = bundle.getString("instanceId"); client.id = ProtocolConstants.whatToId(msg.what); client.messenger = msg.replyTo; clients.put(String.valueOf(client.id), client); if(connectionListener != null) connectionListener.onConnection(client); break; case ProtocolConstants.MSG_DISCONNECT: Log.v(TAG, "IncomingHander: disconnect"); removeClient(String.valueOf(clientId), "Connection disconnected by client"); break; case ProtocolConstants.MSG_DATA: Log.v(TAG, "IncomingHander: data"); String data = ((Bundle)msg.obj).getString("data"); client = clients.get(String.valueOf(clientId)); if(client != null && client.listener != null) client.listener.onMessage(data); break; default: super.handleMessage(msg); } Log.v(TAG, "handleMessage: ret"); } } @Override public IBinder onBind(Intent intent) { Log.v(TAG, "onBind()"); IBinder result = messenger.getBinder(); return result; } @Override public boolean onUnbind(Intent intent) { Log.v(TAG, "onUnbind()"); for(String clientKey : clients.keySet()) { removeClient(clientKey, "WRT exited"); } return super.onUnbind(intent); } public void sendMessage(ClientConnection client, String message) { Bundle messageBundle = new Bundle(); messageBundle.putString("data", message); Message msg = Message.obtain(null, ProtocolConstants.toWhat(ProtocolConstants.MSG_DATA, client.id), messageBundle); try { client.messenger.send(msg); } catch(RemoteException e) { Log.v(TAG, "RemoteException attempting to send message: ", e); } } }