public void updateTypingStatus(final ChatState chatState, final String jid, final int chatType) { if (!Preferences.isTesting()) { new Thread(new Runnable() { @Override public void run() { try { Message message = new Message(JidCreate.from(jid)); message.addExtension(new ChatStateExtension(chatState)); if (chatType == Chat.TYPE_1_T0_1) { message.setType(Message.Type.chat); } else { message.setType(Message.Type.groupchat); } sendMessageDependingOnType(message, jid, chatType); } catch (Exception e) { e.printStackTrace(); } } }).start(); } }
@Override protected void processWakefulStanza(Stanza packet) throws SmackException.NotConnectedException { org.jivesoftware.smack.packet.Message m = (org.jivesoftware.smack.packet.Message) packet; if (m.getType() == org.jivesoftware.smack.packet.Message.Type.chat) { ExtensionElement chatstate = processChatState(m); // non-active chat states are not to be processed as messages if (chatstate == null || chatstate.getElementName().equals(ChatState.active.name())) { processChatMessage(m); } } // error message else if (m.getType() == org.jivesoftware.smack.packet.Message.Type.error) { processErrorMessage(m); } }
public static void sendGroupTextMessage(final Context context, String groupJid, String groupSubject, String[] to, String text, boolean encrypt, long msgId, String packetId, long inReplyTo) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", TextComponent.MIME_TYPE); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.group.subject", groupSubject); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.body", text); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); i.putExtra("org.kontalk.message.inReplyTo", inReplyTo); context.startService(i); }
public static void addGroupMembers(final Context context, String groupJid, String groupSubject, String[] to, String[] members, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", GroupCommandComponent.MIME_TYPE); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.group.subject", groupSubject); i.putExtra("org.kontalk.message.group.command", GROUP_COMMAND_MEMBERS); i.putExtra("org.kontalk.message.group.add", members); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
public static void removeGroupMembers(final Context context, String groupJid, String groupSubject, String[] to, String[] members, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", GroupCommandComponent.MIME_TYPE); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.group.subject", groupSubject); i.putExtra("org.kontalk.message.group.command", GROUP_COMMAND_MEMBERS); i.putExtra("org.kontalk.message.group.remove", members); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
/** * Sends a binary message. */ public static void sendBinaryMessage(final Context context, String to, String mime, Uri localUri, long length, String previewPath, boolean encrypt, int compress, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", mime); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.media.uri", localUri.toString()); i.putExtra("org.kontalk.message.length", length); i.putExtra("org.kontalk.message.preview.path", previewPath); i.putExtra("org.kontalk.message.compress", compress); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
public static void sendGroupBinaryMessage(final Context context, String groupJid, String[] to, String mime, Uri localUri, long length, String previewPath, boolean encrypt, int compress, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", mime); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.media.uri", localUri.toString()); i.putExtra("org.kontalk.message.length", length); i.putExtra("org.kontalk.message.preview.path", previewPath); i.putExtra("org.kontalk.message.compress", compress); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
/** * Sends a location message */ public static void sendLocationMessage(final Context context, String to, String text, double lat, double lon, String geoText, String geoStreet, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", LocationComponent.MIME_TYPE); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.body", text); i.putExtra("org.kontalk.message.geo_lat", lat); i.putExtra("org.kontalk.message.geo_lon", lon); if (geoText != null) i.putExtra("org.kontalk.message.geo_text", geoText); if (geoStreet != null) i.putExtra("org.kontalk.message.geo_street", geoStreet); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
/** * Sends group location message */ public static void sendGroupLocationMessage(final Context context, String groupJid, String groupSubject, String[] to, String text, double lat, double lon, String geoText, String geoStreet, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", LocationComponent.MIME_TYPE); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.group.subject", groupSubject); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.body", text); i.putExtra("org.kontalk.message.geo_lat", lat); i.putExtra("org.kontalk.message.geo_lon", lon); if (geoText != null) i.putExtra("org.kontalk.message.geo_text", geoText); if (geoStreet != null) i.putExtra("org.kontalk.message.geo_street", geoStreet); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
public static void sendGroupUploadedMedia(final Context context, String groupJid, String[] to, String mime, Uri localUri, long length, String previewPath, String fetchUrl, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", mime); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.preview.uri", localUri.toString()); i.putExtra("org.kontalk.message.length", length); i.putExtra("org.kontalk.message.preview.path", previewPath); i.putExtra("org.kontalk.message.body", fetchUrl); i.putExtra("org.kontalk.message.fetch.url", fetchUrl); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
public static void sendUploadedMedia(final Context context, String to, String mime, Uri localUri, long length, String previewPath, String fetchUrl, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", mime); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.preview.uri", localUri.toString()); i.putExtra("org.kontalk.message.length", length); i.putExtra("org.kontalk.message.preview.path", previewPath); i.putExtra("org.kontalk.message.body", fetchUrl); i.putExtra("org.kontalk.message.fetch.url", fetchUrl); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
private void handleState(ChatState state) { if (mScheduledStateSet != null) // whatever we wanted to set next, thats obsolete now mScheduledStateSet.cancel(); if (state != mCurrentState) this.setNewState(state); if (state == ChatState.composing) { mScheduledStateSet = new TimerTask() { @Override public void run() { // NOTE: using 'inactive' instead of 'paused' here as // 'inactive' isn't send at all MyChatState.this.handleState(ChatState.inactive); } }; mTimer.schedule(mScheduledStateSet, TimeUnit.SECONDS.toMillis(COMPOSING_TO_PAUSED)); } }
private void setNewState(ChatState state) { // currently set states from XEP-0085: active, inactive, composing mCurrentState = state; if (state == ChatState.active || !(mChat instanceof SingleChat)) // don't send for groups (TODO (?)) // 'active' is send inside a message return; Contact contact = ((SingleChat) mChat).getMember().getContact(); if (contact.isMe() || contact.isBlocked() || contact.isDeleted()) return; if (Config.getInstance().getBoolean(Config.NET_SEND_CHAT_STATE)) mClient.sendChatState(contact.getJID(), mChat.getXMPPID(), state); }
/** * Inform model (and view) about a received chat state notification. */ public void onChatStateNotification(MessageIDs ids, Optional<Date> serverDate, ChatState chatState) { if (serverDate.isPresent()) { long diff = new Date().getTime() - serverDate.get().getTime(); if (diff > TimeUnit.SECONDS.toMillis(10)) { // too old return; } } Contact contact = mModel.contacts().get(ids.jid).orElse(null); if (contact == null) { LOGGER.info("can't find contact with jid: "+ids.jid); return; } // NOTE: assume chat states are only send for single chats SingleChat chat = mModel.chats().get(contact, ids.xmppThreadID).orElse(null); if (chat == null) // not that important return; chat.setChatState(contact, chatState); }
private void sendInactiveTypingStatus() { if (wasComposingMessage()) { mRoomManager.updateTypingStatus(ChatState.paused, mChatJID, mChat.getType()); } else { mRoomManager.updateTypingStatus(ChatState.inactive, mChatJID, mChat.getType()); } }
private void mockRoomManager() { mRoomManagerMock = mock(RoomManager.class); RoomManager.setSpecialInstanceForTesting(mRoomManagerMock); doNothing().when(mRoomManagerMock).updateTypingStatus(any(ChatState.class), any(String.class), any(int.class)); doNothing().when(mRoomManagerMock).addToMUCLight(any(User.class), any(String.class)); doNothing().when(mRoomManagerMock).removeFromMUCLight(any(User.class), any(String.class)); }
@Override public ChatStateExtension parse(XmlPullParser parser, int initialDepth) { ChatState state; try { state = ChatState.valueOf(parser.getName()); } catch (Exception ex) { state = ChatState.active; } return new ChatStateExtension(state); }
@Override public void sendTypingStatus (final String to, final boolean isTyping) { if (mExecutor != null) mExecutor.execute(new Runnable() { public void run() { sendChatState(to, isTyping ? ChatState.composing : ChatState.inactive); } }); }
private void sendChatState (String to, ChatState currentChatState) { try { if (mConnection != null && mConnection.isConnected()) { // findOrCreateSession(to, false); Chat thisChat = mChatManager.createChat(JidCreate.from(to).asEntityJidIfPossible()); ChatStateManager.getInstance(mConnection).setCurrentState(currentChatState, thisChat); } } catch (Exception e) { Log.w(ImApp.LOG_TAG,"error sending chat state: " + e.getMessage()); } }
/** * Sends a chat state message. */ public static void sendChatState(final Context context, String to, ChatState state) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.chatState", state.name()); i.putExtra("org.kontalk.message.standalone", true); context.startService(i); }
/** * Sends a text message. */ public static void sendTextMessage(final Context context, String to, String text, boolean encrypt, long msgId, String packetId, long inReplyTo) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", TextComponent.MIME_TYPE); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.body", text); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); i.putExtra("org.kontalk.message.inReplyTo", inReplyTo); context.startService(i); }
public static void createGroup(final Context context, String groupJid, String groupSubject, String[] to, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", GroupCommandComponent.MIME_TYPE); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.group.subject", groupSubject); i.putExtra("org.kontalk.message.group.command", GROUP_COMMAND_CREATE); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
public static void leaveGroup(final Context context, String groupJid, String[] to, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", GroupCommandComponent.MIME_TYPE); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.group.command", GROUP_COMMAND_PART); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
public static void setGroupSubject(final Context context, String groupJid, String groupSubject, String[] to, boolean encrypt, long msgId, String packetId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.packetId", packetId); i.putExtra("org.kontalk.message.mime", GroupCommandComponent.MIME_TYPE); i.putExtra("org.kontalk.message.group.jid", groupJid); i.putExtra("org.kontalk.message.group.subject", groupSubject); i.putExtra("org.kontalk.message.group.command", GROUP_COMMAND_SUBJECT); i.putExtra("org.kontalk.message.to", to); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
@Override public boolean sendTyping() { if (mAvailableResources.size() > 0) { MessageCenterService.sendChatState(getContext(), mUserJID, ChatState.composing); return true; } return false; }
@Override public boolean sendInactive() { if (mAvailableResources.size() > 0) { MessageCenterService.sendChatState(getActivity(), mUserJID, ChatState.inactive); return true; } return false; }
/** Sends a chat state message. */ public static void sendChatState(final Context context, String userId, ChatState state) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.toUser", userId); i.putExtra("org.kontalk.message.chatState", state.name()); i.putExtra("org.kontalk.message.standalone", true); context.startService(i); }
/** Sends a text message. */ public static void sendTextMessage(final Context context, String userId, String text, boolean encrypt, long msgId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.mime", TextComponent.MIME_TYPE); i.putExtra("org.kontalk.message.toUser", userId); i.putExtra("org.kontalk.message.body", text); i.putExtra("org.kontalk.message.encrypt", encrypt); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
/** Sends a binary message. */ public static void sendBinaryMessage(final Context context, String userId, String mime, Uri localUri, long length, String previewPath, long msgId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.mime", mime); i.putExtra("org.kontalk.message.toUser", userId); i.putExtra("org.kontalk.message.media.uri", localUri.toString()); i.putExtra("org.kontalk.message.length", length); i.putExtra("org.kontalk.message.preview.path", previewPath); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
public static void sendUploadedMedia(final Context context, String userId, String mime, Uri localUri, long length, String previewPath, String fetchUrl, long msgId) { Intent i = new Intent(context, MessageCenterService.class); i.setAction(MessageCenterService.ACTION_MESSAGE); i.putExtra("org.kontalk.message.msgId", msgId); i.putExtra("org.kontalk.message.mime", mime); i.putExtra("org.kontalk.message.toUser", userId); i.putExtra("org.kontalk.message.preview.uri", localUri.toString()); i.putExtra("org.kontalk.message.length", length); i.putExtra("org.kontalk.message.preview.path", previewPath); i.putExtra("org.kontalk.message.fetch.url", fetchUrl); i.putExtra("org.kontalk.message.chatState", ChatState.active.name()); context.startService(i); }
void onKeyTypeEvent(boolean empty) { this.updateEnabledButtons(); Chat chat = this.getCurrentChat().orElse(null); if (chat == null) return; // workaround: clearing the text area is not a key event if (!empty) mView.getControl().handleOwnChatStateEvent(chat, ChatState.composing); }
@Override public void setChatState(Contact contact, ChatState chatState) { if (!contact.equals(mMember.getContact())) { LOGGER.warning("wrong contact!?"); return; } mMember.setState(chatState); this.changed(ViewChange.MEMBER_STATE); }
@Override public void setChatState(final Contact contact, ChatState chatState) { Member member = mMemberSet.stream() .filter(m -> m.getContact().equals(contact)) .findFirst().orElse(null); if (member == null) { LOGGER.warning("can't find member in member set!?"); return; } member.setState(chatState); this.changed(ViewChange.MEMBER_STATE); }
public void sendChatState(JID jid, String threadID, ChatState state) { Message message = new Message(jid.toBareSmack(), Message.Type.chat); if (!threadID.isEmpty()) message.setThread(threadID); message.addExtension(new ChatStateExtension(state)); this.sendPacket(message); }
void handleOwnChatStateEvent(Chat chat, ChatState state) { if (!mChatStateCache.containsKey(chat)) { if (state == ChatState.gone) // weare and stay at the default state return; mChatStateCache.put(chat, new MyChatState(chat)); } mChatStateCache.get(chat).handleState(state); }
@Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); cancelMessageNotificationsForChat(); switch (id) { case android.R.id.home: mChat = getChatFromRealm(); sendInactiveTypingStatus(); if (mSessionDepth == 1) { Intent intent = new Intent(this, MainMenuActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); } else { finish(); } new Event(Event.Type.GO_BACK_FROM_CHAT).post(); break; case R.id.actionChatMembers: mChat = getChatFromRealm(); Intent chatMembersIntent = new Intent(ChatActivity.this, ChatMembersActivity.class); chatMembersIntent.putExtra(ChatMembersActivity.ROOM_JID_PARAMETER, mChatJID); chatMembersIntent.putExtra(ChatMembersActivity.IS_ADMIN_PARAMETER, mIsOwner); startActivity(chatMembersIntent); break; case R.id.actionChangeRoomName: changeMUCLightRoomName(); break; case R.id.actionChangeSubject: changeMUCLightRoomSubject(); break; case R.id.actionLeaveChat: mRoomManager.updateTypingStatus(ChatState.gone, mChatJID, mChat.getType()); leaveChat(); break; case R.id.actionDestroyChat: mRoomManager.updateTypingStatus(ChatState.gone, mChatJID, mChat.getType()); destroyChat(); break; case R.id.actionAddToContacts: addChatGuyToContacts(); break; case R.id.actionRemoveFromContacts: removeChatGuyFromContacts(); break; } return true; }
public ChatState getChatState() { return state; }
private void handleChatState (String from, String chatStateXml) throws RemoteException { Presence p = null; Contact contact = mContactListManager.getContact(from); if (contact == null) return; boolean isTyping = false; //handle is-typing, probably some indication on screen if (chatStateXml.contains("'error'")||chatStateXml.contains("'cancel'")) { //do nothing } else if (chatStateXml.contains(ChatState.active.toString())) { p = new Presence(Presence.AVAILABLE, "", null, null, Presence.CLIENT_TYPE_MOBILE); p.setLastSeen(new Date()); } else if (chatStateXml.contains(ChatState.inactive.toString())) { p = new Presence(Presence.AWAY, "", null, null, Presence.CLIENT_TYPE_MOBILE); p.setLastSeen(new Date()); } else if (chatStateXml.contains(ChatState.composing.toString())) { p = new Presence(Presence.AVAILABLE, "", null, null, Presence.CLIENT_TYPE_MOBILE); isTyping = true; p.setLastSeen(new Date()); } else if (chatStateXml.contains(ChatState.inactive.toString())||chatStateXml.contains(ChatState.paused.toString())) { } else if (chatStateXml.contains(ChatState.gone.toString())) { } IChatSession csa = mSessionManager.getAdapter().getChatSession(from); if (csa != null) csa.setContactTyping(contact, isTyping); if (p != null) { String[] presenceParts = from.split("/"); if (presenceParts.length > 1) p.setResource(presenceParts[1]); contact.setPresence(p); Collection<Contact> contactsUpdate = new ArrayList<Contact>(); contactsUpdate.add(contact); mContactListManager.notifyContactsPresenceUpdated(contactsUpdate.toArray(new Contact[contactsUpdate.size()])); } }
public ChatState getState() { return mState; }
void setState(ChatState state) { mState = state; if (mState == ChatState.active || mState == ChatState.composing) mLastActive = new Date(); }