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