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