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