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(R.layout.create_contact_dialog, null);
322		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
323		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
324		jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownHosts));
325		if (prefilledJid != null) {
326			jid.append(prefilledJid);
327			if (fingerprint!=null) {
328				jid.setFocusable(false);
329				jid.setFocusableInTouchMode(false);
330				jid.setClickable(false);
331				jid.setCursorVisible(false);
332			}
333		}
334		populateAccountSpinner(spinner);
335		builder.setView(dialogView);
336		builder.setNegativeButton(R.string.cancel, null);
337		builder.setPositiveButton(R.string.create, null);
338		final AlertDialog dialog = builder.create();
339		dialog.show();
340		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
341				new View.OnClickListener() {
342
343					@Override
344					public void onClick(View v) {
345						if (!xmppConnectionServiceBound) {
346							return;
347						}
348						if (Validator.isValidJid(jid.getText().toString())) {
349							final Jid accountJid;
350							try {
351								accountJid = Jid.fromString((String) spinner.getSelectedItem());
352							} catch (final InvalidJidException e) {
353								return;
354							}
355							final Jid contactJid;
356							try {
357								contactJid = Jid.fromString(jid.getText().toString());
358							} catch (final InvalidJidException e) {
359								jid.setError(getString(R.string.invalid_jid));
360								return;
361							}
362							Account account = xmppConnectionService
363									.findAccountByJid(accountJid);
364							if (account == null) {
365								dialog.dismiss();
366								return;
367							}
368							Contact contact = account.getRoster().getContact(contactJid);
369							if (contact.showInRoster()) {
370								jid.setError(getString(R.string.contact_already_exists));
371							} else {
372								contact.addOtrFingerprint(fingerprint);
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(R.layout.join_conference_dialog, null);
390		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
391		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
392		jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownConferenceHosts));
393		if (prefilledJid != null) {
394			jid.append(prefilledJid);
395		}
396		populateAccountSpinner(spinner);
397		final CheckBox bookmarkCheckBox = (CheckBox) dialogView
398				.findViewById(R.id.bookmark);
399		builder.setView(dialogView);
400		builder.setNegativeButton(R.string.cancel, null);
401		builder.setPositiveButton(R.string.join, null);
402		final AlertDialog dialog = builder.create();
403		dialog.show();
404		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
405				new View.OnClickListener() {
406
407					@Override
408					public void onClick(View v) {
409						if (!xmppConnectionServiceBound) {
410							return;
411						}
412						if (Validator.isValidJid(jid.getText().toString())) {
413							final Jid accountJid;
414							try {
415								accountJid = Jid.fromString((String) spinner.getSelectedItem());
416							} catch (final InvalidJidException e) {
417								return;
418							}
419							final Jid conferenceJid;
420							try {
421								conferenceJid = Jid.fromString(jid.getText().toString());
422							} catch (final InvalidJidException e) {
423								jid.setError(getString(R.string.invalid_jid));
424								return;
425							}
426							Account account = xmppConnectionService
427									.findAccountByJid(accountJid);
428							if (account == null) {
429								dialog.dismiss();
430								return;
431							}
432							if (bookmarkCheckBox.isChecked()) {
433								if (account.hasBookmarkFor(conferenceJid)) {
434									jid.setError(getString(R.string.bookmark_already_exists));
435								} else {
436									Bookmark bookmark = new Bookmark(account,
437											conferenceJid);
438									bookmark.setAutojoin(true);
439									account.getBookmarks().add(bookmark);
440									xmppConnectionService
441											.pushBookmarks(account);
442									Conversation conversation = xmppConnectionService
443											.findOrCreateConversation(account,
444													conferenceJid, true);
445									conversation.setBookmark(bookmark);
446									if (!conversation.getMucOptions().online()) {
447										xmppConnectionService
448												.joinMuc(conversation);
449									}
450									dialog.dismiss();
451									switchToConversation(conversation);
452								}
453							} else {
454								Conversation conversation = xmppConnectionService
455										.findOrCreateConversation(account,
456												conferenceJid, true);
457								if (!conversation.getMucOptions().online()) {
458									xmppConnectionService.joinMuc(conversation);
459								}
460								dialog.dismiss();
461								switchToConversation(conversation);
462							}
463						} else {
464							jid.setError(getString(R.string.invalid_jid));
465						}
466					}
467				});
468	}
469
470	protected void switchToConversation(Contact contact) {
471		Conversation conversation = xmppConnectionService
472				.findOrCreateConversation(contact.getAccount(),
473						contact.getJid(), false);
474		switchToConversation(conversation);
475	}
476
477	private void populateAccountSpinner(Spinner spinner) {
478		ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
479				android.R.layout.simple_spinner_item, mActivatedAccounts);
480		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
481		spinner.setAdapter(adapter);
482	}
483
484	@Override
485	public boolean onCreateOptionsMenu(Menu menu) {
486		this.mOptionsMenu = menu;
487		getMenuInflater().inflate(R.menu.start_conversation, menu);
488		MenuItem menuCreateContact = menu
489				.findItem(R.id.action_create_contact);
490		MenuItem menuCreateConference = menu
491				.findItem(R.id.action_join_conference);
492		mMenuSearchView = menu.findItem(R.id.action_search);
493		mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
494		View mSearchView = mMenuSearchView.getActionView();
495		mSearchEditText = (EditText) mSearchView
496				.findViewById(R.id.search_field);
497		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
498		if (getActionBar().getSelectedNavigationIndex() == 0) {
499			menuCreateConference.setVisible(false);
500		} else {
501			menuCreateContact.setVisible(false);
502		}
503		if (mInitialJid != null) {
504			mMenuSearchView.expandActionView();
505			mSearchEditText.append(mInitialJid);
506			filter(mInitialJid);
507		}
508		return true;
509	}
510
511	@Override
512	public boolean onOptionsItemSelected(MenuItem item) {
513		switch (item.getItemId()) {
514			case R.id.action_create_contact:
515				showCreateContactDialog(null,null);
516				return true;
517			case R.id.action_join_conference:
518				showJoinConferenceDialog(null);
519				return true;
520			case R.id.action_scan_qr_code:
521				new IntentIntegrator(this).initiateScan();
522				return true;
523		}
524		return super.onOptionsItemSelected(item);
525	}
526
527	@Override
528	public boolean onKeyUp(int keyCode, KeyEvent event) {
529		if (keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress()) {
530			mOptionsMenu.findItem(R.id.action_search).expandActionView();
531			return true;
532		}
533		return super.onKeyUp(keyCode, event);
534	}
535
536	@Override
537	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
538		if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
539			IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
540			if (scanResult != null && scanResult.getFormatName() != null) {
541				String data = scanResult.getContents();
542				Invite invite = new Invite(data);
543				if (xmppConnectionServiceBound) {
544					invite.invite();
545				} else if (invite.getJid() != null) {
546					this.mPendingInvite = invite;
547				} else {
548					this.mPendingInvite = null;
549				}
550			}
551		}
552		super.onActivityResult(requestCode, requestCode, intent);
553	}
554
555	@Override
556	protected void onBackendConnected() {
557		this.mActivatedAccounts.clear();
558		for (Account account : xmppConnectionService.getAccounts()) {
559			if (account.getStatus() != Account.State.DISABLED) {
560				this.mActivatedAccounts.add(account.getJid().toBareJid().toString());
561			}
562		}
563		this.mKnownHosts = xmppConnectionService.getKnownHosts();
564		this.mKnownConferenceHosts = xmppConnectionService
565				.getKnownConferenceHosts();
566		if (this.mPendingInvite != null) {
567			mPendingInvite.invite();
568			this.mPendingInvite = null;
569		} else if (!handleIntent(getIntent())) {
570			if (mSearchEditText != null) {
571				filter(mSearchEditText.getText().toString());
572			} else {
573				filter(null);
574			}
575		}
576		setIntent(null);
577	}
578
579	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
580	Invite getInviteJellyBean(NdefRecord record) {
581		return new Invite(record.toUri());
582	}
583
584	protected boolean handleIntent(Intent intent) {
585		if (intent == null || intent.getAction() == null) {
586			return false;
587		}
588		switch (intent.getAction()) {
589			case Intent.ACTION_SENDTO:
590			case Intent.ACTION_VIEW:
591				Log.d(Config.LOGTAG, "received uri=" + intent.getData());
592				return new Invite(intent.getData()).invite();
593			case NfcAdapter.ACTION_NDEF_DISCOVERED:
594				for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) {
595					if (message instanceof NdefMessage) {
596						Log.d(Config.LOGTAG, "received message=" + message);
597						for (NdefRecord record : ((NdefMessage) message).getRecords()) {
598							switch (record.getTnf()) {
599								case NdefRecord.TNF_WELL_KNOWN:
600									if (Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
601										if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
602											return getInviteJellyBean(record).invite();
603										} else {
604											byte[] payload = record.getPayload();
605											if (payload[0] == 0) {
606												return new Invite(Uri.parse(new String(Arrays.copyOfRange(
607														payload, 1, payload.length)))).invite();
608											}
609										}
610									}
611							}
612						}
613					}
614				}
615		}
616		return false;
617	}
618
619	private boolean handleJid(Invite invite) {
620		List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid());
621		if (contacts.size() == 0) {
622			showCreateContactDialog(invite.getJid().toString(),invite.getFingerprint());
623			return false;
624		} else if (contacts.size() == 1) {
625			Contact contact = contacts.get(0);
626			if (invite.getFingerprint() != null) {
627				if (contact.addOtrFingerprint(invite.getFingerprint())) {
628					Log.d(Config.LOGTAG,"added new fingerprint");
629					xmppConnectionService.syncRosterToDisk(contact.getAccount());
630				}
631			}
632			switchToConversation(contact);
633			return true;
634		} else {
635			if (mMenuSearchView != null) {
636				mMenuSearchView.expandActionView();
637				mSearchEditText.setText("");
638				mSearchEditText.append(invite.getJid().toString());
639				filter(invite.getJid().toString());
640			} else {
641				mInitialJid = invite.getJid().toString();
642			}
643			return true;
644		}
645	}
646
647	protected void filter(String needle) {
648		if (xmppConnectionServiceBound) {
649			this.filterContacts(needle);
650			this.filterConferences(needle);
651		}
652	}
653
654	protected void filterContacts(String needle) {
655		this.contacts.clear();
656		for (Account account : xmppConnectionService.getAccounts()) {
657			if (account.getStatus() != Account.State.DISABLED) {
658				for (Contact contact : account.getRoster().getContacts()) {
659					if (contact.showInRoster() && contact.match(needle)) {
660						this.contacts.add(contact);
661					}
662				}
663			}
664		}
665		Collections.sort(this.contacts);
666		mContactsAdapter.notifyDataSetChanged();
667	}
668
669	protected void filterConferences(String needle) {
670		this.conferences.clear();
671		for (Account account : xmppConnectionService.getAccounts()) {
672			if (account.getStatus() != Account.State.DISABLED) {
673				for (Bookmark bookmark : account.getBookmarks()) {
674					if (bookmark.match(needle)) {
675						this.conferences.add(bookmark);
676					}
677				}
678			}
679		}
680		Collections.sort(this.conferences);
681		mConferenceAdapter.notifyDataSetChanged();
682	}
683
684	private void onTabChanged() {
685		invalidateOptionsMenu();
686	}
687
688	public static class MyListFragment extends ListFragment {
689		private AdapterView.OnItemClickListener mOnItemClickListener;
690		private int mResContextMenu;
691
692		public void setContextMenu(int res) {
693			this.mResContextMenu = res;
694		}
695
696		@Override
697		public void onListItemClick(ListView l, View v, int position, long id) {
698			if (mOnItemClickListener != null) {
699				mOnItemClickListener.onItemClick(l, v, position, id);
700			}
701		}
702
703		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
704			this.mOnItemClickListener = l;
705		}
706
707		@Override
708		public void onViewCreated(View view, Bundle savedInstanceState) {
709			super.onViewCreated(view, savedInstanceState);
710			registerForContextMenu(getListView());
711			getListView().setFastScrollEnabled(true);
712		}
713
714		@Override
715		public void onCreateContextMenu(ContextMenu menu, View v,
716										ContextMenuInfo menuInfo) {
717			super.onCreateContextMenu(menu, v, menuInfo);
718			StartConversationActivity activity = (StartConversationActivity) getActivity();
719			activity.getMenuInflater().inflate(mResContextMenu, menu);
720			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
721			if (mResContextMenu == R.menu.conference_context) {
722				activity.conference_context_id = acmi.position;
723			} else {
724				activity.contact_context_id = acmi.position;
725			}
726		}
727
728		@Override
729		public boolean onContextItemSelected(MenuItem item) {
730			StartConversationActivity activity = (StartConversationActivity) getActivity();
731			switch (item.getItemId()) {
732				case R.id.context_start_conversation:
733					activity.openConversationForContact();
734					break;
735				case R.id.context_contact_details:
736					activity.openDetailsForContact();
737					break;
738				case R.id.context_delete_contact:
739					activity.deleteContact();
740					break;
741				case R.id.context_join_conference:
742					activity.openConversationForBookmark();
743					break;
744				case R.id.context_delete_conference:
745					activity.deleteConference();
746			}
747			return true;
748		}
749	}
750
751	private class Invite extends XmppUri {
752
753		public Invite(Uri uri) {
754			super(uri);
755		}
756
757		public Invite(String uri) {
758			super(uri);
759		}
760
761		boolean invite() {
762			if (jid != null) {
763				if (muc) {
764					showJoinConferenceDialog(jid);
765				} else {
766					return handleJid(this);
767				}
768			}
769			return false;
770		}
771	}
772}