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