/**
* 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.Dialog;
import android.app.Fragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.SearchView;
import android.widget.Toast;
import com.xabber.android.R;
import com.xabber.android.data.ActivityManager;
import com.xabber.android.data.Application;
import com.xabber.android.data.NetworkException;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.account.AccountManager;
import com.xabber.android.data.account.CommonState;
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.avatar.AvatarManager;
import com.xabber.android.data.extension.muc.MUCManager;
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.roster.AbstractContact;
import com.xabber.android.data.roster.RosterContact;
import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.color.BarPainter;
import com.xabber.android.ui.dialog.AccountChooseDialogFragment;
import com.xabber.android.ui.dialog.AccountChooseDialogFragment.OnChooseListener;
import com.xabber.android.ui.dialog.BatteryOptimizationDisableDialog;
import com.xabber.android.ui.dialog.ContactSubscriptionDialog;
import com.xabber.android.ui.dialog.CrashReportDialog;
import com.xabber.android.ui.dialog.DarkThemeIntroduceDialog;
import com.xabber.android.ui.dialog.MucInviteDialog;
import com.xabber.android.ui.dialog.MucPrivateChatInvitationDialog;
import com.xabber.android.ui.dialog.StartAtBootDialogFragment;
import com.xabber.android.ui.dialog.TranslationDialog;
import com.xabber.android.ui.fragment.ContactListDrawerFragment;
import com.xabber.android.ui.fragment.ContactListFragment;
import com.xabber.android.ui.fragment.ContactListFragment.ContactListFragmentListener;
import com.xabber.android.ui.helper.BatteryHelper;
import com.xabber.android.ui.preferences.PreferenceEditor;
import com.xabber.xmpp.uri.XMPPUri;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Locale;
/**
* Main application activity.
*
* @author alexander.ivanov
*/
public class ContactListActivity extends ManagedActivity implements OnAccountChangedListener,
View.OnClickListener, OnChooseListener, ContactListFragmentListener, ContactListDrawerFragment.ContactListDrawerListener, Toolbar.OnMenuItemClickListener {
/**
* Select contact to be invited to the room was requested.
*/
private static final String ACTION_ROOM_INVITE = "com.xabber.android.ui.activity.ContactList.ACTION_ROOM_INVITE";
private static final String ACTION_MUC_PRIVATE_CHAT_INVITE = "com.xabber.android.ui.activity.ContactList.ACTION_MUC_PRIVATE_CHAT_INVITE";
private static final String ACTION_CONTACT_SUBSCRIPTION = "com.xabber.android.ui.activity.ContactList.ACTION_CONTACT_SUBSCRIPTION";
private static final String ACTION_INCOMING_MUC_INVITE = "com.xabber.android.ui.activity.ContactList.ACTION_INCOMING_MUC_INVITE";
private static final long CLOSE_ACTIVITY_AFTER_DELAY = 300;
private static final String SAVED_ACTION = "com.xabber.android.ui.activity.ContactList.SAVED_ACTION";
private static final String SAVED_SEND_TEXT = "com.xabber.android.ui.activity.ContactList.SAVED_SEND_TEXT";
private static final int DIALOG_CLOSE_APPLICATION_ID = 0x57;
private static final String CONTACT_LIST_TAG = "CONTACT_LIST";
private static final String LOG_TAG = ContactListActivity.class.getSimpleName();
/**
* Current action.
*/
private String action;
/**
* Dialog related values.
*/
private String sendText;
private SearchView searchView;
private BarPainter barPainter;
private ActionBarDrawerToggle drawerToggle;
private DrawerLayout drawerLayout;
private Menu optionsMenu;
public static Intent createPersistentIntent(Context context) {
Intent intent = new Intent(context, ContactListActivity.class);
intent.setAction("android.intent.action.MAIN");
intent.addCategory("android.intent.category.LAUNCHER");
intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
}
public static Intent createIntent(Context context) {
return new Intent(context, ContactListActivity.class);
}
public static Intent createRoomInviteIntent(Context context, AccountJid account, UserJid room) {
Intent intent = new EntityIntentBuilder(context, ContactListActivity.class)
.setAccount(account).setUser(room).build();
intent.setAction(ACTION_ROOM_INVITE);
return intent;
}
public static Intent createMucPrivateChatInviteIntent(Context context, AccountJid account, UserJid user) {
Intent intent = new EntityIntentBuilder(context, ContactListActivity.class)
.setAccount(account).setUser(user).build();
intent.setAction(ACTION_MUC_PRIVATE_CHAT_INVITE);
return intent;
}
public static Intent createContactSubscriptionIntent(Context context, AccountJid account, UserJid user) {
Intent intent = new EntityIntentBuilder(context, ContactListActivity.class)
.setAccount(account).setUser(user).build();
intent.setAction(ACTION_CONTACT_SUBSCRIPTION);
return intent;
}
public static Intent createMucInviteIntent(Context context, AccountJid account, UserJid user) {
Intent intent = new EntityIntentBuilder(context, ContactListActivity.class)
.setAccount(account).setUser(user).build();
intent.setAction(ACTION_INCOMING_MUC_INVITE);
return intent;
}
private static AccountJid getRoomInviteAccount(Intent intent) {
return EntityIntentBuilder.getAccount(intent);
}
private static UserJid getRoomInviteUser(Intent intent) {
return EntityIntentBuilder.getUser(intent);
}
@Override
public void onCreate(Bundle savedInstanceState) {
if (Intent.ACTION_VIEW.equals(getIntent().getAction())
|| Intent.ACTION_SEND.equals(getIntent().getAction())
|| Intent.ACTION_SENDTO.equals(getIntent().getAction())
|| Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) {
ActivityManager.getInstance().startNewTask(this);
}
super.onCreate(savedInstanceState);
if (isFinishing()) {
return;
}
setContentView(R.layout.activity_contact_list);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_default);
toolbar.setOnClickListener(this);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.application_title_short, R.string.application_title_short);
drawerLayout.setDrawerListener(drawerToggle);
toolbar.inflateMenu(R.menu.toolbar_contact_list);
optionsMenu = toolbar.getMenu();
setUpSearchView(optionsMenu);
toolbar.setOnMenuItemClickListener(this);
toolbar.setOverflowIcon(getResources().getDrawable(R.drawable.ic_overflow_menu_white_24dp));
barPainter = new BarPainter(this, toolbar);
barPainter.setDefaultColor();
toolbar.setTitle(R.string.application_title_full);
if (savedInstanceState != null) {
sendText = savedInstanceState.getString(SAVED_SEND_TEXT);
action = savedInstanceState.getString(SAVED_ACTION);
} else {
getFragmentManager().beginTransaction().add(R.id.container,
new ContactListFragment(), CONTACT_LIST_TAG).commit();
sendText = null;
action = getIntent().getAction();
}
getIntent().setAction(null);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
action = getIntent().getAction();
getIntent().setAction(null);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVED_ACTION, action);
outState.putString(SAVED_SEND_TEXT, sendText);
}
/**
* Open chat with specified contact.
* <p/>
* Show dialog to choose account if necessary.
*
* @param user
* @param text can be <code>null</code>.
*/
private void openChat(UserJid user, String text) {
UserJid bareAddress = user.getBareUserJid();
ArrayList<BaseEntity> entities = new ArrayList<>();
for (AbstractChat check : MessageManager.getInstance().getChats()) {
if (check.isActive() && check.getUser().equals(bareAddress)) {
entities.add(check);
}
}
if (entities.size() == 1) {
openChat(entities.get(0), text);
return;
}
entities.clear();
Collection<AccountJid> enabledAccounts = AccountManager.getInstance().getEnabledAccounts();
RosterManager rosterManager = RosterManager.getInstance();
for (AccountJid accountJid : enabledAccounts) {
RosterContact rosterContact = rosterManager.getRosterContact(accountJid, user);
if (rosterContact != null && rosterContact.isEnabled()) {
entities.add(rosterContact);
}
}
if (entities.size() == 1) {
openChat(entities.get(0), text);
return;
}
if (enabledAccounts.isEmpty()) {
return;
}
if (enabledAccounts.size() == 1) {
openChat(rosterManager.getBestContact(enabledAccounts.iterator().next(), bareAddress), text);
return;
}
AccountChooseDialogFragment.newInstance(bareAddress, text)
.show(getFragmentManager(), "OPEN_WITH_ACCOUNT");
}
/**
* Open chat with specified contact and enter text to be sent.
*
* @param text can be <code>null</code>.
*/
private void openChat(AccountJid account, UserJid user, String text) {
if (text == null) {
startActivity(ChatActivity.createSendIntent(this, account, user, null));
} else {
startActivity(ChatActivity.createSendIntent(this, account, user, text));
}
finish();
}
private void openChat(BaseEntity entity, String text) {
openChat(entity.getAccount(), entity.getUser(), text);
}
@Override
protected void onResume() {
super.onResume();
if (!AccountManager.getInstance().hasAccounts()) {
startActivity(IntroActivity.createIntent(this));
finish();
return;
}
barPainter.setDefaultColor();
rebuildAccountToggle();
Application.getInstance().addUIListener(OnAccountChangedListener.class, this);
if (action != null) {
switch (action) {
case ContactListActivity.ACTION_ROOM_INVITE:
case Intent.ACTION_SEND:
case Intent.ACTION_CREATE_SHORTCUT:
if (Intent.ACTION_SEND.equals(action)) {
sendText = getIntent().getStringExtra(Intent.EXTRA_TEXT);
}
Toast.makeText(this, getString(R.string.select_contact), Toast.LENGTH_LONG).show();
break;
case Intent.ACTION_VIEW: {
action = null;
Uri data = getIntent().getData();
if (data != null && "xmpp".equals(data.getScheme())) {
XMPPUri xmppUri;
try {
xmppUri = XMPPUri.parse(data);
} catch (IllegalArgumentException e) {
xmppUri = null;
}
if (xmppUri != null && "message".equals(xmppUri.getQueryType())) {
ArrayList<String> texts = xmppUri.getValues("body");
String text = null;
if (texts != null && !texts.isEmpty()) {
text = texts.get(0);
}
UserJid user = null;
try {
user = UserJid.from(xmppUri.getPath());
} catch (UserJid.UserJidCreateException e) {
LogManager.exception(this, e);
}
if (user != null) {
openChat(user, text);
}
}
}
break;
}
case Intent.ACTION_SENDTO: {
action = null;
Uri data = getIntent().getData();
if (data != null) {
String path = data.getPath();
if (path != null && path.startsWith("/")) {
try {
UserJid user = UserJid.from(path.substring(1));
openChat(user, null);
} catch (UserJid.UserJidCreateException e) {
LogManager.exception(this, e);
}
}
}
break;
}
case ContactListActivity.ACTION_MUC_PRIVATE_CHAT_INVITE:
action = null;
showMucPrivateChatDialog();
break;
case ContactListActivity.ACTION_CONTACT_SUBSCRIPTION:
action = null;
showContactSubscriptionDialog();
break;
case ContactListActivity.ACTION_INCOMING_MUC_INVITE:
action = null;
showMucInviteDialog();
break;
}
}
if (Application.getInstance().doNotify()) {
if (BatteryHelper.isOptimizingBattery()
&& !SettingsManager.isBatteryOptimizationDisableSuggested()) {
BatteryOptimizationDisableDialog.newInstance().show(getFragmentManager(),
BatteryOptimizationDisableDialog.class.getSimpleName());
}
if (!SettingsManager.isTranslationSuggested()) {
Locale currentLocale = getResources().getConfiguration().locale;
if (!currentLocale.getLanguage().equals("en") && !getResources().getBoolean(R.bool.is_translated)) {
new TranslationDialog().show(getFragmentManager(), "TRANSLATION_DIALOG");
}
}
if (SettingsManager.isCrashReportsSupported()
&& !SettingsManager.isCrashReportsDialogShown()) {
CrashReportDialog.newInstance().show(getFragmentManager(), CrashReportDialog.class.getSimpleName());
}
if (SettingsManager.interfaceTheme() != SettingsManager.InterfaceTheme.dark) {
if (!SettingsManager.isDarkThemeSuggested() && SettingsManager.bootCount() > 1) {
new DarkThemeIntroduceDialog().show(getFragmentManager(), DarkThemeIntroduceDialog.class.getSimpleName());
}
} else {
SettingsManager.setDarkThemeSuggested();
}
if (SettingsManager.bootCount() > 2 && !SettingsManager.connectionStartAtBoot()
&& !SettingsManager.startAtBootSuggested()) {
StartAtBootDialogFragment.newInstance().show(getFragmentManager(), "START_AT_BOOT");
}
}
}
private void showMucInviteDialog() {
Intent intent = getIntent();
AccountJid account = getRoomInviteAccount(intent);
UserJid user = getRoomInviteUser(intent);
if (account != null && user != null) {
MucInviteDialog.newInstance(account, user).show(getFragmentManager(), MucInviteDialog.class.getName());
}
}
private void showContactSubscriptionDialog() {
Intent intent = getIntent();
AccountJid account = getRoomInviteAccount(intent);
UserJid user = getRoomInviteUser(intent);
if (account != null && user != null) {
ContactSubscriptionDialog.newInstance(account, user).show(getFragmentManager(), ContactSubscriptionDialog.class.getName());
}
}
private void showMucPrivateChatDialog() {
Intent intent = getIntent();
AccountJid account = getRoomInviteAccount(intent);
UserJid user = getRoomInviteUser(intent);
if (account != null && user != null) {
MucPrivateChatInvitationDialog.newInstance(account, user).show(getFragmentManager(), MucPrivateChatInvitationDialog.class.getName());
}
}
@Override
protected void onPause() {
super.onPause();
hideKeyboard();
Application.getInstance().removeUIListener(OnAccountChangedListener.class, this);
}
private void hideKeyboard() {
if (getCurrentFocus() != null) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.toolbar_contact_list, menu);
menu.findItem(R.id.action_search).setVisible(false);
return true;
}
private void setUpSearchView(final Menu menu) {
searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setQueryHint(getString(R.string.contact_search_hint));
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
menu.findItem(R.id.action_search).collapseActionView();
return true;
}
});
MenuItemCompat.setOnActionExpandListener(menu.findItem(R.id.action_search), new MenuItemCompat.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
searchView.requestFocus();
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).
toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
searchView.setQuery("", true);
searchView.clearFocus();
return true;
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
Fragment fragmentById = getFragmentManager().findFragmentById(R.id.container);
((ContactListFragment) fragmentById).getFilterableAdapter().getFilter().filter(newText);
return true;
}
});
}
@Override
public boolean onMenuItemClick(MenuItem item) {
return onOptionsItemSelected(item);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch (item.getItemId()) {
case R.id.action_search:
searchView.setIconified(false);
return true;
case R.id.action_change_status:
startActivity(StatusEditActivity.createIntent(this));
return true;
case R.id.action_add_contact:
startActivity(ContactAddActivity.createIntent(this));
return true;
case R.id.action_close_chats:
closeAllChats();
return true;
case R.id.action_join_conference:
startActivity(ConferenceSelectActivity.createIntent(this));
return true;
case R.id.action_chat_list:
startActivity(ChatActivity.createRecentChatsIntent(this));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(Gravity.START | Gravity.LEFT)) {
drawerLayout.closeDrawers();
return;
}
super.onBackPressed();
}
private void exit() {
Application.getInstance().requestToClose();
showDialog(DIALOG_CLOSE_APPLICATION_ID);
getContactListFragment().unregisterListeners();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// Close activity if application was not killed yet.
finish();
}
}, CLOSE_ACTIVITY_AFTER_DELAY);
}
private void closeAllChats() {
MessageManager.closeActiveChats();
getContactListFragment().getAdapter().onChange();
}
private ContactListFragment getContactListFragment() {
return (ContactListFragment) getFragmentManager().findFragmentByTag(CONTACT_LIST_TAG);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
}
@Override
protected Dialog onCreateDialog(int id) {
super.onCreateDialog(id);
switch (id) {
case DIALOG_CLOSE_APPLICATION_ID:
ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setMessage(getString(R.string.application_state_closing));
progressDialog.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
});
progressDialog.setIndeterminate(true);
return progressDialog;
default:
return null;
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.toolbar_default:
getContactListFragment().scrollUp();
break;
}
}
@Override
public void onContactClick(AbstractContact abstractContact) {
if (action == null) {
startActivity(ChatActivity.createSpecificChatIntent(this,
abstractContact.getAccount(), abstractContact.getUser()));
return;
}
switch (action) {
case ACTION_ROOM_INVITE: {
action = null;
Intent intent = getIntent();
AccountJid account = getRoomInviteAccount(intent);
UserJid user = getRoomInviteUser(intent);
if (account != null && user != null) {
try {
MUCManager.getInstance().invite(account, user.getJid().asEntityBareJidIfPossible(), abstractContact.getUser());
} catch (NetworkException e) {
Application.getInstance().onError(e);
}
}
finish();
break;
}
case Intent.ACTION_SEND:
action = null;
startActivity(ChatActivity.createSendIntent(this,
abstractContact.getAccount(), abstractContact.getUser(), sendText));
finish();
break;
case Intent.ACTION_CREATE_SHORTCUT: {
createShortcut(abstractContact);
finish();
break;
}
default:
startActivity(ChatActivity.createSpecificChatIntent(this,
abstractContact.getAccount(), abstractContact.getUser()));
break;
}
}
@Override
public void onContactListChange(CommonState commonState) {
switch (commonState) {
case empty:
case disabled:
for (int i = 0; i < optionsMenu.size(); i++) {
optionsMenu.getItem(i).setVisible(false);
}
break;
case offline:
case waiting:
case connecting:
case roster:
case online:
for (int i = 0; i < optionsMenu.size(); i++) {
optionsMenu.getItem(i).setVisible(true);
}
break;
}
}
private void createShortcut(AbstractContact abstractContact) {
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, ChatActivity.createClearTopIntent(this,
abstractContact.getAccount(), abstractContact.getUser()));
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, abstractContact.getName());
Bitmap bitmap;
if (MUCManager.getInstance().hasRoom(abstractContact.getAccount(),
abstractContact.getUser())) {
bitmap = AvatarManager.getInstance().getRoomBitmap(abstractContact.getUser());
} else {
bitmap = AvatarManager.getInstance().getUserBitmap(abstractContact.getUser());
}
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON,
AvatarManager.getInstance().createShortcutBitmap(bitmap));
setResult(RESULT_OK, intent);
}
@Override
public void onAccountsChanged(Collection<AccountJid> accounts) {
((ContactListFragment)getFragmentManager().findFragmentById(R.id.container)).onAccountsChanged();
barPainter.setDefaultColor();
}
@Override
public void onChoose(AccountJid account, UserJid user, String text) {
openChat(account, user, text);
}
private void rebuildAccountToggle() {
((ContactListFragment)getFragmentManager().findFragmentById(R.id.container)).rebuild();
}
@Override
public void onContactListDrawerListener(int viewId) {
drawerLayout.closeDrawers();
switch (viewId) {
case R.id.drawer_action_settings:
startActivity(PreferenceEditor.createIntent(this));
break;
case R.id.drawer_action_about:
startActivity(AboutActivity.createIntent(this));
break;
case R.id.drawer_action_exit:
exit();
break;
case R.id.drawer_header_action_xmpp_accounts:
startActivity(AccountListActivity.createIntent(this));
break;
}
}
@Override
public void onAccountSelected(AccountJid account) {
drawerLayout.closeDrawers();
startActivity(AccountActivity.createIntent(this, account));
}
}