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