Back to project page socket.io-android-chat.
The source code is released under:
MIT License
If you think the Android project socket.io-android-chat listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.github.nkzawa.socketio.androidchat; /* ww w . j a v a 2 s . c o m*/ import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.*; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; import com.github.nkzawa.emitter.Emitter; import com.github.nkzawa.socketio.client.IO; import com.github.nkzawa.socketio.client.Socket; import org.json.JSONException; import org.json.JSONObject; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; /** * A chat fragment containing messages view and input form. */ public class MainFragment extends Fragment { private static final int REQUEST_LOGIN = 0; private static final int TYPING_TIMER_LENGTH = 600; private RecyclerView mMessagesView; private EditText mInputMessageView; private List<Message> mMessages = new ArrayList<Message>(); private RecyclerView.Adapter mAdapter; private boolean mTyping = false; private Handler mTypingHandler = new Handler(); private String mUsername; private Socket mSocket; { try { mSocket = IO.socket("http://chat.socket.io"); } catch (URISyntaxException e) { throw new RuntimeException(e); } } public MainFragment() { super(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); mAdapter = new MessageAdapter(activity, mMessages); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError); mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError); mSocket.on("new message", onNewMessage); mSocket.on("user joined", onUserJoined); mSocket.on("user left", onUserLeft); mSocket.on("typing", onTyping); mSocket.on("stop typing", onStopTyping); mSocket.connect(); startSignIn(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_main, container, false); } @Override public void onDestroy() { super.onDestroy(); mSocket.disconnect(); mSocket.off(Socket.EVENT_CONNECT_ERROR, onConnectError); mSocket.off(Socket.EVENT_CONNECT_TIMEOUT, onConnectError); mSocket.off("new message", onNewMessage); mSocket.off("user joined", onUserJoined); mSocket.off("user left", onUserLeft); mSocket.off("typing", onTyping); mSocket.off("stop typing", onStopTyping); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mMessagesView = (RecyclerView) view.findViewById(R.id.messages); mMessagesView.setLayoutManager(new LinearLayoutManager(getActivity())); mMessagesView.setAdapter(mAdapter); mInputMessageView = (EditText) view.findViewById(R.id.message_input); mInputMessageView.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int id, KeyEvent event) { if (id == R.id.send || id == EditorInfo.IME_NULL) { attemptSend(); return true; } return false; } }); mInputMessageView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (null == mUsername) return; if (!mSocket.connected()) return; if (!mTyping) { mTyping = true; mSocket.emit("typing"); } mTypingHandler.removeCallbacks(onTypingTimeout); mTypingHandler.postDelayed(onTypingTimeout, TYPING_TIMER_LENGTH); } @Override public void afterTextChanged(Editable s) { } }); ImageButton sendButton = (ImageButton) view.findViewById(R.id.send_button); sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { attemptSend(); } }); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (Activity.RESULT_OK != resultCode) { getActivity().finish(); return; } mUsername = data.getStringExtra("username"); int numUsers = data.getIntExtra("numUsers", 1); addLog(getResources().getString(R.string.message_welcome)); addParticipantsLog(numUsers); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // Inflate the menu; this adds items to the action bar if it is present. inflater.inflate(R.menu.menu_main, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_leave) { leave(); return true; } return super.onOptionsItemSelected(item); } private void addLog(String message) { mMessages.add(new Message.Builder(Message.TYPE_LOG) .message(message).build()); mAdapter.notifyItemInserted(mMessages.size() - 1); scrollToBottom(); } private void addParticipantsLog(int numUsers) { addLog(getResources().getQuantityString(R.plurals.message_participants, numUsers, numUsers)); } private void addMessage(String username, String message) { mMessages.add(new Message.Builder(Message.TYPE_MESSAGE) .username(username).message(message).build()); mAdapter.notifyItemInserted(mMessages.size() - 1); scrollToBottom(); } private void addTyping(String username) { mMessages.add(new Message.Builder(Message.TYPE_ACTION) .username(username).build()); mAdapter.notifyItemInserted(mMessages.size() - 1); scrollToBottom(); } private void removeTyping(String username) { for (int i = mMessages.size() - 1; i >= 0; i--) { Message message = mMessages.get(i); if (message.getType() == Message.TYPE_ACTION && message.getUsername().equals(username)) { mMessages.remove(i); mAdapter.notifyItemRemoved(i); } } } private void attemptSend() { if (null == mUsername) return; if (!mSocket.connected()) return; mTyping = false; String message = mInputMessageView.getText().toString().trim(); if (TextUtils.isEmpty(message)) { mInputMessageView.requestFocus(); return; } mInputMessageView.setText(""); addMessage(mUsername, message); // perform the sending message attempt. mSocket.emit("new message", message); } private void startSignIn() { mUsername = null; mSocket.connect(); Intent intent = new Intent(getActivity(), LoginActivity.class); startActivityForResult(intent, REQUEST_LOGIN); } private void leave() { mUsername = null; mSocket.disconnect(); startSignIn(); } private void scrollToBottom() { mMessagesView.scrollToPosition(mAdapter.getItemCount() - 1); } private Emitter.Listener onConnectError = new Emitter.Listener() { @Override public void call(Object... args) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getActivity().getApplicationContext(), R.string.error_connect, Toast.LENGTH_LONG).show(); } }); } }; private Emitter.Listener onNewMessage = new Emitter.Listener() { @Override public void call(final Object... args) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { JSONObject data = (JSONObject) args[0]; String username; String message; try { username = data.getString("username"); message = data.getString("message"); } catch (JSONException e) { return; } removeTyping(username); addMessage(username, message); } }); } }; private Emitter.Listener onUserJoined = new Emitter.Listener() { @Override public void call(final Object... args) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { JSONObject data = (JSONObject) args[0]; String username; int numUsers; try { username = data.getString("username"); numUsers = data.getInt("numUsers"); } catch (JSONException e) { return; } addLog(getResources().getString(R.string.message_user_joined, username)); addParticipantsLog(numUsers); } }); } }; private Emitter.Listener onUserLeft = new Emitter.Listener() { @Override public void call(final Object... args) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { JSONObject data = (JSONObject) args[0]; String username; int numUsers; try { username = data.getString("username"); numUsers = data.getInt("numUsers"); } catch (JSONException e) { return; } addLog(getResources().getString(R.string.message_user_left, username)); addParticipantsLog(numUsers); removeTyping(username); } }); } }; private Emitter.Listener onTyping = new Emitter.Listener() { @Override public void call(final Object... args) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { JSONObject data = (JSONObject) args[0]; String username; try { username = data.getString("username"); } catch (JSONException e) { return; } addTyping(username); } }); } }; private Emitter.Listener onStopTyping = new Emitter.Listener() { @Override public void call(final Object... args) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { JSONObject data = (JSONObject) args[0]; String username; try { username = data.getString("username"); } catch (JSONException e) { return; } removeTyping(username); } }); } }; private Runnable onTypingTimeout = new Runnable() { @Override public void run() { if (!mTyping) return; mTyping = false; mSocket.emit("stop typing"); } }; }