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.Checkable;
 42import android.widget.EditText;
 43import android.widget.ListView;
 44import android.widget.Spinner;
 45
 46import com.google.zxing.integration.android.IntentIntegrator;
 47import com.google.zxing.integration.android.IntentResult;
 48
 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.Blockable;
 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.entities.Presences;
 63import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 64import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 65import eu.siacs.conversations.ui.adapter.ListItemAdapter;
 66import eu.siacs.conversations.utils.XmppUri;
 67import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
 68import eu.siacs.conversations.xmpp.XmppConnection;
 69import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 70import eu.siacs.conversations.xmpp.jid.Jid;
 71
 72public class StartConversationActivity extends XmppActivity implements OnRosterUpdate, OnUpdateBlocklist {
 73
 74	public int conference_context_id;
 75	public int contact_context_id;
 76	private Tab mContactsTab;
 77	private Tab mConferencesTab;
 78	private ViewPager mViewPager;
 79	private MyListFragment mContactsListFragment = new MyListFragment();
 80	private List<ListItem> contacts = new ArrayList<>();
 81	private ArrayAdapter<ListItem> mContactsAdapter;
 82	private MyListFragment mConferenceListFragment = new MyListFragment();
 83	private List<ListItem> conferences = new ArrayList<ListItem>();
 84	private ArrayAdapter<ListItem> mConferenceAdapter;
 85	private List<String> mActivatedAccounts = new ArrayList<String>();
 86	private List<String> mKnownHosts;
 87	private List<String> mKnownConferenceHosts;
 88	private Invite mPendingInvite = null;
 89	private Menu mOptionsMenu;
 90	private EditText mSearchEditText;
 91	private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
 92
 93		@Override
 94		public boolean onMenuItemActionExpand(MenuItem item) {
 95			mSearchEditText.post(new Runnable() {
 96
 97				@Override
 98				public void run() {
 99					mSearchEditText.requestFocus();
100					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
101					imm.showSoftInput(mSearchEditText,
102							InputMethodManager.SHOW_IMPLICIT);
103				}
104			});
105
106			return true;
107		}
108
109		@Override
110		public boolean onMenuItemActionCollapse(MenuItem item) {
111			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
112			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
113					InputMethodManager.HIDE_IMPLICIT_ONLY);
114			mSearchEditText.setText("");
115			filter(null);
116			return true;
117		}
118	};
119	private boolean mHideOfflineContacts = false;
120	private TabListener mTabListener = new TabListener() {
121
122		@Override
123		public void onTabUnselected(Tab tab, FragmentTransaction ft) {
124			return;
125		}
126
127		@Override
128		public void onTabSelected(Tab tab, FragmentTransaction ft) {
129			mViewPager.setCurrentItem(tab.getPosition());
130			onTabChanged();
131		}
132
133		@Override
134		public void onTabReselected(Tab tab, FragmentTransaction ft) {
135			return;
136		}
137	};
138	private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
139		@Override
140		public void onPageSelected(int position) {
141			if (getActionBar() != null) {
142				getActionBar().setSelectedNavigationItem(position);
143			}
144			onTabChanged();
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 MenuItem mMenuSearchView;
165	private ListItemAdapter.OnTagClickedListener mOnTagClickedListener = new ListItemAdapter.OnTagClickedListener() {
166		@Override
167		public void onTagClicked(String tag) {
168			if (mMenuSearchView != null) {
169				mMenuSearchView.expandActionView();
170				mSearchEditText.setText("");
171				mSearchEditText.append(tag);
172				filter(tag);
173			}
174		}
175	};
176	private String mInitialJid;
177
178	@Override
179	public void onRosterUpdate() {
180		this.refreshUi();
181	}
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		((ListItemAdapter) mContactsAdapter).setOnTagClickedListener(this.mOnTagClickedListener);
231		mContactsListFragment.setListAdapter(mContactsAdapter);
232		mContactsListFragment.setContextMenu(R.menu.contact_context);
233		mContactsListFragment
234			.setOnListItemClickListener(new OnItemClickListener() {
235
236				@Override
237				public void onItemClick(AdapterView<?> arg0, View arg1,
238						int position, long arg3) {
239					openConversationForContact(position);
240				}
241			});
242
243		this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false);
244
245	}
246
247	protected void openConversationForContact(int position) {
248		Contact contact = (Contact) contacts.get(position);
249		Conversation conversation = xmppConnectionService
250			.findOrCreateConversation(contact.getAccount(),
251					contact.getJid(), false);
252		switchToConversation(conversation);
253	}
254
255	protected void openConversationForContact() {
256		int position = contact_context_id;
257		openConversationForContact(position);
258	}
259
260	protected void openConversationForBookmark() {
261		openConversationForBookmark(conference_context_id);
262	}
263
264	protected void openConversationForBookmark(int position) {
265		Bookmark bookmark = (Bookmark) conferences.get(position);
266		Conversation conversation = xmppConnectionService
267			.findOrCreateConversation(bookmark.getAccount(),
268					bookmark.getJid(), true);
269		conversation.setBookmark(bookmark);
270		if (!conversation.getMucOptions().online()) {
271			xmppConnectionService.joinMuc(conversation);
272		}
273		if (!bookmark.autojoin()) {
274			bookmark.setAutojoin(true);
275			xmppConnectionService.pushBookmarks(bookmark.getAccount());
276		}
277		switchToConversation(conversation);
278	}
279
280	protected void openDetailsForContact() {
281		int position = contact_context_id;
282		Contact contact = (Contact) contacts.get(position);
283		switchToContactDetails(contact);
284	}
285
286	protected void toggleContactBlock() {
287		final int position = contact_context_id;
288		BlockContactDialog.show(this, xmppConnectionService, (Contact)contacts.get(position));
289	}
290
291	protected void deleteContact() {
292		final int position = contact_context_id;
293		final Contact contact = (Contact) contacts.get(position);
294		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
295		builder.setNegativeButton(R.string.cancel, null);
296		builder.setTitle(R.string.action_delete_contact);
297		builder.setMessage(getString(R.string.remove_contact_text,
298					contact.getJid()));
299		builder.setPositiveButton(R.string.delete, new OnClickListener() {
300
301			@Override
302			public void onClick(DialogInterface dialog, int which) {
303				xmppConnectionService.deleteContactOnServer(contact);
304				filter(mSearchEditText.getText().toString());
305			}
306		});
307		builder.create().show();
308	}
309
310	protected void deleteConference() {
311		int position = conference_context_id;
312		final Bookmark bookmark = (Bookmark) conferences.get(position);
313
314		AlertDialog.Builder builder = new AlertDialog.Builder(this);
315		builder.setNegativeButton(R.string.cancel, null);
316		builder.setTitle(R.string.delete_bookmark);
317		builder.setMessage(getString(R.string.remove_bookmark_text,
318					bookmark.getJid()));
319		builder.setPositiveButton(R.string.delete, new OnClickListener() {
320
321			@Override
322			public void onClick(DialogInterface dialog, int which) {
323				bookmark.unregisterConversation();
324				Account account = bookmark.getAccount();
325				account.getBookmarks().remove(bookmark);
326				xmppConnectionService.pushBookmarks(account);
327				filter(mSearchEditText.getText().toString());
328			}
329		});
330		builder.create().show();
331
332	}
333
334	@SuppressLint("InflateParams")
335	protected void showCreateContactDialog(final String prefilledJid, final String fingerprint) {
336		AlertDialog.Builder builder = new AlertDialog.Builder(this);
337		builder.setTitle(R.string.create_contact);
338		View dialogView = getLayoutInflater().inflate(R.layout.create_contact_dialog, null);
339		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
340		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
341		jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownHosts));
342		if (prefilledJid != null) {
343			jid.append(prefilledJid);
344			if (fingerprint!=null) {
345				jid.setFocusable(false);
346				jid.setFocusableInTouchMode(false);
347				jid.setClickable(false);
348				jid.setCursorVisible(false);
349			}
350		}
351		populateAccountSpinner(spinner);
352		builder.setView(dialogView);
353		builder.setNegativeButton(R.string.cancel, null);
354		builder.setPositiveButton(R.string.create, null);
355		final AlertDialog dialog = builder.create();
356		dialog.show();
357		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
358				new View.OnClickListener() {
359
360					@Override
361					public void onClick(final View v) {
362						if (!xmppConnectionServiceBound) {
363							return;
364						}
365						final Jid accountJid;
366						try {
367							accountJid = Jid.fromString((String) spinner.getSelectedItem());
368						} catch (final InvalidJidException e) {
369							return;
370						}
371						final Jid contactJid;
372						try {
373							contactJid = Jid.fromString(jid.getText().toString());
374						} catch (final InvalidJidException e) {
375							jid.setError(getString(R.string.invalid_jid));
376							return;
377						}
378						final Account account = xmppConnectionService
379							.findAccountByJid(accountJid);
380						if (account == null) {
381							dialog.dismiss();
382							return;
383						}
384						final Contact contact = account.getRoster().getContact(contactJid);
385						if (contact.showInRoster()) {
386							jid.setError(getString(R.string.contact_already_exists));
387						} else {
388							contact.addOtrFingerprint(fingerprint);
389							xmppConnectionService.createContact(contact);
390							dialog.dismiss();
391							switchToConversation(contact);
392						}
393					}
394				});
395
396	}
397
398	@SuppressLint("InflateParams")
399	protected void showJoinConferenceDialog(final String prefilledJid) {
400		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
401		builder.setTitle(R.string.join_conference);
402		final View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null);
403		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
404		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
405		jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownConferenceHosts));
406		if (prefilledJid != null) {
407			jid.append(prefilledJid);
408		}
409		populateAccountSpinner(spinner);
410		final Checkable bookmarkCheckBox = (CheckBox) dialogView
411			.findViewById(R.id.bookmark);
412		builder.setView(dialogView);
413		builder.setNegativeButton(R.string.cancel, null);
414		builder.setPositiveButton(R.string.join, null);
415		final AlertDialog dialog = builder.create();
416		dialog.show();
417		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
418				new View.OnClickListener() {
419
420					@Override
421					public void onClick(final View v) {
422						if (!xmppConnectionServiceBound) {
423							return;
424						}
425						final Jid accountJid;
426						try {
427							accountJid = Jid.fromString((String) spinner.getSelectedItem());
428						} catch (final InvalidJidException e) {
429							return;
430						}
431						final Jid conferenceJid;
432						try {
433							conferenceJid = Jid.fromString(jid.getText().toString());
434						} catch (final InvalidJidException e) {
435							jid.setError(getString(R.string.invalid_jid));
436							return;
437						}
438						final Account account = xmppConnectionService
439							.findAccountByJid(accountJid);
440						if (account == null) {
441							dialog.dismiss();
442							return;
443						}
444						if (bookmarkCheckBox.isChecked()) {
445							if (account.hasBookmarkFor(conferenceJid)) {
446								jid.setError(getString(R.string.bookmark_already_exists));
447							} else {
448								final Bookmark bookmark = new Bookmark(account,conferenceJid.toBareJid());
449								bookmark.setAutojoin(true);
450								account.getBookmarks().add(bookmark);
451								xmppConnectionService
452									.pushBookmarks(account);
453								final Conversation conversation = xmppConnectionService
454									.findOrCreateConversation(account,
455											conferenceJid, true);
456								conversation.setBookmark(bookmark);
457								if (!conversation.getMucOptions().online()) {
458									xmppConnectionService
459										.joinMuc(conversation);
460								}
461								dialog.dismiss();
462								switchToConversation(conversation);
463							}
464						} else {
465							final Conversation conversation = xmppConnectionService
466								.findOrCreateConversation(account,
467										conferenceJid, true);
468							if (!conversation.getMucOptions().online()) {
469								xmppConnectionService.joinMuc(conversation);
470							}
471							dialog.dismiss();
472							switchToConversation(conversation);
473						}
474					}
475				});
476	}
477
478	protected void switchToConversation(Contact contact) {
479		Conversation conversation = xmppConnectionService
480			.findOrCreateConversation(contact.getAccount(),
481					contact.getJid(), false);
482		switchToConversation(conversation);
483	}
484
485	private void populateAccountSpinner(Spinner spinner) {
486		ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
487				android.R.layout.simple_spinner_item, mActivatedAccounts);
488		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
489		spinner.setAdapter(adapter);
490	}
491
492	@Override
493	public boolean onCreateOptionsMenu(Menu menu) {
494		this.mOptionsMenu = menu;
495		getMenuInflater().inflate(R.menu.start_conversation, menu);
496		MenuItem menuCreateContact = menu.findItem(R.id.action_create_contact);
497		MenuItem menuCreateConference = menu.findItem(R.id.action_join_conference);
498		MenuItem menuHideOffline = menu.findItem(R.id.action_hide_offline);
499		menuHideOffline.setChecked(this.mHideOfflineContacts);
500		mMenuSearchView = menu.findItem(R.id.action_search);
501		mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
502		View mSearchView = mMenuSearchView.getActionView();
503		mSearchEditText = (EditText) mSearchView
504			.findViewById(R.id.search_field);
505		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
506		if (getActionBar().getSelectedNavigationIndex() == 0) {
507			menuCreateConference.setVisible(false);
508		} else {
509			menuCreateContact.setVisible(false);
510		}
511		if (mInitialJid != null) {
512			mMenuSearchView.expandActionView();
513			mSearchEditText.append(mInitialJid);
514			filter(mInitialJid);
515		}
516		return true;
517	}
518
519	@Override
520	public boolean onOptionsItemSelected(MenuItem item) {
521		switch (item.getItemId()) {
522			case R.id.action_create_contact:
523				showCreateContactDialog(null,null);
524				return true;
525			case R.id.action_join_conference:
526				showJoinConferenceDialog(null);
527				return true;
528			case R.id.action_scan_qr_code:
529				new IntentIntegrator(this).initiateScan();
530				return true;
531			case R.id.action_hide_offline:
532				mHideOfflineContacts = !item.isChecked();
533				getPreferences().edit().putBoolean("hide_offline", mHideOfflineContacts).commit();
534				if (mSearchEditText != null) {
535					filter(mSearchEditText.getText().toString());
536				}
537				invalidateOptionsMenu();
538		}
539		return super.onOptionsItemSelected(item);
540	}
541
542	@Override
543	public boolean onKeyUp(int keyCode, KeyEvent event) {
544		if (keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress()) {
545			mOptionsMenu.findItem(R.id.action_search).expandActionView();
546			return true;
547		}
548		return super.onKeyUp(keyCode, event);
549	}
550
551	@Override
552	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
553		if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
554			IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
555			if (scanResult != null && scanResult.getFormatName() != null) {
556				String data = scanResult.getContents();
557				Invite invite = new Invite(data);
558				if (xmppConnectionServiceBound) {
559					invite.invite();
560				} else if (invite.getJid() != null) {
561					this.mPendingInvite = invite;
562				} else {
563					this.mPendingInvite = null;
564				}
565			}
566		}
567		super.onActivityResult(requestCode, requestCode, intent);
568	}
569
570	@Override
571	protected void onBackendConnected() {
572		this.mActivatedAccounts.clear();
573		for (Account account : xmppConnectionService.getAccounts()) {
574			if (account.getStatus() != Account.State.DISABLED) {
575				this.mActivatedAccounts.add(account.getJid().toBareJid().toString());
576			}
577		}
578		final Intent intent = getIntent();
579		final ActionBar ab = getActionBar();
580		if (intent != null && intent.getBooleanExtra("init",false) && ab != null) {
581			ab.setDisplayShowHomeEnabled(false);
582			ab.setDisplayHomeAsUpEnabled(false);
583			ab.setHomeButtonEnabled(false);
584		}
585		this.mKnownHosts = xmppConnectionService.getKnownHosts();
586		this.mKnownConferenceHosts = xmppConnectionService.getKnownConferenceHosts();
587		if (this.mPendingInvite != null) {
588			mPendingInvite.invite();
589			this.mPendingInvite = null;
590		} else if (!handleIntent(getIntent())) {
591			if (mSearchEditText != null) {
592				filter(mSearchEditText.getText().toString());
593			} else {
594				filter(null);
595			}
596		}
597		setIntent(null);
598	}
599
600	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
601	Invite getInviteJellyBean(NdefRecord record) {
602		return new Invite(record.toUri());
603	}
604
605	protected boolean handleIntent(Intent intent) {
606		if (intent == null || intent.getAction() == null) {
607			return false;
608		}
609		switch (intent.getAction()) {
610			case Intent.ACTION_SENDTO:
611			case Intent.ACTION_VIEW:
612				Log.d(Config.LOGTAG, "received uri=" + intent.getData());
613				return new Invite(intent.getData()).invite();
614			case NfcAdapter.ACTION_NDEF_DISCOVERED:
615				for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) {
616					if (message instanceof NdefMessage) {
617						Log.d(Config.LOGTAG, "received message=" + message);
618						for (NdefRecord record : ((NdefMessage) message).getRecords()) {
619							switch (record.getTnf()) {
620								case NdefRecord.TNF_WELL_KNOWN:
621									if (Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
622										if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
623											return getInviteJellyBean(record).invite();
624										} else {
625											byte[] payload = record.getPayload();
626											if (payload[0] == 0) {
627												return new Invite(Uri.parse(new String(Arrays.copyOfRange(
628																	payload, 1, payload.length)))).invite();
629											}
630										}
631									}
632							}
633						}
634					}
635				}
636		}
637		return false;
638	}
639
640	private boolean handleJid(Invite invite) {
641		List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid());
642		if (contacts.size() == 0) {
643			showCreateContactDialog(invite.getJid().toString(),invite.getFingerprint());
644			return false;
645		} else if (contacts.size() == 1) {
646			Contact contact = contacts.get(0);
647			if (invite.getFingerprint() != null) {
648				if (contact.addOtrFingerprint(invite.getFingerprint())) {
649					Log.d(Config.LOGTAG,"added new fingerprint");
650					xmppConnectionService.syncRosterToDisk(contact.getAccount());
651				}
652			}
653			switchToConversation(contact);
654			return true;
655		} else {
656			if (mMenuSearchView != null) {
657				mMenuSearchView.expandActionView();
658				mSearchEditText.setText("");
659				mSearchEditText.append(invite.getJid().toString());
660				filter(invite.getJid().toString());
661			} else {
662				mInitialJid = invite.getJid().toString();
663			}
664			return true;
665		}
666	}
667
668	protected void filter(String needle) {
669		if (xmppConnectionServiceBound) {
670			this.filterContacts(needle);
671			this.filterConferences(needle);
672		}
673	}
674
675	protected void filterContacts(String needle) {
676		this.contacts.clear();
677		for (Account account : xmppConnectionService.getAccounts()) {
678			if (account.getStatus() != Account.State.DISABLED) {
679				for (Contact contact : account.getRoster().getContacts()) {
680					if (contact.showInRoster() && contact.match(needle)
681							&& (!this.mHideOfflineContacts
682							|| contact.getPresences().getMostAvailableStatus() < Presences.OFFLINE)) {
683						this.contacts.add(contact);
684					}
685				}
686			}
687		}
688		Collections.sort(this.contacts);
689		mContactsAdapter.notifyDataSetChanged();
690	}
691
692	protected void filterConferences(String needle) {
693		this.conferences.clear();
694		for (Account account : xmppConnectionService.getAccounts()) {
695			if (account.getStatus() != Account.State.DISABLED) {
696				for (Bookmark bookmark : account.getBookmarks()) {
697					if (bookmark.match(needle)) {
698						this.conferences.add(bookmark);
699					}
700				}
701			}
702		}
703		Collections.sort(this.conferences);
704		mConferenceAdapter.notifyDataSetChanged();
705	}
706
707	private void onTabChanged() {
708		invalidateOptionsMenu();
709	}
710
711	@Override
712	public void OnUpdateBlocklist(final Status status) {
713		refreshUi();
714	}
715
716	@Override
717	protected void refreshUiReal() {
718		if (mSearchEditText != null) {
719			filter(mSearchEditText.getText().toString());
720		}
721	}
722
723	public static class MyListFragment extends ListFragment {
724		private AdapterView.OnItemClickListener mOnItemClickListener;
725		private int mResContextMenu;
726
727		public void setContextMenu(final int res) {
728			this.mResContextMenu = res;
729		}
730
731		@Override
732		public void onListItemClick(final ListView l, final View v, final int position, final long id) {
733			if (mOnItemClickListener != null) {
734				mOnItemClickListener.onItemClick(l, v, position, id);
735			}
736		}
737
738		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
739			this.mOnItemClickListener = l;
740		}
741
742		@Override
743		public void onViewCreated(final View view, final Bundle savedInstanceState) {
744			super.onViewCreated(view, savedInstanceState);
745			registerForContextMenu(getListView());
746			getListView().setFastScrollEnabled(true);
747		}
748
749		@Override
750		public void onCreateContextMenu(final ContextMenu menu, final View v,
751				final ContextMenuInfo menuInfo) {
752			super.onCreateContextMenu(menu, v, menuInfo);
753			final StartConversationActivity activity = (StartConversationActivity) getActivity();
754			activity.getMenuInflater().inflate(mResContextMenu, menu);
755			final AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
756			if (mResContextMenu == R.menu.conference_context) {
757				activity.conference_context_id = acmi.position;
758			} else {
759				activity.contact_context_id = acmi.position;
760				final Blockable contact = (Contact) activity.contacts.get(acmi.position);
761				final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock);
762				XmppConnection xmpp = contact.getAccount().getXmppConnection();
763				if (xmpp != null && xmpp.getFeatures().blocking()) {
764					if (contact.isBlocked()) {
765						blockUnblockItem.setTitle(R.string.unblock_contact);
766					} else {
767						blockUnblockItem.setTitle(R.string.block_contact);
768					}
769				} else {
770					blockUnblockItem.setVisible(false);
771				}
772			}
773		}
774
775		@Override
776		public boolean onContextItemSelected(final MenuItem item) {
777			StartConversationActivity activity = (StartConversationActivity) getActivity();
778			switch (item.getItemId()) {
779				case R.id.context_start_conversation:
780					activity.openConversationForContact();
781					break;
782				case R.id.context_contact_details:
783					activity.openDetailsForContact();
784					break;
785				case R.id.context_contact_block_unblock:
786					activity.toggleContactBlock();
787					break;
788				case R.id.context_delete_contact:
789					activity.deleteContact();
790					break;
791				case R.id.context_join_conference:
792					activity.openConversationForBookmark();
793					break;
794				case R.id.context_delete_conference:
795					activity.deleteConference();
796			}
797			return true;
798		}
799	}
800
801	private class Invite extends XmppUri {
802
803		public Invite(final Uri uri) {
804			super(uri);
805		}
806
807		public Invite(final String uri) {
808			super(uri);
809		}
810
811		boolean invite() {
812			if (jid != null) {
813				if (muc) {
814					showJoinConferenceDialog(jid);
815				} else {
816					return handleJid(this);
817				}
818			}
819			return false;
820		}
821	}
822}