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 runOnUiThread(new Runnable() {
180
181 @Override
182 public void run() {
183 if (mSearchEditText != null) {
184 filter(mSearchEditText.getText().toString());
185 }
186 }
187 });
188 }
189
190 @Override
191 public void onCreate(Bundle savedInstanceState) {
192 super.onCreate(savedInstanceState);
193 setContentView(R.layout.activity_start_conversation);
194 mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
195 ActionBar actionBar = getActionBar();
196 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
197
198 mContactsTab = actionBar.newTab().setText(R.string.contacts)
199 .setTabListener(mTabListener);
200 mConferencesTab = actionBar.newTab().setText(R.string.conferences)
201 .setTabListener(mTabListener);
202 actionBar.addTab(mContactsTab);
203 actionBar.addTab(mConferencesTab);
204
205 mViewPager.setOnPageChangeListener(mOnPageChangeListener);
206 mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
207
208 @Override
209 public int getCount() {
210 return 2;
211 }
212
213 @Override
214 public Fragment getItem(int position) {
215 if (position == 0) {
216 return mContactsListFragment;
217 } else {
218 return mConferenceListFragment;
219 }
220 }
221 });
222
223 mConferenceAdapter = new ListItemAdapter(this, conferences);
224 mConferenceListFragment.setListAdapter(mConferenceAdapter);
225 mConferenceListFragment.setContextMenu(R.menu.conference_context);
226 mConferenceListFragment
227 .setOnListItemClickListener(new OnItemClickListener() {
228
229 @Override
230 public void onItemClick(AdapterView<?> arg0, View arg1,
231 int position, long arg3) {
232 openConversationForBookmark(position);
233 }
234 });
235
236 mContactsAdapter = new ListItemAdapter(this, contacts);
237 ((ListItemAdapter) mContactsAdapter).setOnTagClickedListener(this.mOnTagClickedListener);
238 mContactsListFragment.setListAdapter(mContactsAdapter);
239 mContactsListFragment.setContextMenu(R.menu.contact_context);
240 mContactsListFragment
241 .setOnListItemClickListener(new OnItemClickListener() {
242
243 @Override
244 public void onItemClick(AdapterView<?> arg0, View arg1,
245 int position, long arg3) {
246 openConversationForContact(position);
247 }
248 });
249
250 this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false);
251
252 }
253
254 protected void openConversationForContact(int position) {
255 Contact contact = (Contact) contacts.get(position);
256 Conversation conversation = xmppConnectionService
257 .findOrCreateConversation(contact.getAccount(),
258 contact.getJid(), false);
259 switchToConversation(conversation);
260 }
261
262 protected void openConversationForContact() {
263 int position = contact_context_id;
264 openConversationForContact(position);
265 }
266
267 protected void openConversationForBookmark() {
268 openConversationForBookmark(conference_context_id);
269 }
270
271 protected void openConversationForBookmark(int position) {
272 Bookmark bookmark = (Bookmark) conferences.get(position);
273 Conversation conversation = xmppConnectionService
274 .findOrCreateConversation(bookmark.getAccount(),
275 bookmark.getJid(), true);
276 conversation.setBookmark(bookmark);
277 if (!conversation.getMucOptions().online()) {
278 xmppConnectionService.joinMuc(conversation);
279 }
280 if (!bookmark.autojoin()) {
281 bookmark.setAutojoin(true);
282 xmppConnectionService.pushBookmarks(bookmark.getAccount());
283 }
284 switchToConversation(conversation);
285 }
286
287 protected void openDetailsForContact() {
288 int position = contact_context_id;
289 Contact contact = (Contact) contacts.get(position);
290 switchToContactDetails(contact);
291 }
292
293 protected void toggleContactBlock() {
294 final int position = contact_context_id;
295 BlockContactDialog.show(this, xmppConnectionService, (Contact)contacts.get(position));
296 }
297
298 protected void deleteContact() {
299 final int position = contact_context_id;
300 final Contact contact = (Contact) contacts.get(position);
301 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
302 builder.setNegativeButton(R.string.cancel, null);
303 builder.setTitle(R.string.action_delete_contact);
304 builder.setMessage(getString(R.string.remove_contact_text,
305 contact.getJid()));
306 builder.setPositiveButton(R.string.delete, new OnClickListener() {
307
308 @Override
309 public void onClick(DialogInterface dialog, int which) {
310 xmppConnectionService.deleteContactOnServer(contact);
311 filter(mSearchEditText.getText().toString());
312 }
313 });
314 builder.create().show();
315 }
316
317 protected void deleteConference() {
318 int position = conference_context_id;
319 final Bookmark bookmark = (Bookmark) conferences.get(position);
320
321 AlertDialog.Builder builder = new AlertDialog.Builder(this);
322 builder.setNegativeButton(R.string.cancel, null);
323 builder.setTitle(R.string.delete_bookmark);
324 builder.setMessage(getString(R.string.remove_bookmark_text,
325 bookmark.getJid()));
326 builder.setPositiveButton(R.string.delete, new OnClickListener() {
327
328 @Override
329 public void onClick(DialogInterface dialog, int which) {
330 bookmark.unregisterConversation();
331 Account account = bookmark.getAccount();
332 account.getBookmarks().remove(bookmark);
333 xmppConnectionService.pushBookmarks(account);
334 filter(mSearchEditText.getText().toString());
335 }
336 });
337 builder.create().show();
338
339 }
340
341 @SuppressLint("InflateParams")
342 protected void showCreateContactDialog(final String prefilledJid, final String fingerprint) {
343 AlertDialog.Builder builder = new AlertDialog.Builder(this);
344 builder.setTitle(R.string.create_contact);
345 View dialogView = getLayoutInflater().inflate(R.layout.create_contact_dialog, null);
346 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
347 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
348 jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownHosts));
349 if (prefilledJid != null) {
350 jid.append(prefilledJid);
351 if (fingerprint!=null) {
352 jid.setFocusable(false);
353 jid.setFocusableInTouchMode(false);
354 jid.setClickable(false);
355 jid.setCursorVisible(false);
356 }
357 }
358 populateAccountSpinner(spinner);
359 builder.setView(dialogView);
360 builder.setNegativeButton(R.string.cancel, null);
361 builder.setPositiveButton(R.string.create, null);
362 final AlertDialog dialog = builder.create();
363 dialog.show();
364 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
365 new View.OnClickListener() {
366
367 @Override
368 public void onClick(final View v) {
369 if (!xmppConnectionServiceBound) {
370 return;
371 }
372 final Jid accountJid;
373 try {
374 accountJid = Jid.fromString((String) spinner.getSelectedItem());
375 } catch (final InvalidJidException e) {
376 return;
377 }
378 final Jid contactJid;
379 try {
380 contactJid = Jid.fromString(jid.getText().toString());
381 } catch (final InvalidJidException e) {
382 jid.setError(getString(R.string.invalid_jid));
383 return;
384 }
385 final Account account = xmppConnectionService
386 .findAccountByJid(accountJid);
387 if (account == null) {
388 dialog.dismiss();
389 return;
390 }
391 final Contact contact = account.getRoster().getContact(contactJid);
392 if (contact.showInRoster()) {
393 jid.setError(getString(R.string.contact_already_exists));
394 } else {
395 contact.addOtrFingerprint(fingerprint);
396 xmppConnectionService.createContact(contact);
397 dialog.dismiss();
398 switchToConversation(contact);
399 }
400 }
401 });
402
403 }
404
405 @SuppressLint("InflateParams")
406 protected void showJoinConferenceDialog(final String prefilledJid) {
407 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
408 builder.setTitle(R.string.join_conference);
409 final View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null);
410 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
411 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
412 jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownConferenceHosts));
413 if (prefilledJid != null) {
414 jid.append(prefilledJid);
415 }
416 populateAccountSpinner(spinner);
417 final Checkable bookmarkCheckBox = (CheckBox) dialogView
418 .findViewById(R.id.bookmark);
419 builder.setView(dialogView);
420 builder.setNegativeButton(R.string.cancel, null);
421 builder.setPositiveButton(R.string.join, null);
422 final AlertDialog dialog = builder.create();
423 dialog.show();
424 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
425 new View.OnClickListener() {
426
427 @Override
428 public void onClick(final View v) {
429 if (!xmppConnectionServiceBound) {
430 return;
431 }
432 final Jid accountJid;
433 try {
434 accountJid = Jid.fromString((String) spinner.getSelectedItem());
435 } catch (final InvalidJidException e) {
436 return;
437 }
438 final Jid conferenceJid;
439 try {
440 conferenceJid = Jid.fromString(jid.getText().toString());
441 } catch (final InvalidJidException e) {
442 jid.setError(getString(R.string.invalid_jid));
443 return;
444 }
445 final Account account = xmppConnectionService
446 .findAccountByJid(accountJid);
447 if (account == null) {
448 dialog.dismiss();
449 return;
450 }
451 if (bookmarkCheckBox.isChecked()) {
452 if (account.hasBookmarkFor(conferenceJid)) {
453 jid.setError(getString(R.string.bookmark_already_exists));
454 } else {
455 final Bookmark bookmark = new Bookmark(account,conferenceJid.toBareJid());
456 bookmark.setAutojoin(true);
457 account.getBookmarks().add(bookmark);
458 xmppConnectionService
459 .pushBookmarks(account);
460 final Conversation conversation = xmppConnectionService
461 .findOrCreateConversation(account,
462 conferenceJid, true);
463 conversation.setBookmark(bookmark);
464 if (!conversation.getMucOptions().online()) {
465 xmppConnectionService
466 .joinMuc(conversation);
467 }
468 dialog.dismiss();
469 switchToConversation(conversation);
470 }
471 } else {
472 final Conversation conversation = xmppConnectionService
473 .findOrCreateConversation(account,
474 conferenceJid, true);
475 if (!conversation.getMucOptions().online()) {
476 xmppConnectionService.joinMuc(conversation);
477 }
478 dialog.dismiss();
479 switchToConversation(conversation);
480 }
481 }
482 });
483 }
484
485 protected void switchToConversation(Contact contact) {
486 Conversation conversation = xmppConnectionService
487 .findOrCreateConversation(contact.getAccount(),
488 contact.getJid(), false);
489 switchToConversation(conversation);
490 }
491
492 private void populateAccountSpinner(Spinner spinner) {
493 ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
494 android.R.layout.simple_spinner_item, mActivatedAccounts);
495 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
496 spinner.setAdapter(adapter);
497 }
498
499 @Override
500 public boolean onCreateOptionsMenu(Menu menu) {
501 this.mOptionsMenu = menu;
502 getMenuInflater().inflate(R.menu.start_conversation, menu);
503 MenuItem menuCreateContact = menu.findItem(R.id.action_create_contact);
504 MenuItem menuCreateConference = menu.findItem(R.id.action_join_conference);
505 MenuItem menuHideOffline = menu.findItem(R.id.action_hide_offline);
506 menuHideOffline.setChecked(this.mHideOfflineContacts);
507 mMenuSearchView = menu.findItem(R.id.action_search);
508 mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
509 View mSearchView = mMenuSearchView.getActionView();
510 mSearchEditText = (EditText) mSearchView
511 .findViewById(R.id.search_field);
512 mSearchEditText.addTextChangedListener(mSearchTextWatcher);
513 if (getActionBar().getSelectedNavigationIndex() == 0) {
514 menuCreateConference.setVisible(false);
515 } else {
516 menuCreateContact.setVisible(false);
517 }
518 if (mInitialJid != null) {
519 mMenuSearchView.expandActionView();
520 mSearchEditText.append(mInitialJid);
521 filter(mInitialJid);
522 }
523 return true;
524 }
525
526 @Override
527 public boolean onOptionsItemSelected(MenuItem item) {
528 switch (item.getItemId()) {
529 case R.id.action_create_contact:
530 showCreateContactDialog(null,null);
531 return true;
532 case R.id.action_join_conference:
533 showJoinConferenceDialog(null);
534 return true;
535 case R.id.action_scan_qr_code:
536 new IntentIntegrator(this).initiateScan();
537 return true;
538 case R.id.action_hide_offline:
539 mHideOfflineContacts = !item.isChecked();
540 getPreferences().edit().putBoolean("hide_offline", mHideOfflineContacts).commit();
541 if (mSearchEditText != null) {
542 filter(mSearchEditText.getText().toString());
543 }
544 invalidateOptionsMenu();
545 }
546 return super.onOptionsItemSelected(item);
547 }
548
549 @Override
550 public boolean onKeyUp(int keyCode, KeyEvent event) {
551 if (keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress()) {
552 mOptionsMenu.findItem(R.id.action_search).expandActionView();
553 return true;
554 }
555 return super.onKeyUp(keyCode, event);
556 }
557
558 @Override
559 public void onActivityResult(int requestCode, int resultCode, Intent intent) {
560 if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
561 IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
562 if (scanResult != null && scanResult.getFormatName() != null) {
563 String data = scanResult.getContents();
564 Invite invite = new Invite(data);
565 if (xmppConnectionServiceBound) {
566 invite.invite();
567 } else if (invite.getJid() != null) {
568 this.mPendingInvite = invite;
569 } else {
570 this.mPendingInvite = null;
571 }
572 }
573 }
574 super.onActivityResult(requestCode, requestCode, intent);
575 }
576
577 @Override
578 protected void onBackendConnected() {
579 this.mActivatedAccounts.clear();
580 for (Account account : xmppConnectionService.getAccounts()) {
581 if (account.getStatus() != Account.State.DISABLED) {
582 this.mActivatedAccounts.add(account.getJid().toBareJid().toString());
583 }
584 }
585 this.mKnownHosts = xmppConnectionService.getKnownHosts();
586 this.mKnownConferenceHosts = xmppConnectionService
587 .getKnownConferenceHosts();
588 if (this.mPendingInvite != null) {
589 mPendingInvite.invite();
590 this.mPendingInvite = null;
591 } else if (!handleIntent(getIntent())) {
592 if (mSearchEditText != null) {
593 filter(mSearchEditText.getText().toString());
594 } else {
595 filter(null);
596 }
597 }
598 setIntent(null);
599 }
600
601 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
602 Invite getInviteJellyBean(NdefRecord record) {
603 return new Invite(record.toUri());
604 }
605
606 protected boolean handleIntent(Intent intent) {
607 if (intent == null || intent.getAction() == null) {
608 return false;
609 }
610 switch (intent.getAction()) {
611 case Intent.ACTION_SENDTO:
612 case Intent.ACTION_VIEW:
613 Log.d(Config.LOGTAG, "received uri=" + intent.getData());
614 return new Invite(intent.getData()).invite();
615 case NfcAdapter.ACTION_NDEF_DISCOVERED:
616 for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) {
617 if (message instanceof NdefMessage) {
618 Log.d(Config.LOGTAG, "received message=" + message);
619 for (NdefRecord record : ((NdefMessage) message).getRecords()) {
620 switch (record.getTnf()) {
621 case NdefRecord.TNF_WELL_KNOWN:
622 if (Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
623 if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
624 return getInviteJellyBean(record).invite();
625 } else {
626 byte[] payload = record.getPayload();
627 if (payload[0] == 0) {
628 return new Invite(Uri.parse(new String(Arrays.copyOfRange(
629 payload, 1, payload.length)))).invite();
630 }
631 }
632 }
633 }
634 }
635 }
636 }
637 }
638 return false;
639 }
640
641 private boolean handleJid(Invite invite) {
642 List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid());
643 if (contacts.size() == 0) {
644 showCreateContactDialog(invite.getJid().toString(),invite.getFingerprint());
645 return false;
646 } else if (contacts.size() == 1) {
647 Contact contact = contacts.get(0);
648 if (invite.getFingerprint() != null) {
649 if (contact.addOtrFingerprint(invite.getFingerprint())) {
650 Log.d(Config.LOGTAG,"added new fingerprint");
651 xmppConnectionService.syncRosterToDisk(contact.getAccount());
652 }
653 }
654 switchToConversation(contact);
655 return true;
656 } else {
657 if (mMenuSearchView != null) {
658 mMenuSearchView.expandActionView();
659 mSearchEditText.setText("");
660 mSearchEditText.append(invite.getJid().toString());
661 filter(invite.getJid().toString());
662 } else {
663 mInitialJid = invite.getJid().toString();
664 }
665 return true;
666 }
667 }
668
669 protected void filter(String needle) {
670 if (xmppConnectionServiceBound) {
671 this.filterContacts(needle);
672 this.filterConferences(needle);
673 }
674 }
675
676 protected void filterContacts(String needle) {
677 this.contacts.clear();
678 for (Account account : xmppConnectionService.getAccounts()) {
679 if (account.getStatus() != Account.State.DISABLED) {
680 for (Contact contact : account.getRoster().getContacts()) {
681 if (contact.showInRoster() && contact.match(needle)
682 && (!this.mHideOfflineContacts
683 || contact.getPresences().getMostAvailableStatus() < Presences.OFFLINE)) {
684 this.contacts.add(contact);
685 }
686 }
687 }
688 }
689 Collections.sort(this.contacts);
690 mContactsAdapter.notifyDataSetChanged();
691 }
692
693 protected void filterConferences(String needle) {
694 this.conferences.clear();
695 for (Account account : xmppConnectionService.getAccounts()) {
696 if (account.getStatus() != Account.State.DISABLED) {
697 for (Bookmark bookmark : account.getBookmarks()) {
698 if (bookmark.match(needle)) {
699 this.conferences.add(bookmark);
700 }
701 }
702 }
703 }
704 Collections.sort(this.conferences);
705 mConferenceAdapter.notifyDataSetChanged();
706 }
707
708 private void onTabChanged() {
709 invalidateOptionsMenu();
710 }
711
712 @Override
713 public void OnUpdateBlocklist(final Status status) {
714 runOnUiThread(new Runnable() {
715
716 @Override
717 public void run() {
718 if (mSearchEditText != null) {
719 filter(mSearchEditText.getText().toString());
720 }
721 }
722 });
723 }
724
725 public static class MyListFragment extends ListFragment {
726 private AdapterView.OnItemClickListener mOnItemClickListener;
727 private int mResContextMenu;
728
729 public void setContextMenu(final int res) {
730 this.mResContextMenu = res;
731 }
732
733 @Override
734 public void onListItemClick(final ListView l, final View v, final int position, final long id) {
735 if (mOnItemClickListener != null) {
736 mOnItemClickListener.onItemClick(l, v, position, id);
737 }
738 }
739
740 public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
741 this.mOnItemClickListener = l;
742 }
743
744 @Override
745 public void onViewCreated(final View view, final Bundle savedInstanceState) {
746 super.onViewCreated(view, savedInstanceState);
747 registerForContextMenu(getListView());
748 getListView().setFastScrollEnabled(true);
749 }
750
751 @Override
752 public void onCreateContextMenu(final ContextMenu menu, final View v,
753 final ContextMenuInfo menuInfo) {
754 super.onCreateContextMenu(menu, v, menuInfo);
755 final StartConversationActivity activity = (StartConversationActivity) getActivity();
756 activity.getMenuInflater().inflate(mResContextMenu, menu);
757 final AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
758 if (mResContextMenu == R.menu.conference_context) {
759 activity.conference_context_id = acmi.position;
760 } else {
761 activity.contact_context_id = acmi.position;
762 final Blockable contact = (Contact) activity.contacts.get(acmi.position);
763
764 final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock);
765 if (blockUnblockItem != null) {
766 if (contact.isBlocked()) {
767 blockUnblockItem.setTitle(R.string.unblock_contact);
768 } else {
769 blockUnblockItem.setTitle(R.string.block_contact);
770 }
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}