conversations-classic/src/eu/siacs/conversations/ui/ContactsActivity.java

609 lines
19 KiB
Java
Raw Normal View History

2014-02-28 17:46:01 +00:00
package eu.siacs.conversations.ui;
2014-01-24 01:04:05 +00:00
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
2014-01-24 01:04:05 +00:00
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.utils.CryptoHelper;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.Validator;
2014-01-24 01:04:05 +00:00
import android.os.Bundle;
import android.preference.PreferenceManager;
2014-01-24 01:04:05 +00:00
import android.text.Editable;
import android.text.TextWatcher;
2014-03-15 03:59:18 +00:00
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
2014-01-24 01:04:05 +00:00
import android.view.LayoutInflater;
import android.view.Menu;
2014-03-15 03:59:18 +00:00
import android.view.MenuInflater;
import android.view.MenuItem;
2014-01-24 01:04:05 +00:00
import android.view.View;
import android.view.ViewGroup;
2014-03-15 03:59:18 +00:00
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
2014-02-07 01:57:36 +00:00
import android.widget.ProgressBar;
2014-01-24 01:04:05 +00:00
import android.widget.TextView;
import android.widget.ImageView;
import android.widget.Toast;
2014-02-03 15:04:27 +00:00
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
2014-01-24 01:04:05 +00:00
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnClickListener;
2014-01-24 01:04:05 +00:00
import android.content.Intent;
public class ContactsActivity extends XmppActivity {
2014-01-24 01:04:05 +00:00
protected List<Contact> rosterContacts = new ArrayList<Contact>();
protected List<Contact> aggregatedContacts = new ArrayList<Contact>();
protected ListView contactsView;
protected ArrayAdapter<Contact> contactsAdapter;
protected EditText search;
protected String searchString = "";
private TextView contactsHeader;
private List<Account> accounts;
2014-03-15 03:59:18 +00:00
private List<Contact> selectedContacts = new ArrayList<Contact>();
private ContactsActivity activity = this;
2014-03-15 05:20:59 +00:00
private boolean useSubject = true;
2014-03-15 03:59:18 +00:00
private boolean isActionMode = false;
2014-03-15 05:20:59 +00:00
private boolean inviteIntent = false;
2014-03-15 03:59:18 +00:00
private ActionMode actionMode = null;
private AbsListView.MultiChoiceModeListener actionModeCallback = new AbsListView.MultiChoiceModeListener() {
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
menu.clear();
MenuInflater inflater = mode.getMenuInflater();
2014-03-15 05:20:59 +00:00
inflater.inflate(R.menu.newconversation_context, menu);
SparseBooleanArray checkedItems = contactsView
.getCheckedItemPositions();
selectedContacts.clear();
for (int i = 0; i < aggregatedContacts.size(); ++i) {
if (checkedItems.get(i, false)) {
selectedContacts.add(aggregatedContacts.get(i));
}
}
if (selectedContacts.size() == 0) {
menu.findItem(R.id.action_start_conversation).setVisible(false);
menu.findItem(R.id.action_contact_details).setVisible(false);
menu.findItem(R.id.action_invite).setVisible(false);
menu.findItem(R.id.action_invite_to_existing).setVisible(false);
} else if ((selectedContacts.size() == 1) && (!inviteIntent)) {
2014-03-15 05:20:59 +00:00
menu.findItem(R.id.action_start_conversation).setVisible(true);
menu.findItem(R.id.action_contact_details).setVisible(true);
menu.findItem(R.id.action_invite).setVisible(false);
menu.findItem(R.id.action_invite_to_existing).setVisible(true);
} else if (!inviteIntent) {
2014-03-15 05:20:59 +00:00
menu.findItem(R.id.action_start_conversation).setVisible(true);
menu.findItem(R.id.action_contact_details).setVisible(false);
menu.findItem(R.id.action_invite).setVisible(false);
menu.findItem(R.id.action_invite_to_existing).setVisible(true);
2014-03-15 05:20:59 +00:00
} else {
menu.findItem(R.id.action_invite).setVisible(true);
menu.findItem(R.id.action_start_conversation).setVisible(false);
menu.findItem(R.id.action_contact_details).setVisible(false);
menu.findItem(R.id.action_invite_to_existing).setVisible(false);
2014-03-15 05:20:59 +00:00
}
2014-03-15 03:59:18 +00:00
return true;
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
@Override
public void onDestroyActionMode(ActionMode mode) {
// TODO Auto-generated method stub
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return true;
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_start_conversation:
if (selectedContacts.size() == 1) {
startConversation(selectedContacts.get(0));
} else {
startConference();
}
break;
case R.id.action_contact_details:
2014-03-15 05:20:59 +00:00
Intent intent = new Intent(getApplicationContext(),
ContactDetailsActivity.class);
2014-03-15 03:59:18 +00:00
intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
intent.putExtra("uuid", selectedContacts.get(0).getUuid());
startActivity(intent);
break;
2014-03-15 05:20:59 +00:00
case R.id.action_invite:
invite();
break;
case R.id.action_invite_to_existing:
final List<Conversation> mucs = new ArrayList<Conversation>();
for(Conversation conv : xmppConnectionService.getConversations()) {
if (conv.getMode() == Conversation.MODE_MULTI) {
mucs.add(conv);
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(getString(R.string.invite_contacts_to_existing));
if (mucs.size() >= 1) {
String[] options = new String[mucs.size()];
for(int i = 0; i < options.length; ++i) {
options[i] = mucs.get(i).getName(useSubject);
}
builder.setItems(options, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Conversation conversation = mucs.get(which);
if (isOnline(conversation.getAccount())) {
xmppConnectionService.inviteToConference(conversation, selectedContacts);
Toast.makeText(activity, getString(R.string.invitation_sent), Toast.LENGTH_SHORT).show();
actionMode.finish();
}
}
});
} else {
builder.setMessage(getString(R.string.no_open_mucs));
}
builder.setNegativeButton(getString(R.string.cancel),null);
builder.create().show();
break;
2014-03-15 03:59:18 +00:00
default:
break;
}
return false;
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
}
};
2014-03-15 05:20:59 +00:00
private boolean isOnline(Account account) {
if (account.getStatus() == Account.STATUS_ONLINE) {
return true;
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.account_offline));
builder.setMessage(getString(R.string.cant_invite_while_offline));
builder.setNegativeButton("OK", null);
builder.setIconAttribute(android.R.attr.alertDialogIcon);
builder.create().show();
return false;
}
}
2014-03-15 05:20:59 +00:00
private void invite() {
List<Conversation> conversations = xmppConnectionService
.getConversations();
Conversation conversation = null;
for (Conversation tmpConversation : conversations) {
if (tmpConversation.getUuid().equals(
getIntent().getStringExtra("uuid"))) {
conversation = tmpConversation;
break;
}
}
if (conversation != null) {
xmppConnectionService.inviteToConference(conversation,
selectedContacts);
2014-03-15 05:20:59 +00:00
}
finish();
}
2014-03-15 03:59:18 +00:00
private void startConference() {
2014-03-15 05:20:59 +00:00
if (accounts.size() > 1) {
2014-03-15 03:59:18 +00:00
getAccountChooser(new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startConference(accounts.get(which));
2014-03-15 03:59:18 +00:00
}
2014-03-15 05:20:59 +00:00
}).show();
2014-03-15 03:59:18 +00:00
} else {
startConference(accounts.get(0));
2014-03-15 03:59:18 +00:00
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
}
2014-03-15 05:20:59 +00:00
private void startConference(final Account account) {
if (isOnline(account)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.new_conference));
builder.setMessage(getString(R.string.new_conference_explained));
builder.setNegativeButton(getString(R.string.cancel), null);
builder.setPositiveButton(getString(R.string.create_invite),
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String mucName = CryptoHelper.randomMucName();
String serverName = account.getXmppConnection()
.getMucServer();
String jid = mucName + "@" + serverName;
Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, jid, true);
StringBuilder subject = new StringBuilder();
subject.append(account.getUsername() + ", ");
for (int i = 0; i < selectedContacts.size(); ++i) {
if (i + 1 != selectedContacts.size()) {
subject.append(selectedContacts.get(i)
.getDisplayName() + ", ");
} else {
subject.append(selectedContacts.get(i)
.getDisplayName());
}
}
xmppConnectionService.sendConversationSubject(
conversation, subject.toString());
xmppConnectionService.inviteToConference(conversation,
selectedContacts);
switchToConversation(conversation, null);
}
});
builder.create().show();
2014-03-15 03:59:18 +00:00
}
}
protected void updateAggregatedContacts() {
aggregatedContacts.clear();
for (Contact contact : rosterContacts) {
if (contact.match(searchString))
aggregatedContacts.add(contact);
}
Collections.sort(aggregatedContacts, new Comparator<Contact>() {
2014-02-03 15:04:27 +00:00
@SuppressLint("DefaultLocale")
@Override
public int compare(Contact lhs, Contact rhs) {
return lhs.getDisplayName().toLowerCase()
.compareTo(rhs.getDisplayName().toLowerCase());
}
});
if (aggregatedContacts.size() == 0) {
if (Validator.isValidJid(searchString)) {
String name = searchString.split("@")[0];
Contact newContact = new Contact(null, name, searchString, null);
newContact.flagAsNotInRoster();
aggregatedContacts.add(newContact);
contactsHeader.setText("Create new contact");
} else {
contactsHeader.setText("Contacts");
}
} else {
contactsHeader.setText("Contacts");
}
contactsAdapter.notifyDataSetChanged();
contactsView.setScrollX(0);
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
private OnItemLongClickListener onLongClickListener = new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View view,
int position, long arg3) {
if (!isActionMode) {
contactsView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
2014-03-15 05:20:59 +00:00
contactsView.setItemChecked(position, true);
2014-03-15 03:59:18 +00:00
actionMode = contactsView.startActionMode(actionModeCallback);
}
return true;
}
};
2014-01-24 01:04:05 +00:00
2014-03-15 05:20:59 +00:00
@Override
protected void onStart() {
super.onStart();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
2014-03-15 05:20:59 +00:00
inviteIntent = "invite".equals(getIntent().getAction());
if (inviteIntent) {
contactsHeader.setVisibility(View.GONE);
actionMode = contactsView.startActionMode(actionModeCallback);
search.setVisibility(View.GONE);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_conversation);
contactsHeader = (TextView) findViewById(R.id.contacts_header);
search = (EditText) findViewById(R.id.new_conversation_search);
search.addTextChangedListener(new TextWatcher() {
2014-01-24 01:04:05 +00:00
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
searchString = search.getText().toString();
updateAggregatedContacts();
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
});
contactsView = (ListView) findViewById(R.id.contactList);
contactsAdapter = new ArrayAdapter<Contact>(getApplicationContext(),
R.layout.contact, aggregatedContacts) {
@Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Contact contact = getItem(position);
if (view == null) {
view = (View) inflater.inflate(R.layout.contact, null);
2014-01-24 01:04:05 +00:00
}
((TextView) view.findViewById(R.id.contact_display_name))
.setText(getItem(position).getDisplayName());
TextView contactJid = (TextView) view
.findViewById(R.id.contact_jid);
contactJid.setText(contact.getJid());
ImageView imageView = (ImageView) view
.findViewById(R.id.contact_photo);
imageView.setImageBitmap(UIHelper.getContactPicture(contact, 48, this.getContext(), false));
return view;
}
};
contactsView.setAdapter(contactsAdapter);
2014-03-15 03:59:18 +00:00
contactsView.setMultiChoiceModeListener(actionModeCallback);
contactsView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, final View view,
int pos, long arg3) {
2014-03-15 03:59:18 +00:00
if (!isActionMode) {
Contact clickedContact = aggregatedContacts.get(pos);
startConversation(clickedContact);
2014-03-15 05:20:59 +00:00
} else {
2014-03-15 03:59:18 +00:00
actionMode.invalidate();
}
2014-01-24 01:04:05 +00:00
}
});
2014-03-15 03:59:18 +00:00
contactsView.setOnItemLongClickListener(this.onLongClickListener);
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
public void startConversation(final Contact contact) {
2014-03-15 05:20:59 +00:00
if ((contact.getAccount() == null) && (accounts.size() > 1)) {
2014-03-15 03:59:18 +00:00
getAccountChooser(new OnClickListener() {
2014-03-15 03:59:18 +00:00
@Override
public void onClick(DialogInterface dialog, int which) {
contact.setAccount(accounts.get(which));
showIsMucDialogIfNeeded(contact);
}
2014-03-15 05:20:59 +00:00
}).show();
2014-03-15 03:59:18 +00:00
} else {
2014-03-15 05:20:59 +00:00
if (contact.getAccount() == null) {
2014-03-15 03:59:18 +00:00
contact.setAccount(accounts.get(0));
}
2014-03-15 03:59:18 +00:00
showIsMucDialogIfNeeded(contact);
}
2014-01-24 01:04:05 +00:00
}
2014-03-15 05:20:59 +00:00
protected AlertDialog getAccountChooser(OnClickListener listener) {
String[] accountList = new String[accounts.size()];
for (int i = 0; i < accounts.size(); ++i) {
2014-03-15 05:20:59 +00:00
accountList[i] = accounts.get(i).getJid();
}
2014-03-15 05:20:59 +00:00
AlertDialog.Builder accountChooser = new AlertDialog.Builder(this);
accountChooser.setTitle("Choose account");
accountChooser.setItems(accountList, listener);
return accountChooser.create();
}
2014-03-15 05:20:59 +00:00
public void showIsMucDialogIfNeeded(final Contact clickedContact) {
if (clickedContact.couldBeMuc()) {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle("Multi User Conference");
dialog.setMessage("Are you trying to join a conference?");
dialog.setPositiveButton("Yes", new OnClickListener() {
2014-03-15 05:20:59 +00:00
@Override
public void onClick(DialogInterface dialog, int which) {
2014-03-15 05:20:59 +00:00
startConversation(clickedContact,
clickedContact.getAccount(), true);
}
});
dialog.setNegativeButton("No", new OnClickListener() {
2014-03-15 05:20:59 +00:00
@Override
public void onClick(DialogInterface dialog, int which) {
2014-03-15 05:20:59 +00:00
startConversation(clickedContact,
clickedContact.getAccount(), false);
}
});
dialog.create().show();
} else {
2014-03-15 05:20:59 +00:00
startConversation(clickedContact, clickedContact.getAccount(),
false);
}
}
public void startConversation(Contact contact, Account account, boolean muc) {
2014-03-27 10:41:32 +00:00
if (!contact.isInRoster()&&(!muc)) {
xmppConnectionService.createContact(contact);
}
Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, contact.getJid(), muc);
2014-03-15 05:20:59 +00:00
switchToConversation(conversation, null);
}
@Override
void onBackendConnected() {
this.accounts = xmppConnectionService.getAccounts();
if (Intent.ACTION_SENDTO.equals(getIntent().getAction())) {
getActionBar().setDisplayHomeAsUpEnabled(false);
getActionBar().setHomeButtonEnabled(false);
String jid;
try {
2014-03-15 05:20:59 +00:00
jid = URLDecoder.decode(getIntent().getData().getEncodedPath(),
"UTF-8").split("/")[1];
} catch (UnsupportedEncodingException e) {
jid = null;
}
2014-03-15 05:20:59 +00:00
if (jid != null) {
final String finalJid = jid;
if (this.accounts.size() > 1) {
getAccountChooser(new OnClickListener() {
2014-03-15 05:20:59 +00:00
@Override
public void onClick(DialogInterface dialog, int which) {
2014-03-15 05:20:59 +00:00
Conversation conversation = xmppConnectionService
.findOrCreateConversation(
accounts.get(which), finalJid,
false);
switchToConversation(conversation, null);
2014-03-13 20:37:27 +00:00
finish();
}
}).show();
} else {
2014-03-15 05:20:59 +00:00
Conversation conversation = xmppConnectionService
.findOrCreateConversation(this.accounts.get(0),
jid, false);
switchToConversation(conversation, null);
2014-03-13 20:37:27 +00:00
finish();
}
}
}
2014-03-15 05:20:59 +00:00
if (xmppConnectionService.getConversationCount() == 0) {
2014-01-28 18:21:54 +00:00
getActionBar().setDisplayHomeAsUpEnabled(false);
getActionBar().setHomeButtonEnabled(false);
}
this.rosterContacts.clear();
2014-05-17 09:08:32 +00:00
for(Account account : accounts) {
if (account.getStatus() != Account.STATUS_DISABLED) {
rosterContacts.addAll(xmppConnectionService.getRoster(account));
}
2014-02-07 01:57:36 +00:00
}
2014-03-13 20:37:27 +00:00
updateAggregatedContacts();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.newconversation, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
2014-02-07 01:57:36 +00:00
case R.id.action_refresh_contacts:
refreshContacts();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
2014-02-07 01:57:36 +00:00
private void refreshContacts() {
final ProgressBar progress = (ProgressBar) findViewById(R.id.progressBar1);
final EditText searchBar = (EditText) findViewById(R.id.new_conversation_search);
final TextView contactsHeader = (TextView) findViewById(R.id.contacts_header);
final ListView contactList = (ListView) findViewById(R.id.contactList);
searchBar.setVisibility(View.GONE);
contactsHeader.setVisibility(View.GONE);
contactList.setVisibility(View.GONE);
progress.setVisibility(View.VISIBLE);
this.accounts = xmppConnectionService.getAccounts();
this.rosterContacts.clear();
for (int i = 0; i < accounts.size(); ++i) {
if (accounts.get(i).getStatus() == Account.STATUS_ONLINE) {
xmppConnectionService.updateRoster(accounts.get(i),
new OnRosterFetchedListener() {
@Override
public void onRosterFetched(
final List<Contact> roster) {
runOnUiThread(new Runnable() {
@Override
public void run() {
rosterContacts.addAll(roster);
progress.setVisibility(View.GONE);
searchBar.setVisibility(View.VISIBLE);
contactList.setVisibility(View.VISIBLE);
contactList.setVisibility(View.VISIBLE);
updateAggregatedContacts();
}
});
}
});
2014-02-07 01:57:36 +00:00
}
}
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
@Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
this.isActionMode = true;
search.setEnabled(false);
}
2014-03-15 05:20:59 +00:00
2014-03-15 03:59:18 +00:00
@Override
public void onActionModeFinished(ActionMode mode) {
super.onActionModeFinished(mode);
2014-03-15 05:20:59 +00:00
if (inviteIntent) {
finish();
} else {
this.isActionMode = false;
contactsView.clearChoices();
contactsView.requestLayout();
contactsView.post(new Runnable() {
@Override
public void run() {
contactsView.setChoiceMode(ListView.CHOICE_MODE_NONE);
}
});
search.setEnabled(true);
}
2014-03-15 03:59:18 +00:00
}
2014-03-15 05:20:59 +00:00
2014-01-24 01:04:05 +00:00
}