StartConversationActivity.java

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