StartConversationActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.annotation.SuppressLint;
  4import android.app.ActionBar;
  5import android.app.ActionBar.Tab;
  6import android.app.ActionBar.TabListener;
  7import android.app.AlertDialog;
  8import android.app.Fragment;
  9import android.app.FragmentTransaction;
 10import android.app.ListFragment;
 11import android.content.Context;
 12import android.content.DialogInterface;
 13import android.content.DialogInterface.OnClickListener;
 14import android.content.Intent;
 15import android.net.Uri;
 16import android.nfc.NdefMessage;
 17import android.nfc.NdefRecord;
 18import android.nfc.NfcAdapter;
 19import android.os.Bundle;
 20import android.os.Parcelable;
 21import android.support.v13.app.FragmentPagerAdapter;
 22import android.support.v4.view.ViewPager;
 23import android.text.Editable;
 24import android.text.TextWatcher;
 25import android.view.ContextMenu;
 26import android.view.ContextMenu.ContextMenuInfo;
 27import android.view.KeyEvent;
 28import android.view.Menu;
 29import android.view.MenuItem;
 30import android.view.View;
 31import android.view.inputmethod.InputMethodManager;
 32import android.widget.AdapterView;
 33import android.widget.AdapterView.AdapterContextMenuInfo;
 34import android.widget.AdapterView.OnItemClickListener;
 35import android.widget.ArrayAdapter;
 36import android.widget.AutoCompleteTextView;
 37import android.widget.CheckBox;
 38import android.widget.EditText;
 39import android.widget.ListView;
 40import android.widget.Spinner;
 41
 42import com.google.zxing.integration.android.IntentIntegrator;
 43import com.google.zxing.integration.android.IntentResult;
 44
 45import java.io.UnsupportedEncodingException;
 46import java.net.URLDecoder;
 47import java.util.ArrayList;
 48import java.util.Collections;
 49import java.util.List;
 50
 51import eu.siacs.conversations.R;
 52import eu.siacs.conversations.entities.Account;
 53import eu.siacs.conversations.entities.Bookmark;
 54import eu.siacs.conversations.entities.Contact;
 55import eu.siacs.conversations.entities.Conversation;
 56import eu.siacs.conversations.entities.ListItem;
 57import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 58import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 59import eu.siacs.conversations.ui.adapter.ListItemAdapter;
 60import eu.siacs.conversations.utils.Validator;
 61
 62public class StartConversationActivity extends XmppActivity {
 63
 64	private Tab mContactsTab;
 65	private Tab mConferencesTab;
 66	private ViewPager mViewPager;
 67
 68	private MyListFragment mContactsListFragment = new MyListFragment();
 69	private List<ListItem> contacts = new ArrayList<ListItem>();
 70	private ArrayAdapter<ListItem> mContactsAdapter;
 71
 72	private MyListFragment mConferenceListFragment = new MyListFragment();
 73	private List<ListItem> conferences = new ArrayList<ListItem>();
 74	private ArrayAdapter<ListItem> mConferenceAdapter;
 75
 76	private List<String> mActivatedAccounts = new ArrayList<String>();
 77	private List<String> mKnownHosts;
 78	private List<String> mKnownConferenceHosts;
 79
 80	private Invite mPendingInvite = null;
 81
 82	private Menu mOptionsMenu;
 83	private EditText mSearchEditText;
 84
 85	public int conference_context_id;
 86	public int contact_context_id;
 87
 88	private TabListener mTabListener = new TabListener() {
 89
 90		@Override
 91		public void onTabUnselected(Tab tab, FragmentTransaction ft) {
 92			return;
 93		}
 94
 95		@Override
 96		public void onTabSelected(Tab tab, FragmentTransaction ft) {
 97			mViewPager.setCurrentItem(tab.getPosition());
 98			onTabChanged();
 99		}
100
101		@Override
102		public void onTabReselected(Tab tab, FragmentTransaction ft) {
103			return;
104		}
105	};
106
107	private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
108		@Override
109		public void onPageSelected(int position) {
110			getActionBar().setSelectedNavigationItem(position);
111			onTabChanged();
112		}
113	};
114
115	private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
116
117		@Override
118		public boolean onMenuItemActionExpand(MenuItem item) {
119			mSearchEditText.post(new Runnable() {
120
121				@Override
122				public void run() {
123					mSearchEditText.requestFocus();
124					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
125					imm.showSoftInput(mSearchEditText,
126							InputMethodManager.SHOW_IMPLICIT);
127				}
128			});
129
130			return true;
131		}
132
133		@Override
134		public boolean onMenuItemActionCollapse(MenuItem item) {
135			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
136			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
137					InputMethodManager.HIDE_IMPLICIT_ONLY);
138			mSearchEditText.setText("");
139			filter(null);
140			return true;
141		}
142	};
143	private TextWatcher mSearchTextWatcher = new TextWatcher() {
144
145		@Override
146		public void afterTextChanged(Editable editable) {
147			filter(editable.toString());
148		}
149
150		@Override
151		public void beforeTextChanged(CharSequence s, int start, int count,
152									  int after) {
153		}
154
155		@Override
156		public void onTextChanged(CharSequence s, int start, int before,
157								  int count) {
158		}
159	};
160	private OnRosterUpdate onRosterUpdate = new OnRosterUpdate() {
161
162		@Override
163		public void onRosterUpdate() {
164			runOnUiThread(new Runnable() {
165
166				@Override
167				public void run() {
168					if (mSearchEditText != null) {
169						filter(mSearchEditText.getText().toString());
170					}
171				}
172			});
173		}
174	};
175	private MenuItem mMenuSearchView;
176	private String mInitialJid;
177
178	@Override
179	public void onCreate(Bundle savedInstanceState) {
180		super.onCreate(savedInstanceState);
181		setContentView(R.layout.activity_start_conversation);
182		mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
183		ActionBar actionBar = getActionBar();
184		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
185
186		mContactsTab = actionBar.newTab().setText(R.string.contacts)
187				.setTabListener(mTabListener);
188		mConferencesTab = actionBar.newTab().setText(R.string.conferences)
189				.setTabListener(mTabListener);
190		actionBar.addTab(mContactsTab);
191		actionBar.addTab(mConferencesTab);
192
193		mViewPager.setOnPageChangeListener(mOnPageChangeListener);
194		mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
195
196			@Override
197			public int getCount() {
198				return 2;
199			}
200
201			@Override
202			public Fragment getItem(int position) {
203				if (position == 0) {
204					return mContactsListFragment;
205				} else {
206					return mConferenceListFragment;
207				}
208			}
209		});
210
211		mConferenceAdapter = new ListItemAdapter(this, conferences);
212		mConferenceListFragment.setListAdapter(mConferenceAdapter);
213		mConferenceListFragment.setContextMenu(R.menu.conference_context);
214		mConferenceListFragment
215				.setOnListItemClickListener(new OnItemClickListener() {
216
217					@Override
218					public void onItemClick(AdapterView<?> arg0, View arg1,
219											int position, long arg3) {
220						openConversationForBookmark(position);
221					}
222				});
223
224		mContactsAdapter = new ListItemAdapter(this, contacts);
225		mContactsListFragment.setListAdapter(mContactsAdapter);
226		mContactsListFragment.setContextMenu(R.menu.contact_context);
227		mContactsListFragment
228				.setOnListItemClickListener(new OnItemClickListener() {
229
230					@Override
231					public void onItemClick(AdapterView<?> arg0, View arg1,
232											int position, long arg3) {
233						openConversationForContact(position);
234					}
235				});
236
237	}
238
239	@Override
240	public void onStop() {
241		super.onStop();
242		xmppConnectionService.removeOnRosterUpdateListener();
243	}
244
245	protected void openConversationForContact(int position) {
246		Contact contact = (Contact) contacts.get(position);
247		Conversation conversation = xmppConnectionService
248				.findOrCreateConversation(contact.getAccount(),
249						contact.getJid(), false);
250		switchToConversation(conversation);
251	}
252
253	protected void openConversationForContact() {
254		int position = contact_context_id;
255		openConversationForContact(position);
256	}
257
258	protected void openConversationForBookmark() {
259		openConversationForBookmark(conference_context_id);
260	}
261
262	protected void openConversationForBookmark(int position) {
263		Bookmark bookmark = (Bookmark) conferences.get(position);
264		Conversation conversation = xmppConnectionService
265				.findOrCreateConversation(bookmark.getAccount(),
266						bookmark.getJid(), true);
267		conversation.setBookmark(bookmark);
268		if (!conversation.getMucOptions().online()) {
269			xmppConnectionService.joinMuc(conversation);
270		}
271		if (!bookmark.autojoin()) {
272			bookmark.setAutojoin(true);
273			xmppConnectionService.pushBookmarks(bookmark.getAccount());
274		}
275		switchToConversation(conversation);
276	}
277
278	protected void openDetailsForContact() {
279		int position = contact_context_id;
280		Contact contact = (Contact) contacts.get(position);
281		switchToContactDetails(contact);
282	}
283
284	protected void deleteContact() {
285		int position = contact_context_id;
286		final Contact contact = (Contact) contacts.get(position);
287		AlertDialog.Builder builder = new AlertDialog.Builder(this);
288		builder.setNegativeButton(R.string.cancel, null);
289		builder.setTitle(R.string.action_delete_contact);
290		builder.setMessage(getString(R.string.remove_contact_text,
291				contact.getJid()));
292		builder.setPositiveButton(R.string.delete, new OnClickListener() {
293
294			@Override
295			public void onClick(DialogInterface dialog, int which) {
296				xmppConnectionService.deleteContactOnServer(contact);
297				filter(mSearchEditText.getText().toString());
298			}
299		});
300		builder.create().show();
301
302	}
303
304	protected void deleteConference() {
305		int position = conference_context_id;
306		final Bookmark bookmark = (Bookmark) conferences.get(position);
307
308		AlertDialog.Builder builder = new AlertDialog.Builder(this);
309		builder.setNegativeButton(R.string.cancel, null);
310		builder.setTitle(R.string.delete_bookmark);
311		builder.setMessage(getString(R.string.remove_bookmark_text,
312				bookmark.getJid()));
313		builder.setPositiveButton(R.string.delete, new OnClickListener() {
314
315			@Override
316			public void onClick(DialogInterface dialog, int which) {
317				bookmark.unregisterConversation();
318				Account account = bookmark.getAccount();
319				account.getBookmarks().remove(bookmark);
320				xmppConnectionService.pushBookmarks(account);
321				filter(mSearchEditText.getText().toString());
322			}
323		});
324		builder.create().show();
325
326	}
327
328	@SuppressLint("InflateParams")
329	protected void showCreateContactDialog(String prefilledJid) {
330		AlertDialog.Builder builder = new AlertDialog.Builder(this);
331		builder.setTitle(R.string.create_contact);
332		View dialogView = getLayoutInflater().inflate(
333				R.layout.create_contact_dialog, null);
334		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
335		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
336				.findViewById(R.id.jid);
337		jid.setAdapter(new KnownHostsAdapter(this,
338				android.R.layout.simple_list_item_1, mKnownHosts));
339		if (prefilledJid != null) {
340			jid.append(prefilledJid);
341		}
342		populateAccountSpinner(spinner);
343		builder.setView(dialogView);
344		builder.setNegativeButton(R.string.cancel, null);
345		builder.setPositiveButton(R.string.create, null);
346		final AlertDialog dialog = builder.create();
347		dialog.show();
348		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
349				new View.OnClickListener() {
350
351					@Override
352					public void onClick(View v) {
353						if (!xmppConnectionServiceBound) {
354							return;
355						}
356						if (Validator.isValidJid(jid.getText().toString())) {
357							String accountJid = (String) spinner
358									.getSelectedItem();
359							String contactJid = jid.getText().toString();
360							Account account = xmppConnectionService
361									.findAccountByJid(accountJid);
362							if (account == null) {
363								dialog.dismiss();
364								return;
365							}
366							Contact contact = account.getRoster().getContact(
367									contactJid);
368							if (contact.showInRoster()) {
369								jid.setError(getString(R.string.contact_already_exists));
370							} else {
371								xmppConnectionService.createContact(contact);
372								dialog.dismiss();
373								switchToConversation(contact);
374							}
375						} else {
376							jid.setError(getString(R.string.invalid_jid));
377						}
378					}
379				});
380
381	}
382
383	@SuppressLint("InflateParams")
384	protected void showJoinConferenceDialog(String prefilledJid) {
385		AlertDialog.Builder builder = new AlertDialog.Builder(this);
386		builder.setTitle(R.string.join_conference);
387		View dialogView = getLayoutInflater().inflate(
388				R.layout.join_conference_dialog, null);
389		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
390		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
391				.findViewById(R.id.jid);
392		jid.setAdapter(new KnownHostsAdapter(this,
393				android.R.layout.simple_list_item_1, mKnownConferenceHosts));
394		if (prefilledJid != null) {
395			jid.append(prefilledJid);
396		}
397		populateAccountSpinner(spinner);
398		final CheckBox bookmarkCheckBox = (CheckBox) dialogView
399				.findViewById(R.id.bookmark);
400		builder.setView(dialogView);
401		builder.setNegativeButton(R.string.cancel, null);
402		builder.setPositiveButton(R.string.join, null);
403		final AlertDialog dialog = builder.create();
404		dialog.show();
405		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
406				new View.OnClickListener() {
407
408					@Override
409					public void onClick(View v) {
410						if (!xmppConnectionServiceBound) {
411							return;
412						}
413						if (Validator.isValidJid(jid.getText().toString())) {
414							String accountJid = (String) spinner
415									.getSelectedItem();
416							String conferenceJid = jid.getText().toString();
417							Account account = xmppConnectionService
418									.findAccountByJid(accountJid);
419							if (account == null) {
420								dialog.dismiss();
421								return;
422							}
423							if (bookmarkCheckBox.isChecked()) {
424								if (account.hasBookmarkFor(conferenceJid)) {
425									jid.setError(getString(R.string.bookmark_already_exists));
426								} else {
427									Bookmark bookmark = new Bookmark(account,
428											conferenceJid);
429									bookmark.setAutojoin(true);
430									account.getBookmarks().add(bookmark);
431									xmppConnectionService
432											.pushBookmarks(account);
433									Conversation conversation = xmppConnectionService
434											.findOrCreateConversation(account,
435													conferenceJid, true);
436									conversation.setBookmark(bookmark);
437									if (!conversation.getMucOptions().online()) {
438										xmppConnectionService
439												.joinMuc(conversation);
440									}
441									dialog.dismiss();
442									switchToConversation(conversation);
443								}
444							} else {
445								Conversation conversation = xmppConnectionService
446										.findOrCreateConversation(account,
447												conferenceJid, true);
448								if (!conversation.getMucOptions().online()) {
449									xmppConnectionService.joinMuc(conversation);
450								}
451								dialog.dismiss();
452								switchToConversation(conversation);
453							}
454						} else {
455							jid.setError(getString(R.string.invalid_jid));
456						}
457					}
458				});
459	}
460
461	protected void switchToConversation(Contact contact) {
462		Conversation conversation = xmppConnectionService
463				.findOrCreateConversation(contact.getAccount(),
464						contact.getJid(), false);
465		switchToConversation(conversation);
466	}
467
468	private void populateAccountSpinner(Spinner spinner) {
469		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
470				android.R.layout.simple_spinner_item, mActivatedAccounts);
471		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
472		spinner.setAdapter(adapter);
473	}
474
475	@Override
476	public boolean onCreateOptionsMenu(Menu menu) {
477		this.mOptionsMenu = menu;
478		getMenuInflater().inflate(R.menu.start_conversation, menu);
479		MenuItem menuCreateContact = menu
480				.findItem(R.id.action_create_contact);
481		MenuItem menuCreateConference = menu
482				.findItem(R.id.action_join_conference);
483		mMenuSearchView = menu.findItem(R.id.action_search);
484		mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
485		View mSearchView = mMenuSearchView.getActionView();
486		mSearchEditText = (EditText) mSearchView
487				.findViewById(R.id.search_field);
488		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
489		if (getActionBar().getSelectedNavigationIndex() == 0) {
490			menuCreateConference.setVisible(false);
491		} else {
492			menuCreateContact.setVisible(false);
493		}
494		if (mInitialJid != null) {
495			mMenuSearchView.expandActionView();
496			mSearchEditText.append(mInitialJid);
497			filter(mInitialJid);
498		}
499		return true;
500	}
501
502	@Override
503	public boolean onOptionsItemSelected(MenuItem item) {
504		switch (item.getItemId()) {
505			case R.id.action_create_contact:
506				showCreateContactDialog(null);
507				return true;
508			case R.id.action_join_conference:
509				showJoinConferenceDialog(null);
510				return true;
511			case R.id.action_scan_qr_code:
512				new IntentIntegrator(this).initiateScan();
513				return true;
514		}
515		return super.onOptionsItemSelected(item);
516	}
517
518	@Override
519	public boolean onKeyUp(int keyCode, KeyEvent event) {
520		if (keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress()) {
521			mOptionsMenu.findItem(R.id.action_search).expandActionView();
522			return true;
523		}
524		return super.onKeyUp(keyCode, event);
525	}
526
527	@Override
528	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
529		if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
530			IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
531			if (scanResult != null && scanResult.getFormatName() != null) {
532				String data = scanResult.getContents();
533				Invite invite = parseInviteUri(data);
534				if (xmppConnectionServiceBound) {
535					if (invite.muc) {
536						showJoinConferenceDialog(invite.jid);
537					} else {
538						handleJid(invite.jid);
539					}
540				} else if (invite.jid != null) {
541					this.mPendingInvite = invite;
542				} else {
543					this.mPendingInvite = null;
544				}
545			}
546		}
547		super.onActivityResult(requestCode, requestCode, intent);
548	}
549
550	@Override
551	protected void onBackendConnected() {
552		xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate);
553		this.mActivatedAccounts.clear();
554		for (Account account : xmppConnectionService.getAccounts()) {
555			if (account.getStatus() != Account.STATUS_DISABLED) {
556				this.mActivatedAccounts.add(account.getJid());
557			}
558		}
559		this.mKnownHosts = xmppConnectionService.getKnownHosts();
560		this.mKnownConferenceHosts = xmppConnectionService
561				.getKnownConferenceHosts();
562		if (this.mPendingInvite != null) {
563			if (this.mPendingInvite.muc) {
564				showJoinConferenceDialog(this.mPendingInvite.jid);
565			} else {
566				handleJid(this.mPendingInvite.jid);
567			}
568			this.mPendingInvite = null;
569		} else if (!handleIntent(getIntent())) {
570			if (mSearchEditText != null) {
571				filter(mSearchEditText.getText().toString());
572			} else {
573				filter(null);
574			}
575		}
576		setIntent(null);
577	}
578
579	protected boolean handleIntent(Intent intent) {
580		if (intent == null || intent.getAction() == null) {
581			return false;
582		}
583		String jid;
584		Uri uri;
585		Invite invite;
586		switch (intent.getAction()) {
587			case Intent.ACTION_SENDTO:
588				try {
589					jid = URLDecoder.decode(
590							intent.getData().getEncodedPath(), "UTF-8").split(
591							"/")[1];
592					return handleJid(jid);
593				} catch (UnsupportedEncodingException e) {
594					return false;
595				}
596			case Intent.ACTION_VIEW:
597				uri = intent.getData();
598				invite = parseInviteUri(uri);
599				if (invite.muc) {
600					showJoinConferenceDialog(invite.jid);
601					return false;
602				} else {
603					return handleJid(invite.jid);
604				}
605			case NfcAdapter.ACTION_NDEF_DISCOVERED:
606				if (android.os.Build.VERSION.SDK_INT >= 16) {
607					Parcelable[] messages = getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
608					NdefMessage message = (NdefMessage) messages[0];
609					NdefRecord record = message.getRecords()[0];
610					invite = parseInviteUri(record.toUri());
611					if (invite != null) {
612						if (invite.muc) {
613							showJoinConferenceDialog(invite.jid);
614							return false;
615						} else {
616							return handleJid(invite.jid);
617						}
618					}
619				} else {
620					return false;
621				}
622			default:
623				return false;
624		}
625	}
626
627	private Invite parseInviteUri(String uri) {
628		try {
629			return parseInviteUri(Uri.parse(uri));
630		} catch (IllegalArgumentException e) {
631			return null;
632		}
633	}
634
635	private Invite parseInviteUri(Uri uri) {
636		Invite invite = new Invite();
637		invite.muc = uri.getQuery() != null && uri.getQuery().equalsIgnoreCase("join");
638		if (uri.getAuthority() != null) {
639			invite.jid = uri.getAuthority();
640		} else {
641			invite.jid = uri.getSchemeSpecificPart().split("\\?")[0];
642		}
643		return invite;
644	}
645
646	private boolean handleJid(String jid) {
647		List<Contact> contacts = xmppConnectionService.findContacts(jid);
648		if (contacts.size() == 0) {
649			showCreateContactDialog(jid);
650			return false;
651		} else if (contacts.size() == 1) {
652			switchToConversation(contacts.get(0));
653			return true;
654		} else {
655			if (mMenuSearchView != null) {
656				mMenuSearchView.expandActionView();
657				mSearchEditText.setText("");
658				mSearchEditText.append(jid);
659				filter(jid);
660			} else {
661				mInitialJid = jid;
662			}
663			return true;
664		}
665	}
666
667	protected void filter(String needle) {
668		if (xmppConnectionServiceBound) {
669			this.filterContacts(needle);
670			this.filterConferences(needle);
671		}
672	}
673
674	protected void filterContacts(String needle) {
675		this.contacts.clear();
676		for (Account account : xmppConnectionService.getAccounts()) {
677			if (account.getStatus() != Account.STATUS_DISABLED) {
678				for (Contact contact : account.getRoster().getContacts()) {
679					if (contact.showInRoster() && contact.match(needle)) {
680						this.contacts.add(contact);
681					}
682				}
683			}
684		}
685		Collections.sort(this.contacts);
686		mContactsAdapter.notifyDataSetChanged();
687	}
688
689	protected void filterConferences(String needle) {
690		this.conferences.clear();
691		for (Account account : xmppConnectionService.getAccounts()) {
692			if (account.getStatus() != Account.STATUS_DISABLED) {
693				for (Bookmark bookmark : account.getBookmarks()) {
694					if (bookmark.match(needle)) {
695						this.conferences.add(bookmark);
696					}
697				}
698			}
699		}
700		Collections.sort(this.conferences);
701		mConferenceAdapter.notifyDataSetChanged();
702	}
703
704	private void onTabChanged() {
705		invalidateOptionsMenu();
706	}
707
708	public static class MyListFragment extends ListFragment {
709		private AdapterView.OnItemClickListener mOnItemClickListener;
710		private int mResContextMenu;
711
712		public void setContextMenu(int res) {
713			this.mResContextMenu = res;
714		}
715
716		@Override
717		public void onListItemClick(ListView l, View v, int position, long id) {
718			if (mOnItemClickListener != null) {
719				mOnItemClickListener.onItemClick(l, v, position, id);
720			}
721		}
722
723		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
724			this.mOnItemClickListener = l;
725		}
726
727		@Override
728		public void onViewCreated(View view, Bundle savedInstanceState) {
729			super.onViewCreated(view, savedInstanceState);
730			registerForContextMenu(getListView());
731			getListView().setFastScrollEnabled(true);
732		}
733
734		@Override
735		public void onCreateContextMenu(ContextMenu menu, View v,
736										ContextMenuInfo menuInfo) {
737			super.onCreateContextMenu(menu, v, menuInfo);
738			StartConversationActivity activity = (StartConversationActivity) getActivity();
739			activity.getMenuInflater().inflate(mResContextMenu, menu);
740			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
741			if (mResContextMenu == R.menu.conference_context) {
742				activity.conference_context_id = acmi.position;
743			} else {
744				activity.contact_context_id = acmi.position;
745			}
746		}
747
748		@Override
749		public boolean onContextItemSelected(MenuItem item) {
750			StartConversationActivity activity = (StartConversationActivity) getActivity();
751			switch (item.getItemId()) {
752				case R.id.context_start_conversation:
753					activity.openConversationForContact();
754					break;
755				case R.id.context_contact_details:
756					activity.openDetailsForContact();
757					break;
758				case R.id.context_delete_contact:
759					activity.deleteContact();
760					break;
761				case R.id.context_join_conference:
762					activity.openConversationForBookmark();
763					break;
764				case R.id.context_delete_conference:
765					activity.deleteConference();
766			}
767			return true;
768		}
769	}
770
771	private class Invite {
772		public String jid;
773		public boolean muc;
774	}
775}