package com.xconns.samples.chat; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; 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; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import com.xconns.peerdevicenet.Router; public class ChatByMessengerActivity extends Activity { // Debugging private static final String TAG = "ChatByMessengerActivity"; /** Messenger for communicating with service. */ Messenger mService = null; private static final String groupId = "WifiChat"; /** * Handler of incoming messages from service. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case Router.MsgId.RECV_MSG: // append peer msg to chat area byte[] data = msg.getData().getByteArray(Router.MSG_DATA); mChatArrayAdapter.add("Peer: " + new String(data)); break; case Router.MsgId.SELF_JOIN: // append peer msg to chat area String[] pnames = msg.getData().getStringArray( Router.PEER_NAMES); String[] paddrs = msg.getData().getStringArray( Router.PEER_ADDRS); if (pnames != null && pnames.length > 0 && paddrs != null && paddrs.length > 0) { for (int i = 0; i < pnames.length; i++) { mChatArrayAdapter.add("Peer join : " + pnames[i] + ":" + paddrs[i]); } numPeer = pnames.length; Log.d(TAG, "self_join found peers: " + numPeer); mSendButton.setEnabled(true); } break; case Router.MsgId.PEER_JOIN: // append peer msg to chat area String pname = msg.getData().getString(Router.PEER_NAME); String paddr = msg.getData().getString(Router.PEER_ADDR); if (pname != null && paddr != null) { mChatArrayAdapter.add("Peer join : " + pname + ":" + paddr); numPeer++; mSendButton.setEnabled(true); } break; case Router.MsgId.PEER_LEAVE: // append peer msg to chat area pname = msg.getData().getString(Router.PEER_NAME); paddr = msg.getData().getString(Router.PEER_ADDR); if (pname != null && paddr != null) { mChatArrayAdapter .add("Peer leave : " + pname + ":" + paddr); numPeer--; if (numPeer <= 0) { numPeer = 0; mSendButton.setEnabled(false); } } break; case Router.MsgId.ERROR: String err = msg.getData().getString(Router.MSG_DATA); mChatArrayAdapter.add(err); // Toast.makeText(ChatByIntentingActivity.this, // "connection failed: "+msg, Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. We are communicating with our // service through an IDL interface, so get a client-side // representation of that from the raw service object. mService = new Messenger(service); mChatArrayAdapter.add("Service attached."); // register callback msnger try { Message msg = Message.obtain(null, Router.MsgId.REGISTER_RECEIVER); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even // do anything with it; we can count on soon being // disconnected (and then reconnected if it can be restarted) // so there is no need to do anything here. // Log.e(TAG, e.getMessage()); } // join group Bundle b = new Bundle(); b.putString(Router.GROUP_ID, groupId); Message msg = Message.obtain(null, Router.MsgId.JOIN_GROUP); msg.setData(b); try { mService.send(msg); } catch (RemoteException e) { // Log.e(TAG, e.getMessage()); } } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; mChatArrayAdapter.add("Service disconnected."); } }; void doBindService() { // Establish a connection with the service. We use an explicit // class name because there is no reason to be able to let other // applications replace our component. Intent intent = new Intent("com.xconns.peerdevicenet.Messenger"); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); mChatArrayAdapter.add("Service connecting."); } void doUnbindService() { // leave group Bundle b = new Bundle(); b.putString(Router.GROUP_ID, groupId); Message msg = Message.obtain(null, Router.MsgId.LEAVE_GROUP); msg.setData(b); try { mService.send(msg); } catch (RemoteException e) { // Log.e(TAG, e.getMessage()); } // unregister callback msnger if (mService != null) { try { msg = Message.obtain(null, Router.MsgId.UNREGISTER_RECEIVER); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // There is nothing special we need to do if the service // has crashed. } } // Detach our existing connection. unbindService(mConnection); mChatArrayAdapter.add("Service unbinding."); } private ArrayAdapter<String> mChatArrayAdapter; private ListView mChatView; private EditText mOutMsgText; private Button mSendButton; int numPeer = 0; /** * Standard initialization of this activity. Set up the UI, then wait for * the user to poke it before doing anything. */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Initialize the array adapter for the conversation thread mChatArrayAdapter = new ArrayAdapter<String>(this, R.layout.message); mChatView = (ListView) findViewById(R.id.chat_msgs); mChatView.setAdapter(mChatArrayAdapter); // Initialize the compose field with a listener for the return key mOutMsgText = (EditText) findViewById(R.id.msg_out); mOutMsgText .setOnEditorActionListener(new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView view, int actionId, KeyEvent event) { // If the action is a key-up event on the return key, // send the message if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) { String message = view.getText().toString(); view.setText(""); sendMsg(message); } return true; } }); // Initialize the send button with a listener that for click events mSendButton = (Button) findViewById(R.id.button_send); mSendButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { String message = mOutMsgText.getText().toString(); sendMsg(message); mOutMsgText.setText(""); } }); mSendButton.setEnabled(false); // bind to router messenger doBindService(); } @Override public void onDestroy() { doUnbindService(); super.onDestroy(); } private void sendMsg(String msg_data) { // show my msg first mChatArrayAdapter.add("Me: " + msg_data); // send my msg if (mService != null) { Message msg = Message.obtain(null, Router.MsgId.SEND_MSG, 0, 0); Bundle b = new Bundle(); b.putByteArray(Router.MSG_DATA, msg_data.getBytes()); b.putString(Router.GROUP_ID, groupId); msg.setData(b); try { mService.send(msg); } catch (RemoteException e) { // Log.e(TAG, "failed to connect peer: " + e.getMessage()); } } } }