/** * Copyright (c) 2013, Redsolution LTD. All rights reserved. * * This file is part of Xabber project; you can redistribute it and/or * modify it under the terms of the GNU General Public License, Version 3. * * Xabber 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 General Public License for more details. * * You should have received a copy of the GNU General Public License, * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.xabber.android.ui.activity; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.view.ViewPager; import android.view.View; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import com.xabber.android.R; import com.xabber.android.data.ActivityManager; import com.xabber.android.data.Application; import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.listeners.OnAccountChangedListener; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.BaseEntity; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.extension.attention.AttentionManager; import com.xabber.android.data.extension.blocking.BlockingManager; import com.xabber.android.data.extension.blocking.OnBlockedListChangedListener; import com.xabber.android.data.intent.EntityIntentBuilder; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.NewMessageEvent; import com.xabber.android.data.message.chat.ChatManager; import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.roster.OnContactChangedListener; import com.xabber.android.data.roster.RosterContact; import com.xabber.android.ui.adapter.ChatViewerAdapter; import com.xabber.android.ui.color.ColorManager; import com.xabber.android.ui.color.StatusBarPainter; import com.xabber.android.ui.fragment.ChatFragment; import com.xabber.android.ui.fragment.RecentChatFragment; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import org.jxmpp.stringprep.XmppStringprepException; import java.util.Collection; /** * Chat activity. * <p/> * * @author alexander.ivanov */ public class ChatActivity extends ManagedActivity implements OnContactChangedListener, OnAccountChangedListener, ViewPager.OnPageChangeListener, ChatFragment.ChatViewerFragmentListener, OnBlockedListChangedListener, RecentChatFragment.Listener, ChatViewerAdapter.FinishUpdateListener { private static final String LOG_TAG = ChatActivity.class.getSimpleName(); private static final String ACTION_ATTENTION = "com.xabber.android.data.ATTENTION"; private static final String ACTION_RECENT_CHATS = "com.xabber.android.data.RECENT_CHATS"; private static final String ACTION_SPECIFIC_CHAT = "com.xabber.android.data.ACTION_SPECIFIC_CHAT"; private static final String SAVE_SELECTED_PAGE = "com.xabber.android.ui.activity.ChatActivity.SAVE_SELECTED_PAGE"; private static final String SAVE_SELECTED_ACCOUNT = "com.xabber.android.ui.activity.ChatActivity.SAVE_SELECTED_ACCOUNT"; private static final String SAVE_SELECTED_USER = "com.xabber.android.ui.activity.ChatActivity.SAVE_SELECTED_USER"; private static final String SAVE_EXIT_ON_SEND = "com.xabber.android.ui.activity.ChatActivity.SAVE_EXIT_ON_SEND"; ChatViewerAdapter chatViewerAdapter; ViewPager viewPager; private String extraText = null; private StatusBarPainter statusBarPainter; private boolean isVisible; private AccountJid account; private UserJid user; private int selectedPagePosition; private boolean exitOnSend; @Nullable private ChatFragment chatFragment; @Nullable private RecentChatFragment recentChatFragment; public static void hideKeyboard(Activity activity) { // Check if no view has focus: View view = activity.getCurrentFocus(); if (view != null) { InputMethodManager inputManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } } @Nullable private static AccountJid getAccount(Intent intent) { AccountJid value = EntityIntentBuilder.getAccount(intent); if (value != null) return value; // Backward compatibility. String stringExtra = intent.getStringExtra("com.xabber.android.data.account"); if (stringExtra == null) { return null; } try { return AccountJid.from(stringExtra); } catch (XmppStringprepException e) { LogManager.exception(LOG_TAG, e); return null; } } @Nullable private static UserJid getUser(Intent intent) { UserJid value = EntityIntentBuilder.getUser(intent); if (value != null) return value; // Backward compatibility. String stringExtra = intent.getStringExtra("com.xabber.android.data.user"); if (stringExtra == null) { return null; } try { return UserJid.from(stringExtra); } catch (UserJid.UserJidCreateException e) { LogManager.exception(LOG_TAG, e); return null; } } private static boolean hasAttention(Intent intent) { return ACTION_ATTENTION.equals(intent.getAction()); } public static Intent createSpecificChatIntent(Context context, AccountJid account, UserJid user) { Intent intent = new EntityIntentBuilder(context, ChatActivity.class).setAccount(account).setUser(user).build(); intent.setAction(ACTION_SPECIFIC_CHAT); return intent; } public static Intent createRecentChatsIntent(Context context) { Intent intent = new EntityIntentBuilder(context, ChatActivity.class).build(); intent.setAction(ACTION_RECENT_CHATS); return intent; } public static Intent createClearTopIntent(Context context, AccountJid account, UserJid user) { Intent intent = createSpecificChatIntent(context, account, user); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); return intent; } /** * Create intent to send message. * <p/> * Contact list will not be shown on when chat will be closed. * @param text if <code>null</code> then user will be able to send a number * of messages. Else only one message can be send. */ public static Intent createSendIntent(Context context, AccountJid account, UserJid user, String text) { Intent intent = ChatActivity.createSpecificChatIntent(context, account, user); intent.setAction(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, text); return intent; } public static Intent createAttentionRequestIntent(Context context, AccountJid account, UserJid user) { Intent intent = ChatActivity.createClearTopIntent(context, account, user); intent.setAction(ACTION_ATTENTION); return intent; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LogManager.i(LOG_TAG, "onCreate " + savedInstanceState); setContentView(R.layout.activity_chat); statusBarPainter = new StatusBarPainter(this); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); getInitialChatFromIntent(); getSelectedPageDataFromIntent(); if (savedInstanceState != null) { restoreInstanceState(savedInstanceState); } initChats(); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); LogManager.i(LOG_TAG, "onNewIntent"); setIntent(intent); getSelectedPageDataFromIntent(); getInitialChatFromIntent(); selectChat(account, user); } @Override protected void onResume() { super.onResume(); LogManager.i(LOG_TAG, "onResume"); isVisible = true; Application.getInstance().addUIListener(OnContactChangedListener.class, this); Application.getInstance().addUIListener(OnAccountChangedListener.class, this); Application.getInstance().addUIListener(OnBlockedListChangedListener.class, this); selectPage(); Intent intent = getIntent(); if (hasAttention(intent)) { AttentionManager.getInstance().removeAccountNotifications(account, user); } if (Intent.ACTION_SEND.equals(intent.getAction())) { extraText = intent.getStringExtra(Intent.EXTRA_TEXT); if (extraText != null) { intent.removeExtra(Intent.EXTRA_TEXT); exitOnSend = true; } } } private void initChats() { if (account != null && user != null) { chatViewerAdapter = new ChatViewerAdapter(getFragmentManager(), this, account, user); } else { chatViewerAdapter = new ChatViewerAdapter(getFragmentManager(), this); } viewPager = (ViewPager) findViewById(R.id.pager); viewPager.setAdapter(chatViewerAdapter); viewPager.addOnPageChangeListener(this); if (SettingsManager.chatsShowBackground()) { if (SettingsManager.interfaceTheme() == SettingsManager.InterfaceTheme.dark) { viewPager.setBackgroundDrawable(getResources().getDrawable(R.drawable.chat_background_repeat_dark)); } else { viewPager.setBackgroundDrawable(getResources().getDrawable(R.drawable.chat_background_repeat)); } } else { viewPager.setBackgroundColor(ColorManager.getInstance().getChatBackgroundColor()); } } private void getInitialChatFromIntent() { Intent intent = getIntent(); AccountJid newAccount = getAccount(intent); UserJid newUser = getUser(intent); if (newAccount != null) { this.account = newAccount; } if (newUser != null) { this.user = newUser; } LogManager.i(LOG_TAG, "getInitialChatFromIntent " + this.user); } private void getSelectedPageDataFromIntent() { Intent intent = getIntent(); if (intent.getAction() == null) { return; } switch (intent.getAction()) { case ACTION_RECENT_CHATS: selectedPagePosition = ChatViewerAdapter.PAGE_POSITION_RECENT_CHATS; break; case ACTION_SPECIFIC_CHAT: case ACTION_ATTENTION: case Intent.ACTION_SEND: selectedPagePosition = ChatViewerAdapter.PAGE_POSITION_CHAT; break; } } private void restoreInstanceState(Bundle savedInstanceState) { account = savedInstanceState.getParcelable(SAVE_SELECTED_ACCOUNT); user = savedInstanceState.getParcelable(SAVE_SELECTED_USER); selectedPagePosition = savedInstanceState.getInt(SAVE_SELECTED_PAGE); exitOnSend = savedInstanceState.getBoolean(SAVE_EXIT_ON_SEND); } private void selectPage() { selectPage(selectedPagePosition, false); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(SAVE_SELECTED_PAGE, selectedPagePosition); outState.putParcelable(SAVE_SELECTED_ACCOUNT, account); outState.putParcelable(SAVE_SELECTED_USER, user); outState.putBoolean(SAVE_EXIT_ON_SEND, exitOnSend); } @Override protected void onPause() { super.onPause(); Application.getInstance().removeUIListener(OnContactChangedListener.class, this); Application.getInstance().removeUIListener(OnAccountChangedListener.class, this); Application.getInstance().removeUIListener(OnBlockedListChangedListener.class, this); MessageManager.getInstance().removeVisibleChat(); isVisible = false; } @Override protected void onStop() { super.onStop(); ChatManager.getInstance().clearScrollStates(); } private void selectChatPage(BaseEntity chat, boolean smoothScroll) { account = chat.getAccount(); user = chat.getUser(); if (chatFragment == null) { chatViewerAdapter.selectChat(chat.getAccount(), chat.getUser()); } else { chatFragment.saveInputState(); chatFragment.setChat(chat.getAccount(), chat.getUser()); } selectPage(ChatViewerAdapter.PAGE_POSITION_CHAT, smoothScroll); } private void selectPage(int position, boolean smoothScroll) { onPageSelected(position); viewPager.setCurrentItem(position, smoothScroll); } @Subscribe(threadMode = ThreadMode.MAIN) public void onNewMessageEvent(NewMessageEvent event) { updateRecentChats(); } @Override public void onContactsChanged(Collection<RosterContact> entities) { updateChat(); updateRecentChats(); } @Override public void onAccountsChanged(Collection<AccountJid> accounts) { updateChat(); updateRecentChats(); updateStatusBar(); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { hideKeyboard(this); } @Override public void onPageSelected(int position) { selectedPagePosition = position; if (selectedPagePosition == ChatViewerAdapter.PAGE_POSITION_RECENT_CHATS) { MessageManager.getInstance().removeVisibleChat(); } else { if (isVisible) { MessageManager.getInstance().setVisibleChat(MessageManager.getInstance().getOrCreateChat(account, user)); NotificationManager.getInstance() .removeMessageNotification(account, user); } } updateStatusBar(); } private void updateStatusBar() { if (selectedPagePosition == ChatViewerAdapter.PAGE_POSITION_RECENT_CHATS || account == null) { statusBarPainter.updateWithDefaultColor(); } else { statusBarPainter.updateWithAccountName(account); } } private void updateChat() { if (chatFragment != null) { chatFragment.updateContact(); } } private void updateRecentChats() { if (recentChatFragment != null) { recentChatFragment.updateChats(); } } @Override public void onPageScrollStateChanged(int state) { } @Override public void onChatViewAdapterFinishUpdate() { insertExtraText(); } private void insertExtraText() { if (extraText == null) { return; } if (chatFragment != null) { chatFragment.setInputText(extraText); extraText = null; } } @Override public void onChatSelected(BaseEntity chat) { selectChat(chat.getAccount(), chat.getUser()); } private void selectChat(AccountJid accountJid, UserJid userJid) { AbstractChat chat = MessageManager.getInstance().getOrCreateChat(accountJid, userJid); selectChatPage(chat, true); } @Override public void registerRecentChatFragment(RecentChatFragment recentChatFragment) { this.recentChatFragment = recentChatFragment; } @Override public void unregisterRecentChatFragment() { this.recentChatFragment = null; } @Override public void onCloseChat() { close(); } @Override public void onMessageSent() { if (exitOnSend) { close(); } } @Override public void registerChatFragment(ChatFragment chatFragment) { this.chatFragment = chatFragment; } @Override public void unregisterChatFragment() { this.chatFragment = null; } private void close() { finish(); if (!Intent.ACTION_SEND.equals(getIntent().getAction())) { ActivityManager.getInstance().clearStack(false); if (!ActivityManager.getInstance().hasContactList(this)) { startActivity(ContactListActivity.createIntent(this)); } } } @Override public void onBlockedListChanged(AccountJid account) { // if chat of blocked contact is currently opened, it should be closed final Collection<UserJid> blockedContacts = BlockingManager.getInstance().getBlockedContacts(account); if (blockedContacts.contains(user)) { close(); } } }