StartConversationActivity.java

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