bring scan button to StartConversationActivity

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java      |   12 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java | 2120 
src/main/res/menu/start_conversation.xml                               |    3 
3 files changed, 1,076 insertions(+), 1,059 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -1746,8 +1746,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
 	}
 
 	private boolean scrolledToBottom() {
-		final ListView l = this.binding.messagesView;
-		return l.getLastVisiblePosition() == l.getAdapter().getCount() -1 && l.getChildAt(l.getChildCount() - 1).getBottom() <= l.getHeight();
+		if (this.binding == null) {
+			return false;
+		}
+		final ListView listView = this.binding.messagesView;
+		if (listView.getLastVisiblePosition() == listView.getAdapter().getCount() -1) {
+			final View lastChild = listView.getChildAt(listView.getChildCount() -1);
+			return lastChild != null && lastChild.getBottom() <= listView.getHeight();
+		} else {
+			return false;
+		}
 	}
 
 	private void processExtras(Bundle extras) {

src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java 🔗

@@ -84,1060 +84,1068 @@ import eu.siacs.conversations.xmpp.jid.Jid;
 
 public class StartConversationActivity extends XmppActivity implements OnRosterUpdate, OnUpdateBlocklist {
 
-    public int conference_context_id;
-    public int contact_context_id;
-    private ListPagerAdapter mListPagerAdapter;
-    private List<ListItem> contacts = new ArrayList<>();
-    private ListItemAdapter mContactsAdapter;
-    private List<ListItem> conferences = new ArrayList<>();
-    private ListItemAdapter mConferenceAdapter;
-    private List<String> mActivatedAccounts = new ArrayList<>();
-    private List<String> mKnownHosts;
-    private List<String> mKnownConferenceHosts;
-    private Invite mPendingInvite = null;
-    private EditText mSearchEditText;
-    private AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false);
-    private final int REQUEST_SYNC_CONTACTS = 0x28cf;
-    private final int REQUEST_CREATE_CONFERENCE = 0x39da;
-    private Dialog mCurrentDialog = null;
-
-    private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
-
-        @Override
-        public boolean onMenuItemActionExpand(MenuItem item) {
-            mSearchEditText.post(() -> {
-                mSearchEditText.requestFocus();
-                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-                imm.showSoftInput(mSearchEditText, InputMethodManager.SHOW_IMPLICIT);
-            });
-
-            return true;
-        }
-
-        @Override
-        public boolean onMenuItemActionCollapse(MenuItem item) {
-            hideKeyboard();
-            mSearchEditText.setText("");
-            filter(null);
-            return true;
-        }
-    };
-    private boolean mHideOfflineContacts = false;
-    private ActionBar.TabListener mTabListener = new ActionBar.TabListener() {
-
-        @Override
-        public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
-            return;
-        }
-
-        @Override
-        public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
-            binding.startConversationViewPager.setCurrentItem(tab.getPosition());
-            onTabChanged();
-        }
-
-        @Override
-        public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
-            return;
-        }
-    };
-    private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
-        @Override
-        public void onPageSelected(int position) {
-            ActionBar actionBar = getSupportActionBar();
-            if (actionBar != null) {
-                actionBar.setSelectedNavigationItem(position);
-            }
-            onTabChanged();
-        }
-    };
-    private TextWatcher mSearchTextWatcher = new TextWatcher() {
-
-        @Override
-        public void afterTextChanged(Editable editable) {
-            filter(editable.toString());
-        }
-
-        @Override
-        public void beforeTextChanged(CharSequence s, int start, int count,
-                                      int after) {
-        }
-
-        @Override
-        public void onTextChanged(CharSequence s, int start, int before, int count) {
-        }
-    };
-
-    private TextView.OnEditorActionListener mSearchDone = new TextView.OnEditorActionListener() {
-        @Override
-        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-            int pos = getSupportActionBar().getSelectedNavigationIndex();
-            if (pos == 0) {
-                if (contacts.size() == 1) {
-                    openConversationForContact((Contact) contacts.get(0));
-                    return true;
-                }
-            } else {
-                if (conferences.size() == 1) {
-                    openConversationsForBookmark((Bookmark) conferences.get(0));
-                    return true;
-                }
-            }
-            hideKeyboard();
-            mListPagerAdapter.requestFocus(pos);
-            return true;
-        }
-    };
-    private MenuItem mMenuSearchView;
-    private ListItemAdapter.OnTagClickedListener mOnTagClickedListener = new ListItemAdapter.OnTagClickedListener() {
-        @Override
-        public void onTagClicked(String tag) {
-            if (mMenuSearchView != null) {
-                mMenuSearchView.expandActionView();
-                mSearchEditText.setText("");
-                mSearchEditText.append(tag);
-                filter(tag);
-            }
-        }
-    };
-    private String mInitialJid;
-    private Pair<Integer, Intent> mPostponedActivityResult;
-    private UiCallback<Conversation> mAdhocConferenceCallback = new UiCallback<Conversation>() {
-        @Override
-        public void success(final Conversation conversation) {
-            runOnUiThread(() -> {
-                hideToast();
-                switchToConversation(conversation);
-            });
-        }
-
-        @Override
-        public void error(final int errorCode, Conversation object) {
-            runOnUiThread(() -> replaceToast(getString(errorCode)));
-        }
-
-        @Override
-        public void userInputRequried(PendingIntent pi, Conversation object) {
-
-        }
-    };
-    private Toast mToast;
-    private ActivityStartConversationBinding binding;
-
-    protected void hideToast() {
-        if (mToast != null) {
-            mToast.cancel();
-        }
-    }
-
-    protected void replaceToast(String msg) {
-        hideToast();
-        mToast = Toast.makeText(this, msg, Toast.LENGTH_LONG);
-        mToast.show();
-    }
-
-    @Override
-    public void onRosterUpdate() {
-        this.refreshUi();
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        new EmojiService(this).init();
-        this.binding = DataBindingUtil.setContentView(this,R.layout.activity_start_conversation);
-        this.binding.fab.setOnClickListener((v) -> {
-            if (getSupportActionBar().getSelectedNavigationIndex() == 0) {
-                showCreateContactDialog(null, null);
-            } else {
-                showCreateConferenceDialog();
-            }
-            });
-        ActionBar actionBar = getSupportActionBar();
-        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-
-        ActionBar.Tab mContactsTab = actionBar.newTab().setText(R.string.contacts).setTabListener(mTabListener);
-        ActionBar.Tab mConferencesTab = actionBar.newTab().setText(R.string.conferences).setTabListener(mTabListener);
-        actionBar.addTab(mContactsTab);
-        actionBar.addTab(mConferencesTab);
-
-        binding.startConversationViewPager.setOnPageChangeListener(mOnPageChangeListener);
-        mListPagerAdapter = new ListPagerAdapter(getSupportFragmentManager());
-        binding.startConversationViewPager.setAdapter(mListPagerAdapter);
-
-        mConferenceAdapter = new ListItemAdapter(this, conferences);
-        mContactsAdapter = new ListItemAdapter(this, contacts);
-        mContactsAdapter.setOnTagClickedListener(this.mOnTagClickedListener);
-        this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false);
-
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        } else {
-            Intent i = getIntent();
-            if (i == null || !i.hasExtra(WelcomeActivity.EXTRA_INVITE_URI)) {
-                askForContactsPermissions();
-            }
-        }
-        mConferenceAdapter.refreshSettings();
-        mContactsAdapter.refreshSettings();
-    }
-
-    @Override
-    public void onStop() {
-        if (mCurrentDialog != null) {
-            mCurrentDialog.dismiss();
-        }
-        super.onStop();
-    }
-
-    @Override
-    public void onNewIntent(Intent intent) {
-        if (xmppConnectionServiceBound) {
-            handleIntent(intent);
-        } else {
-            setIntent(intent);
-        }
-    }
-
-    protected void openConversationForContact(int position) {
-        Contact contact = (Contact) contacts.get(position);
-        openConversationForContact(contact);
-    }
-
-    protected void openConversationForContact(Contact contact) {
-        Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
-        switchToConversation(conversation);
-    }
-
-    protected void openConversationForContact() {
-        int position = contact_context_id;
-        openConversationForContact(position);
-    }
-
-    protected void openConversationForBookmark() {
-        openConversationForBookmark(conference_context_id);
-    }
-
-    protected void openConversationForBookmark(int position) {
-        Bookmark bookmark = (Bookmark) conferences.get(position);
-        openConversationsForBookmark(bookmark);
-    }
-
-    protected void shareBookmarkUri() {
-        shareBookmarkUri(conference_context_id);
-    }
-
-    protected void shareBookmarkUri(int position) {
-        Bookmark bookmark = (Bookmark) conferences.get(position);
-        Intent shareIntent = new Intent();
-        shareIntent.setAction(Intent.ACTION_SEND);
-        shareIntent.putExtra(Intent.EXTRA_TEXT, "xmpp:"+bookmark.getJid().toBareJid().toString()+"?join");
-        shareIntent.setType("text/plain");
-        try {
-            startActivity(Intent.createChooser(shareIntent, getText(R.string.share_uri_with)));
-        } catch (ActivityNotFoundException e) {
-            Toast.makeText(this, R.string.no_application_to_share_uri, Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    protected void openConversationsForBookmark(Bookmark bookmark) {
-        Jid jid = bookmark.getJid();
-        if (jid == null) {
-            Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
-            return;
-        }
-        Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), jid, true, true, true);
-        bookmark.setConversation(conversation);
-        if (!bookmark.autojoin() && getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin))) {
-            bookmark.setAutojoin(true);
-            xmppConnectionService.pushBookmarks(bookmark.getAccount());
-        }
-        switchToConversation(conversation);
-    }
-
-    protected void openDetailsForContact() {
-        int position = contact_context_id;
-        Contact contact = (Contact) contacts.get(position);
-        switchToContactDetails(contact);
-    }
-
-    protected void toggleContactBlock() {
-        final int position = contact_context_id;
-        BlockContactDialog.show(this, (Contact) contacts.get(position));
-    }
-
-    protected void deleteContact() {
-        final int position = contact_context_id;
-        final Contact contact = (Contact) contacts.get(position);
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setNegativeButton(R.string.cancel, null);
-        builder.setTitle(R.string.action_delete_contact);
-        builder.setMessage(getString(R.string.remove_contact_text,
-                contact.getJid()));
-        builder.setPositiveButton(R.string.delete, new OnClickListener() {
-
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                xmppConnectionService.deleteContactOnServer(contact);
-                filter(mSearchEditText.getText().toString());
-            }
-        });
-        builder.create().show();
-    }
-
-    protected void deleteConference() {
-        int position = conference_context_id;
-        final Bookmark bookmark = (Bookmark) conferences.get(position);
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setNegativeButton(R.string.cancel, null);
-        builder.setTitle(R.string.delete_bookmark);
-        builder.setMessage(getString(R.string.remove_bookmark_text,
-                bookmark.getJid()));
-        builder.setPositiveButton(R.string.delete, new OnClickListener() {
-
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                bookmark.setConversation(null);
-                Account account = bookmark.getAccount();
-                account.getBookmarks().remove(bookmark);
-                xmppConnectionService.pushBookmarks(account);
-                filter(mSearchEditText.getText().toString());
-            }
-        });
-        builder.create().show();
-
-    }
-
-    @SuppressLint("InflateParams")
-    protected void showCreateContactDialog(final String prefilledJid, final Invite invite) {
-        EnterJidDialog dialog = new EnterJidDialog(
-                this, mKnownHosts, mActivatedAccounts,
-                getString(R.string.dialog_title_create_contact), getString(R.string.create),
-                prefilledJid, null, invite == null || !invite.hasFingerprints()
-        );
-
-        dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> {
-            if (!xmppConnectionServiceBound) {
-                return false;
-            }
-
-            final Account account = xmppConnectionService.findAccountByJid(accountJid);
-            if (account == null) {
-                return true;
-            }
-
-            final Contact contact = account.getRoster().getContact(contactJid);
-            if (invite != null && invite.getName() != null) {
-                contact.setServerName(invite.getName());
-            }
-            if (contact.isSelf()) {
-                switchToConversation(contact,null);
-                return true;
-            } else if (contact.showInRoster()) {
-                throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists));
-            } else {
-                xmppConnectionService.createContact(contact);
-                if (invite != null && invite.hasFingerprints()) {
-                    xmppConnectionService.verifyFingerprints(contact,invite.getFingerprints());
-                }
-                switchToConversation(contact, invite == null ? null : invite.getBody());
-                return true;
-            }
-        });
-
-        mCurrentDialog = dialog.show();
-    }
-
-    @SuppressLint("InflateParams")
-    protected void showJoinConferenceDialog(final String prefilledJid) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setTitle(R.string.dialog_title_join_conference);
-        final View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null);
-        final Spinner spinner = dialogView.findViewById(R.id.account);
-        final AutoCompleteTextView jid = dialogView.findViewById(R.id.jid);
-        final TextView jabberIdDesc = dialogView.findViewById(R.id.jabber_id);
-        jabberIdDesc.setText(R.string.conference_address);
-        jid.setHint(R.string.conference_address_example);
-        jid.setAdapter(new KnownHostsAdapter(this, R.layout.simple_list_item, mKnownConferenceHosts));
-        if (prefilledJid != null) {
-            jid.append(prefilledJid);
-        }
-        populateAccountSpinner(this, mActivatedAccounts, spinner);
-        final Checkable bookmarkCheckBox = (CheckBox) dialogView
-                .findViewById(R.id.bookmark);
-        builder.setView(dialogView);
-        builder.setNegativeButton(R.string.cancel, null);
-        builder.setPositiveButton(R.string.join, null);
-        final AlertDialog dialog = builder.create();
-        dialog.show();
-        mCurrentDialog = dialog;
-        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
-                new View.OnClickListener() {
-
-                    @Override
-                    public void onClick(final View v) {
-                        if (!xmppConnectionServiceBound) {
-                            return;
-                        }
-                        final Account account = getSelectedAccount(spinner);
-                        if (account == null) {
-                            return;
-                        }
-                        final Jid conferenceJid;
-                        try {
-                            conferenceJid = Jid.fromString(jid.getText().toString());
-                        } catch (final InvalidJidException e) {
-                            jid.setError(getString(R.string.invalid_jid));
-                            return;
-                        }
-
-                        if (bookmarkCheckBox.isChecked()) {
-                            if (account.hasBookmarkFor(conferenceJid)) {
-                                jid.setError(getString(R.string.bookmark_already_exists));
-                            } else {
-                                final Bookmark bookmark = new Bookmark(account, conferenceJid.toBareJid());
-                                bookmark.setAutojoin(getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin)));
-                                String nick = conferenceJid.getResourcepart();
-                                if (nick != null && !nick.isEmpty()) {
-                                    bookmark.setNick(nick);
-                                }
-                                account.getBookmarks().add(bookmark);
-                                xmppConnectionService.pushBookmarks(account);
-                                final Conversation conversation = xmppConnectionService
-                                        .findOrCreateConversation(account, conferenceJid, true, true, true);
-                                bookmark.setConversation(conversation);
-                                dialog.dismiss();
-                                mCurrentDialog = null;
-                                switchToConversation(conversation);
-                            }
-                        } else {
-                            final Conversation conversation = xmppConnectionService
-                                    .findOrCreateConversation(account,conferenceJid, true, true, true);
-                            dialog.dismiss();
-                            mCurrentDialog = null;
-                            switchToConversation(conversation);
-                        }
-                    }
-                });
-    }
-
-    private void showCreateConferenceDialog() {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setTitle(R.string.dialog_title_create_conference);
-        final View dialogView = getLayoutInflater().inflate(R.layout.create_conference_dialog, null);
-        final Spinner spinner = dialogView.findViewById(R.id.account);
-        final EditText subject = dialogView.findViewById(R.id.subject);
-        populateAccountSpinner(this, mActivatedAccounts, spinner);
-        builder.setView(dialogView);
-        builder.setPositiveButton(R.string.choose_participants, new OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                if (!xmppConnectionServiceBound) {
-                    return;
-                }
-                final Account account = getSelectedAccount(spinner);
-                if (account == null) {
-                    return;
-                }
-                Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
-                intent.putExtra("multiple", true);
-                intent.putExtra("show_enter_jid", true);
-                intent.putExtra("subject", subject.getText().toString());
-                intent.putExtra(EXTRA_ACCOUNT, account.getJid().toBareJid().toString());
-                intent.putExtra(ChooseContactActivity.EXTRA_TITLE_RES_ID, R.string.choose_participants);
-                startActivityForResult(intent, REQUEST_CREATE_CONFERENCE);
-            }
-        });
-        builder.setNegativeButton(R.string.cancel, null);
-        mCurrentDialog = builder.create();
-        mCurrentDialog.show();
-    }
-
-    private Account getSelectedAccount(Spinner spinner) {
-        if (!spinner.isEnabled()) {
-            return null;
-        }
-        Jid jid;
-        try {
-            if (Config.DOMAIN_LOCK != null) {
-                jid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
-            } else {
-                jid = Jid.fromString((String) spinner.getSelectedItem());
-            }
-        } catch (final InvalidJidException e) {
-            return null;
-        }
-        return xmppConnectionService.findAccountByJid(jid);
-    }
-
-    protected void switchToConversation(Contact contact, String body) {
-        Conversation conversation = xmppConnectionService
-                .findOrCreateConversation(contact.getAccount(),
-                        contact.getJid(),false,true);
-        switchToConversation(conversation, body, false);
-    }
-
-    public static void populateAccountSpinner(Context context, List<String> accounts, Spinner spinner) {
-        if (accounts.size() > 0) {
-            ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.simple_list_item, accounts);
-            adapter.setDropDownViewResource(R.layout.simple_list_item);
-            spinner.setAdapter(adapter);
-            spinner.setEnabled(true);
-        } else {
-            ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
-                    R.layout.simple_list_item,
-                    Arrays.asList(context.getString(R.string.no_accounts)));
-            adapter.setDropDownViewResource(R.layout.simple_list_item);
-            spinner.setAdapter(adapter);
-            spinner.setEnabled(false);
-        }
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.start_conversation, menu);
-        MenuItem menuHideOffline = menu.findItem(R.id.action_hide_offline);
-        menuHideOffline.setChecked(this.mHideOfflineContacts);
-        mMenuSearchView = menu.findItem(R.id.action_search);
-        mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
-        View mSearchView = mMenuSearchView.getActionView();
-        mSearchEditText = mSearchView.findViewById(R.id.search_field);
-        mSearchEditText.addTextChangedListener(mSearchTextWatcher);
-        mSearchEditText.setOnEditorActionListener(mSearchDone);
-        if (mInitialJid != null) {
-            MenuItemCompat.expandActionView(mMenuSearchView);
-            mSearchEditText.append(mInitialJid);
-            filter(mInitialJid);
-        }
-        return super.onCreateOptionsMenu(menu);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.action_join_conference:
-                showJoinConferenceDialog(null);
-                return true;
-            case R.id.action_scan_qr_code:
-                UriHandlerActivity.scan(this);
-                return true;
-            case R.id.action_hide_offline:
-                mHideOfflineContacts = !item.isChecked();
-                getPreferences().edit().putBoolean("hide_offline", mHideOfflineContacts).commit();
-                if (mSearchEditText != null) {
-                    filter(mSearchEditText.getText().toString());
-                }
-                invalidateOptionsMenu();
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress()) {
-            openSearch();
-            return true;
-        }
-        int c = event.getUnicodeChar();
-        if (c > 32) {
-            if (mSearchEditText != null && !mSearchEditText.isFocused()) {
-                openSearch();
-                mSearchEditText.append(Character.toString((char) c));
-                return true;
-            }
-        }
-        return super.onKeyUp(keyCode, event);
-    }
-
-    private void openSearch() {
-        if (mMenuSearchView != null) {
-            mMenuSearchView.expandActionView();
-        }
-    }
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
-        if (resultCode == RESULT_OK) {
-            if (xmppConnectionServiceBound) {
-                this.mPostponedActivityResult = null;
-                if (requestCode == REQUEST_CREATE_CONFERENCE) {
-                    Account account = extractAccount(intent);
-                    final String subject = intent.getStringExtra("subject");
-                    List<Jid> jids = new ArrayList<>();
-                    if (intent.getBooleanExtra("multiple", false)) {
-                        String[] toAdd = intent.getStringArrayExtra("contacts");
-                        for (String item : toAdd) {
-                            try {
-                                jids.add(Jid.fromString(item));
-                            } catch (InvalidJidException e) {
-                                //ignored
-                            }
-                        }
-                    } else {
-                        try {
-                            jids.add(Jid.fromString(intent.getStringExtra("contact")));
-                        } catch (Exception e) {
-                            //ignored
-                        }
-                    }
-                    if (account != null && jids.size() > 0) {
-                        if (xmppConnectionService.createAdhocConference(account, subject, jids, mAdhocConferenceCallback)) {
-                            mToast = Toast.makeText(this, R.string.creating_conference, Toast.LENGTH_LONG);
-                            mToast.show();
-                        }
-                    }
-                }
-            } else {
-                this.mPostponedActivityResult = new Pair<>(requestCode, intent);
-            }
-        }
-        super.onActivityResult(requestCode, requestCode, intent);
-    }
-
-    private void askForContactsPermissions() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
-                if (mRequestedContactsPermission.compareAndSet(false, true)) {
-                    if (shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) {
-                        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-                        builder.setTitle(R.string.sync_with_contacts);
-                        builder.setMessage(R.string.sync_with_contacts_long);
-                        builder.setPositiveButton(R.string.next, new OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-                                    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
-                                }
-                            }
-                        });
-                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-                            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
-                                @Override
-                                public void onDismiss(DialogInterface dialog) {
-                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-                                        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
-                                    }
-                                }
-                            });
-                        }
-                        builder.create().show();
-                    } else {
-                        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode,@NonNull String permissions[],@NonNull int[] grantResults) {
-        if (grantResults.length > 0)
-            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-                if (requestCode == REQUEST_SYNC_CONTACTS && xmppConnectionServiceBound) {
-                    xmppConnectionService.loadPhoneContacts();
-                }
-            }
-    }
-
-    @Override
-    protected void onBackendConnected() {
-        if (mPostponedActivityResult != null) {
-            onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
-            this.mPostponedActivityResult = null;
-        }
-        this.mActivatedAccounts.clear();
-        for (Account account : xmppConnectionService.getAccounts()) {
-            if (account.getStatus() != Account.State.DISABLED) {
-                if (Config.DOMAIN_LOCK != null) {
-                    this.mActivatedAccounts.add(account.getJid().getLocalpart());
-                } else {
-                    this.mActivatedAccounts.add(account.getJid().toBareJid().toString());
-                }
-            }
-        }
-        final Intent intent = getIntent();
-        final ActionBar ab = getSupportActionBar();
-        boolean init = intent != null && intent.getBooleanExtra("init", false);
-        boolean noConversations = xmppConnectionService.getConversations().size() == 0;
-        if ((init || noConversations) && ab != null) {
-            ab.setDisplayShowHomeEnabled(false);
-            ab.setDisplayHomeAsUpEnabled(false);
-            ab.setHomeButtonEnabled(false);
-        }
-        this.mKnownHosts = xmppConnectionService.getKnownHosts();
-        this.mKnownConferenceHosts = xmppConnectionService.getKnownConferenceHosts();
-        if (this.mPendingInvite != null) {
-            mPendingInvite.invite();
-            this.mPendingInvite = null;
-            filter(null);
-        } else if (!handleIntent(getIntent())) {
-            if (mSearchEditText != null) {
-                filter(mSearchEditText.getText().toString());
-            } else {
-                filter(null);
-            }
-        } else {
-            filter(null);
-        }
-        setIntent(null);
-    }
-
-    protected boolean handleIntent(Intent intent) {
-        if (intent == null) {
-            return false;
-        }
-        final String inviteUri = intent.getStringExtra(WelcomeActivity.EXTRA_INVITE_URI);
-        if (inviteUri != null) {
-            Invite invite = new Invite(inviteUri);
-            if (invite.isJidValid()) {
-                return invite.invite();
-            }
-        }
-        if (intent.getAction() == null) {
-            return false;
-        }
-        switch (intent.getAction()) {
-            case Intent.ACTION_SENDTO:
-            case Intent.ACTION_VIEW:
-                Uri uri = intent.getData();
-                if (uri != null) {
-                    Invite invite = new Invite(intent.getData(),false);
-                    invite.account = intent.getStringExtra("account");
-                    return invite.invite();
-                } else {
-                    return false;
-                }
-        }
-        return false;
-    }
-
-    private boolean handleJid(Invite invite) {
-        List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid(),invite.account);
-        if (invite.isAction(XmppUri.ACTION_JOIN)) {
-            Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid());
-            if (muc != null) {
-                switchToConversation(muc,invite.getBody(),false);
-                return true;
-            } else {
-                showJoinConferenceDialog(invite.getJid().toBareJid().toString());
-                return false;
-            }
-        } else if (contacts.size() == 0) {
-            showCreateContactDialog(invite.getJid().toString(), invite);
-            return false;
-        } else if (contacts.size() == 1) {
-            Contact contact = contacts.get(0);
-            if (!invite.isSafeSource() && invite.hasFingerprints()) {
-                displayVerificationWarningDialog(contact,invite);
-            } else {
-                if (invite.hasFingerprints()) {
-                    if(xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints())) {
-                        Toast.makeText(this,R.string.verified_fingerprints,Toast.LENGTH_SHORT).show();
-                    }
-                }
-                if (invite.account != null) {
-                    xmppConnectionService.getShortcutService().report(contact);
-                }
-                switchToConversation(contact, invite.getBody());
-            }
-            return true;
-        } else {
-            if (mMenuSearchView != null) {
-                mMenuSearchView.expandActionView();
-                mSearchEditText.setText("");
-                mSearchEditText.append(invite.getJid().toString());
-                filter(invite.getJid().toString());
-            } else {
-                mInitialJid = invite.getJid().toString();
-            }
-            return true;
-        }
-    }
-
-    private void displayVerificationWarningDialog(final Contact contact, final Invite invite) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setTitle(R.string.verify_omemo_keys);
-        View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
-        final CheckBox isTrustedSource = (CheckBox) view.findViewById(R.id.trusted_source);
-        TextView warning = (TextView) view.findViewById(R.id.warning);
-        String jid = contact.getJid().toBareJid().toString();
-        SpannableString spannable = new SpannableString(getString(R.string.verifying_omemo_keys_trusted_source,jid,contact.getDisplayName()));
-        int start = spannable.toString().indexOf(jid);
-        if (start >= 0) {
-            spannable.setSpan(new TypefaceSpan("monospace"),start,start + jid.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-        }
-        warning.setText(spannable);
-        builder.setView(view);
-        builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
-            if (isTrustedSource.isChecked() && invite.hasFingerprints()) {
-                xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
-            }
-            switchToConversation(contact, invite.getBody());
-        });
-        builder.setNegativeButton(R.string.cancel, (dialog, which) -> StartConversationActivity.this.finish());
-        AlertDialog dialog = builder.create();
-        dialog.setCanceledOnTouchOutside(false);
-        dialog.setOnCancelListener(dialog1 -> StartConversationActivity.this.finish());
-        dialog.show();
-    }
-
-    protected void filter(String needle) {
-        if (xmppConnectionServiceBound) {
-            this.filterContacts(needle);
-            this.filterConferences(needle);
-        }
-    }
-
-    protected void filterContacts(String needle) {
-        this.contacts.clear();
-        for (Account account : xmppConnectionService.getAccounts()) {
-            if (account.getStatus() != Account.State.DISABLED) {
-                for (Contact contact : account.getRoster().getContacts()) {
-                    Presence.Status s = contact.getShownStatus();
-                    if (contact.showInRoster() && contact.match(this, needle)
-                            && (!this.mHideOfflineContacts
-                            || (needle != null && !needle.trim().isEmpty())
-                            || s.compareTo(Presence.Status.OFFLINE) < 0)) {
-                        this.contacts.add(contact);
-                    }
-                }
-            }
-        }
-        Collections.sort(this.contacts);
-        mContactsAdapter.notifyDataSetChanged();
-    }
-
-    protected void filterConferences(String needle) {
-        this.conferences.clear();
-        for (Account account : xmppConnectionService.getAccounts()) {
-            if (account.getStatus() != Account.State.DISABLED) {
-                for (Bookmark bookmark : account.getBookmarks()) {
-                    if (bookmark.match(this, needle)) {
-                        this.conferences.add(bookmark);
-                    }
-                }
-            }
-        }
-        Collections.sort(this.conferences);
-        mConferenceAdapter.notifyDataSetChanged();
-    }
-
-    private void onTabChanged() {
-        @DrawableRes final int fabDrawable;
-        if (getSupportActionBar().getSelectedNavigationIndex() == 0) {
-            fabDrawable = R.drawable.ic_person_add_white_24dp;
-        } else {
-            fabDrawable = R.drawable.ic_group_add_white_24dp;
-        }
-        binding.fab.setImageResource(fabDrawable);
-        invalidateOptionsMenu();
-    }
-
-    public static void launch(Context context) {
-        final Intent intent = new Intent(context,StartConversationActivity.class);
-        context.startActivity(intent);
-    }
-
-    @Override
-    public void OnUpdateBlocklist(final Status status) {
-        refreshUi();
-    }
-
-    @Override
-    protected void refreshUiReal() {
-        if (mSearchEditText != null) {
-            filter(mSearchEditText.getText().toString());
-        }
-    }
-
-    public class ListPagerAdapter extends PagerAdapter {
-        FragmentManager fragmentManager;
-        MyListFragment[] fragments;
-
-        public ListPagerAdapter(FragmentManager fm) {
-            fragmentManager = fm;
-            fragments = new MyListFragment[2];
-        }
-
-        public void requestFocus(int pos) {
-            if (fragments.length > pos) {
-                fragments[pos].getListView().requestFocus();
-            }
-        }
-
-        @Override
-        public void destroyItem(@NonNull ViewGroup container, int position,@NonNull Object object) {
-            assert (0 <= position && position < fragments.length);
-            FragmentTransaction trans = fragmentManager.beginTransaction();
-            trans.remove(fragments[position]);
-            trans.commit();
-            fragments[position] = null;
-        }
-
-        @Override
-        public Fragment instantiateItem(@NonNull ViewGroup container, int position) {
-            Fragment fragment = getItem(position);
-            FragmentTransaction trans = fragmentManager.beginTransaction();
-            trans.add(container.getId(), fragment, "fragment:" + position);
-            trans.commit();
-            return fragment;
-        }
-
-        @Override
-        public int getCount() {
-            return fragments.length;
-        }
-
-        @Override
-        public boolean isViewFromObject(@NonNull View view,@NonNull  Object fragment) {
-            return ((Fragment) fragment).getView() == view;
-        }
-
-        public Fragment getItem(int position) {
-            assert (0 <= position && position < fragments.length);
-            if (fragments[position] == null) {
-                final MyListFragment listFragment = new MyListFragment();
-                if (position == 1) {
-                    listFragment.setListAdapter(mConferenceAdapter);
-                    listFragment.setContextMenu(R.menu.conference_context);
-                    listFragment.setOnListItemClickListener((arg0, arg1, p, arg3) -> openConversationForBookmark(p));
-                } else {
-
-                    listFragment.setListAdapter(mContactsAdapter);
-                    listFragment.setContextMenu(R.menu.contact_context);
-                    listFragment.setOnListItemClickListener((arg0, arg1, p, arg3) -> openConversationForContact(p));
-                }
-                fragments[position] = listFragment;
-            }
-            return fragments[position];
-        }
-    }
-
-    public static class MyListFragment extends ListFragment {
-        private AdapterView.OnItemClickListener mOnItemClickListener;
-        private int mResContextMenu;
-
-        public void setContextMenu(final int res) {
-            this.mResContextMenu = res;
-        }
-
-        @Override
-        public void onListItemClick(final ListView l, final View v, final int position, final long id) {
-            if (mOnItemClickListener != null) {
-                mOnItemClickListener.onItemClick(l, v, position, id);
-            }
-        }
-
-        public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
-            this.mOnItemClickListener = l;
-        }
-
-        @Override
-        public void onViewCreated(@NonNull final View view, final Bundle savedInstanceState) {
-            super.onViewCreated(view, savedInstanceState);
-            registerForContextMenu(getListView());
-            getListView().setFastScrollEnabled(true);
-            getListView().setDivider(null);
-            getListView().setDividerHeight(0);
-        }
-
-        @Override
-        public void onCreateContextMenu(final ContextMenu menu, final View v,
-                                        final ContextMenuInfo menuInfo) {
-            super.onCreateContextMenu(menu, v, menuInfo);
-            final StartConversationActivity activity = (StartConversationActivity) getActivity();
-            if (activity == null) {
-                return;
-            }
-            activity.getMenuInflater().inflate(mResContextMenu, menu);
-            final AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
-            if (mResContextMenu == R.menu.conference_context) {
-                activity.conference_context_id = acmi.position;
-            } else if (mResContextMenu == R.menu.contact_context) {
-                activity.contact_context_id = acmi.position;
-                final Contact contact = (Contact) activity.contacts.get(acmi.position);
-                final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock);
-                final MenuItem showContactDetailsItem = menu.findItem(R.id.context_contact_details);
-                if (contact.isSelf()) {
-                    showContactDetailsItem.setVisible(false);
-                }
-                XmppConnection xmpp = contact.getAccount().getXmppConnection();
-                if (xmpp != null && xmpp.getFeatures().blocking() && !contact.isSelf()) {
-                    if (contact.isBlocked()) {
-                        blockUnblockItem.setTitle(R.string.unblock_contact);
-                    } else {
-                        blockUnblockItem.setTitle(R.string.block_contact);
-                    }
-                } else {
-                    blockUnblockItem.setVisible(false);
-                }
-            }
-        }
-
-        @Override
-        public boolean onContextItemSelected(final MenuItem item) {
-            StartConversationActivity activity = (StartConversationActivity) getActivity();
-            if (activity == null) {
-                return true;
-            }
-            switch (item.getItemId()) {
-                case R.id.context_start_conversation:
-                    activity.openConversationForContact();
-                    break;
-                case R.id.context_contact_details:
-                    activity.openDetailsForContact();
-                    break;
-                case R.id.context_contact_block_unblock:
-                    activity.toggleContactBlock();
-                    break;
-                case R.id.context_delete_contact:
-                    activity.deleteContact();
-                    break;
-                case R.id.context_join_conference:
-                    activity.openConversationForBookmark();
-                    break;
-                case R.id.context_share_uri:
-                    activity.shareBookmarkUri();
-                    break;
-                case R.id.context_delete_conference:
-                    activity.deleteConference();
-            }
-            return true;
-        }
-    }
-
-    private class Invite extends XmppUri {
-
-        public Invite(final Uri uri) {
-            super(uri);
-        }
-
-        public Invite(final String uri) {
-            super(uri);
-        }
-
-        public Invite(Uri uri, boolean safeSource) {
-            super(uri,safeSource);
-        }
-
-        public String account;
-
-        boolean invite() {
-            if (!isJidValid()) {
-                Toast.makeText(StartConversationActivity.this,R.string.invalid_jid,Toast.LENGTH_SHORT).show();
-                return false;
-            }
-            if (getJid() != null) {
-                return handleJid(this);
-            }
-            return false;
-        }
-    }
+	private final int REQUEST_SYNC_CONTACTS = 0x28cf;
+	private final int REQUEST_CREATE_CONFERENCE = 0x39da;
+	public int conference_context_id;
+	public int contact_context_id;
+	private ListPagerAdapter mListPagerAdapter;
+	private List<ListItem> contacts = new ArrayList<>();
+	private ListItemAdapter mContactsAdapter;
+	private List<ListItem> conferences = new ArrayList<>();
+	private ListItemAdapter mConferenceAdapter;
+	private List<String> mActivatedAccounts = new ArrayList<>();
+	private List<String> mKnownHosts;
+	private List<String> mKnownConferenceHosts;
+	private Invite mPendingInvite = null;
+	private EditText mSearchEditText;
+	private AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false);
+	private Dialog mCurrentDialog = null;
+	private boolean mHideOfflineContacts = false;
+	private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
+
+		@Override
+		public boolean onMenuItemActionExpand(MenuItem item) {
+			mSearchEditText.post(() -> {
+				mSearchEditText.requestFocus();
+				InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+				imm.showSoftInput(mSearchEditText, InputMethodManager.SHOW_IMPLICIT);
+			});
+
+			return true;
+		}
+
+		@Override
+		public boolean onMenuItemActionCollapse(MenuItem item) {
+			hideKeyboard();
+			mSearchEditText.setText("");
+			filter(null);
+			return true;
+		}
+	};
+	private TextWatcher mSearchTextWatcher = new TextWatcher() {
+
+		@Override
+		public void afterTextChanged(Editable editable) {
+			filter(editable.toString());
+		}
+
+		@Override
+		public void beforeTextChanged(CharSequence s, int start, int count,
+		                              int after) {
+		}
+
+		@Override
+		public void onTextChanged(CharSequence s, int start, int before, int count) {
+		}
+	};
+	private TextView.OnEditorActionListener mSearchDone = new TextView.OnEditorActionListener() {
+		@Override
+		public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+			int pos = getSupportActionBar().getSelectedNavigationIndex();
+			if (pos == 0) {
+				if (contacts.size() == 1) {
+					openConversationForContact((Contact) contacts.get(0));
+					return true;
+				}
+			} else {
+				if (conferences.size() == 1) {
+					openConversationsForBookmark((Bookmark) conferences.get(0));
+					return true;
+				}
+			}
+			hideKeyboard();
+			mListPagerAdapter.requestFocus(pos);
+			return true;
+		}
+	};
+	private MenuItem mMenuSearchView;
+	private ListItemAdapter.OnTagClickedListener mOnTagClickedListener = new ListItemAdapter.OnTagClickedListener() {
+		@Override
+		public void onTagClicked(String tag) {
+			if (mMenuSearchView != null) {
+				mMenuSearchView.expandActionView();
+				mSearchEditText.setText("");
+				mSearchEditText.append(tag);
+				filter(tag);
+			}
+		}
+	};
+	private String mInitialJid;
+	private Pair<Integer, Intent> mPostponedActivityResult;
+	private Toast mToast;
+	private UiCallback<Conversation> mAdhocConferenceCallback = new UiCallback<Conversation>() {
+		@Override
+		public void success(final Conversation conversation) {
+			runOnUiThread(() -> {
+				hideToast();
+				switchToConversation(conversation);
+			});
+		}
+
+		@Override
+		public void error(final int errorCode, Conversation object) {
+			runOnUiThread(() -> replaceToast(getString(errorCode)));
+		}
+
+		@Override
+		public void userInputRequried(PendingIntent pi, Conversation object) {
+
+		}
+	};
+	private ActivityStartConversationBinding binding;
+	private ActionBar.TabListener mTabListener = new ActionBar.TabListener() {
+
+		@Override
+		public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
+			return;
+		}
+
+		@Override
+		public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
+			binding.startConversationViewPager.setCurrentItem(tab.getPosition());
+			onTabChanged();
+		}
+
+		@Override
+		public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
+			return;
+		}
+	};
+	private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
+		@Override
+		public void onPageSelected(int position) {
+			ActionBar actionBar = getSupportActionBar();
+			if (actionBar != null) {
+				actionBar.setSelectedNavigationItem(position);
+			}
+			onTabChanged();
+		}
+	};
+
+	public static void populateAccountSpinner(Context context, List<String> accounts, Spinner spinner) {
+		if (accounts.size() > 0) {
+			ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.simple_list_item, accounts);
+			adapter.setDropDownViewResource(R.layout.simple_list_item);
+			spinner.setAdapter(adapter);
+			spinner.setEnabled(true);
+		} else {
+			ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
+					R.layout.simple_list_item,
+					Arrays.asList(context.getString(R.string.no_accounts)));
+			adapter.setDropDownViewResource(R.layout.simple_list_item);
+			spinner.setAdapter(adapter);
+			spinner.setEnabled(false);
+		}
+	}
+
+	public static void launch(Context context) {
+		final Intent intent = new Intent(context, StartConversationActivity.class);
+		context.startActivity(intent);
+	}
+
+	protected void hideToast() {
+		if (mToast != null) {
+			mToast.cancel();
+		}
+	}
+
+	protected void replaceToast(String msg) {
+		hideToast();
+		mToast = Toast.makeText(this, msg, Toast.LENGTH_LONG);
+		mToast.show();
+	}
+
+	@Override
+	public void onRosterUpdate() {
+		this.refreshUi();
+	}
+
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		new EmojiService(this).init();
+		this.binding = DataBindingUtil.setContentView(this, R.layout.activity_start_conversation);
+		this.binding.fab.setOnClickListener((v) -> {
+			if (getSupportActionBar().getSelectedNavigationIndex() == 0) {
+				String searchString = mSearchEditText != null ? mSearchEditText.getText().toString() : null;
+				if (searchString != null && !searchString.trim().isEmpty()) {
+					try {
+						Jid jid = Jid.fromString(searchString);
+						if (!jid.isDomainJid() && jid.isBareJid() && jid.getDomainpart().contains(".")) {
+							showCreateContactDialog(jid.toString(),null);
+							return;
+						}
+					} catch (InvalidJidException ignored) {
+						//ignore and fall through
+					}
+				}
+				showCreateContactDialog(null, null);
+			} else {
+				showCreateConferenceDialog();
+			}
+		});
+		ActionBar actionBar = getSupportActionBar();
+		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+		ActionBar.Tab mContactsTab = actionBar.newTab().setText(R.string.contacts).setTabListener(mTabListener);
+		ActionBar.Tab mConferencesTab = actionBar.newTab().setText(R.string.conferences).setTabListener(mTabListener);
+		actionBar.addTab(mContactsTab);
+		actionBar.addTab(mConferencesTab);
+
+		binding.startConversationViewPager.setOnPageChangeListener(mOnPageChangeListener);
+		mListPagerAdapter = new ListPagerAdapter(getSupportFragmentManager());
+		binding.startConversationViewPager.setAdapter(mListPagerAdapter);
+
+		mConferenceAdapter = new ListItemAdapter(this, conferences);
+		mContactsAdapter = new ListItemAdapter(this, contacts);
+		mContactsAdapter.setOnTagClickedListener(this.mOnTagClickedListener);
+		this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false);
+
+	}
+
+	@Override
+	public void onStart() {
+		super.onStart();
+		final int theme = findTheme();
+		if (this.mTheme != theme) {
+			recreate();
+		} else {
+			Intent i = getIntent();
+			if (i == null || !i.hasExtra(WelcomeActivity.EXTRA_INVITE_URI)) {
+				askForContactsPermissions();
+			}
+		}
+		mConferenceAdapter.refreshSettings();
+		mContactsAdapter.refreshSettings();
+	}
+
+	@Override
+	public void onStop() {
+		if (mCurrentDialog != null) {
+			mCurrentDialog.dismiss();
+		}
+		super.onStop();
+	}
+
+	@Override
+	public void onNewIntent(Intent intent) {
+		if (xmppConnectionServiceBound) {
+			handleIntent(intent);
+		} else {
+			setIntent(intent);
+		}
+	}
+
+	protected void openConversationForContact(int position) {
+		Contact contact = (Contact) contacts.get(position);
+		openConversationForContact(contact);
+	}
+
+	protected void openConversationForContact(Contact contact) {
+		Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
+		switchToConversation(conversation);
+	}
+
+	protected void openConversationForContact() {
+		int position = contact_context_id;
+		openConversationForContact(position);
+	}
+
+	protected void openConversationForBookmark() {
+		openConversationForBookmark(conference_context_id);
+	}
+
+	protected void openConversationForBookmark(int position) {
+		Bookmark bookmark = (Bookmark) conferences.get(position);
+		openConversationsForBookmark(bookmark);
+	}
+
+	protected void shareBookmarkUri() {
+		shareBookmarkUri(conference_context_id);
+	}
+
+	protected void shareBookmarkUri(int position) {
+		Bookmark bookmark = (Bookmark) conferences.get(position);
+		Intent shareIntent = new Intent();
+		shareIntent.setAction(Intent.ACTION_SEND);
+		shareIntent.putExtra(Intent.EXTRA_TEXT, "xmpp:" + bookmark.getJid().toBareJid().toString() + "?join");
+		shareIntent.setType("text/plain");
+		try {
+			startActivity(Intent.createChooser(shareIntent, getText(R.string.share_uri_with)));
+		} catch (ActivityNotFoundException e) {
+			Toast.makeText(this, R.string.no_application_to_share_uri, Toast.LENGTH_SHORT).show();
+		}
+	}
+
+	protected void openConversationsForBookmark(Bookmark bookmark) {
+		Jid jid = bookmark.getJid();
+		if (jid == null) {
+			Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
+			return;
+		}
+		Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), jid, true, true, true);
+		bookmark.setConversation(conversation);
+		if (!bookmark.autojoin() && getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin))) {
+			bookmark.setAutojoin(true);
+			xmppConnectionService.pushBookmarks(bookmark.getAccount());
+		}
+		switchToConversation(conversation);
+	}
+
+	protected void openDetailsForContact() {
+		int position = contact_context_id;
+		Contact contact = (Contact) contacts.get(position);
+		switchToContactDetails(contact);
+	}
+
+	protected void toggleContactBlock() {
+		final int position = contact_context_id;
+		BlockContactDialog.show(this, (Contact) contacts.get(position));
+	}
+
+	protected void deleteContact() {
+		final int position = contact_context_id;
+		final Contact contact = (Contact) contacts.get(position);
+		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		builder.setNegativeButton(R.string.cancel, null);
+		builder.setTitle(R.string.action_delete_contact);
+		builder.setMessage(getString(R.string.remove_contact_text,
+				contact.getJid()));
+		builder.setPositiveButton(R.string.delete, new OnClickListener() {
+
+			@Override
+			public void onClick(DialogInterface dialog, int which) {
+				xmppConnectionService.deleteContactOnServer(contact);
+				filter(mSearchEditText.getText().toString());
+			}
+		});
+		builder.create().show();
+	}
+
+	protected void deleteConference() {
+		int position = conference_context_id;
+		final Bookmark bookmark = (Bookmark) conferences.get(position);
+
+		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		builder.setNegativeButton(R.string.cancel, null);
+		builder.setTitle(R.string.delete_bookmark);
+		builder.setMessage(getString(R.string.remove_bookmark_text,
+				bookmark.getJid()));
+		builder.setPositiveButton(R.string.delete, new OnClickListener() {
+
+			@Override
+			public void onClick(DialogInterface dialog, int which) {
+				bookmark.setConversation(null);
+				Account account = bookmark.getAccount();
+				account.getBookmarks().remove(bookmark);
+				xmppConnectionService.pushBookmarks(account);
+				filter(mSearchEditText.getText().toString());
+			}
+		});
+		builder.create().show();
+
+	}
+
+	@SuppressLint("InflateParams")
+	protected void showCreateContactDialog(final String prefilledJid, final Invite invite) {
+		EnterJidDialog dialog = new EnterJidDialog(
+				this, mKnownHosts, mActivatedAccounts,
+				getString(R.string.dialog_title_create_contact), getString(R.string.create),
+				prefilledJid, null, invite == null || !invite.hasFingerprints()
+		);
+
+		dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> {
+			if (!xmppConnectionServiceBound) {
+				return false;
+			}
+
+			final Account account = xmppConnectionService.findAccountByJid(accountJid);
+			if (account == null) {
+				return true;
+			}
+
+			final Contact contact = account.getRoster().getContact(contactJid);
+			if (invite != null && invite.getName() != null) {
+				contact.setServerName(invite.getName());
+			}
+			if (contact.isSelf()) {
+				switchToConversation(contact, null);
+				return true;
+			} else if (contact.showInRoster()) {
+				throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists));
+			} else {
+				xmppConnectionService.createContact(contact);
+				if (invite != null && invite.hasFingerprints()) {
+					xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
+				}
+				switchToConversation(contact, invite == null ? null : invite.getBody());
+				return true;
+			}
+		});
+
+		mCurrentDialog = dialog.show();
+	}
+
+	@SuppressLint("InflateParams")
+	protected void showJoinConferenceDialog(final String prefilledJid) {
+		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		builder.setTitle(R.string.dialog_title_join_conference);
+		final View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null);
+		final Spinner spinner = dialogView.findViewById(R.id.account);
+		final AutoCompleteTextView jid = dialogView.findViewById(R.id.jid);
+		final TextView jabberIdDesc = dialogView.findViewById(R.id.jabber_id);
+		jabberIdDesc.setText(R.string.conference_address);
+		jid.setHint(R.string.conference_address_example);
+		jid.setAdapter(new KnownHostsAdapter(this, R.layout.simple_list_item, mKnownConferenceHosts));
+		if (prefilledJid != null) {
+			jid.append(prefilledJid);
+		}
+		populateAccountSpinner(this, mActivatedAccounts, spinner);
+		final Checkable bookmarkCheckBox = (CheckBox) dialogView
+				.findViewById(R.id.bookmark);
+		builder.setView(dialogView);
+		builder.setNegativeButton(R.string.cancel, null);
+		builder.setPositiveButton(R.string.join, null);
+		final AlertDialog dialog = builder.create();
+		dialog.show();
+		mCurrentDialog = dialog;
+		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
+			if (!xmppConnectionServiceBound) {
+				return;
+			}
+			final Account account = getSelectedAccount(spinner);
+			if (account == null) {
+				return;
+			}
+			final Jid conferenceJid;
+			try {
+				conferenceJid = Jid.fromString(jid.getText().toString());
+			} catch (final InvalidJidException e) {
+				jid.setError(getString(R.string.invalid_jid));
+				return;
+			}
+
+			if (bookmarkCheckBox.isChecked()) {
+				if (account.hasBookmarkFor(conferenceJid)) {
+					jid.setError(getString(R.string.bookmark_already_exists));
+				} else {
+					final Bookmark bookmark = new Bookmark(account, conferenceJid.toBareJid());
+					bookmark.setAutojoin(getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin)));
+					String nick = conferenceJid.getResourcepart();
+					if (nick != null && !nick.isEmpty()) {
+						bookmark.setNick(nick);
+					}
+					account.getBookmarks().add(bookmark);
+					xmppConnectionService.pushBookmarks(account);
+					final Conversation conversation = xmppConnectionService
+							.findOrCreateConversation(account, conferenceJid, true, true, true);
+					bookmark.setConversation(conversation);
+					dialog.dismiss();
+					mCurrentDialog = null;
+					switchToConversation(conversation);
+				}
+			} else {
+				final Conversation conversation = xmppConnectionService
+						.findOrCreateConversation(account, conferenceJid, true, true, true);
+				dialog.dismiss();
+				mCurrentDialog = null;
+				switchToConversation(conversation);
+			}
+		});
+	}
+
+	private void showCreateConferenceDialog() {
+		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		builder.setTitle(R.string.dialog_title_create_conference);
+		final View dialogView = getLayoutInflater().inflate(R.layout.create_conference_dialog, null);
+		final Spinner spinner = dialogView.findViewById(R.id.account);
+		final EditText subject = dialogView.findViewById(R.id.subject);
+		populateAccountSpinner(this, mActivatedAccounts, spinner);
+		builder.setView(dialogView);
+		builder.setPositiveButton(R.string.choose_participants, new OnClickListener() {
+			@Override
+			public void onClick(DialogInterface dialog, int which) {
+				if (!xmppConnectionServiceBound) {
+					return;
+				}
+				final Account account = getSelectedAccount(spinner);
+				if (account == null) {
+					return;
+				}
+				Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
+				intent.putExtra("multiple", true);
+				intent.putExtra("show_enter_jid", true);
+				intent.putExtra("subject", subject.getText().toString());
+				intent.putExtra(EXTRA_ACCOUNT, account.getJid().toBareJid().toString());
+				intent.putExtra(ChooseContactActivity.EXTRA_TITLE_RES_ID, R.string.choose_participants);
+				startActivityForResult(intent, REQUEST_CREATE_CONFERENCE);
+			}
+		});
+		builder.setNegativeButton(R.string.cancel, null);
+		mCurrentDialog = builder.create();
+		mCurrentDialog.show();
+	}
+
+	private Account getSelectedAccount(Spinner spinner) {
+		if (!spinner.isEnabled()) {
+			return null;
+		}
+		Jid jid;
+		try {
+			if (Config.DOMAIN_LOCK != null) {
+				jid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
+			} else {
+				jid = Jid.fromString((String) spinner.getSelectedItem());
+			}
+		} catch (final InvalidJidException e) {
+			return null;
+		}
+		return xmppConnectionService.findAccountByJid(jid);
+	}
+
+	protected void switchToConversation(Contact contact, String body) {
+		Conversation conversation = xmppConnectionService
+				.findOrCreateConversation(contact.getAccount(),
+						contact.getJid(), false, true);
+		switchToConversation(conversation, body, false);
+	}
+
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		getMenuInflater().inflate(R.menu.start_conversation, menu);
+		MenuItem menuHideOffline = menu.findItem(R.id.action_hide_offline);
+		MenuItem joinGroupChat = menu.findItem(R.id.action_join_conference);
+		ActionBar bar = getSupportActionBar();
+		joinGroupChat.setVisible(bar != null && bar.getSelectedNavigationIndex() == 1);
+		menuHideOffline.setChecked(this.mHideOfflineContacts);
+		mMenuSearchView = menu.findItem(R.id.action_search);
+		mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
+		View mSearchView = mMenuSearchView.getActionView();
+		mSearchEditText = mSearchView.findViewById(R.id.search_field);
+		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
+		mSearchEditText.setOnEditorActionListener(mSearchDone);
+		if (mInitialJid != null) {
+			MenuItemCompat.expandActionView(mMenuSearchView);
+			mSearchEditText.append(mInitialJid);
+			filter(mInitialJid);
+		}
+		return super.onCreateOptionsMenu(menu);
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch (item.getItemId()) {
+			case R.id.action_join_conference:
+				showJoinConferenceDialog(null);
+				return true;
+			case R.id.action_scan_qr_code:
+				UriHandlerActivity.scan(this);
+				return true;
+			case R.id.action_hide_offline:
+				mHideOfflineContacts = !item.isChecked();
+				getPreferences().edit().putBoolean("hide_offline", mHideOfflineContacts).commit();
+				if (mSearchEditText != null) {
+					filter(mSearchEditText.getText().toString());
+				}
+				invalidateOptionsMenu();
+		}
+		return super.onOptionsItemSelected(item);
+	}
+
+	@Override
+	public boolean onKeyUp(int keyCode, KeyEvent event) {
+		if (keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress()) {
+			openSearch();
+			return true;
+		}
+		int c = event.getUnicodeChar();
+		if (c > 32) {
+			if (mSearchEditText != null && !mSearchEditText.isFocused()) {
+				openSearch();
+				mSearchEditText.append(Character.toString((char) c));
+				return true;
+			}
+		}
+		return super.onKeyUp(keyCode, event);
+	}
+
+	private void openSearch() {
+		if (mMenuSearchView != null) {
+			mMenuSearchView.expandActionView();
+		}
+	}
+
+	@Override
+	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+		if (resultCode == RESULT_OK) {
+			if (xmppConnectionServiceBound) {
+				this.mPostponedActivityResult = null;
+				if (requestCode == REQUEST_CREATE_CONFERENCE) {
+					Account account = extractAccount(intent);
+					final String subject = intent.getStringExtra("subject");
+					List<Jid> jids = new ArrayList<>();
+					if (intent.getBooleanExtra("multiple", false)) {
+						String[] toAdd = intent.getStringArrayExtra("contacts");
+						for (String item : toAdd) {
+							try {
+								jids.add(Jid.fromString(item));
+							} catch (InvalidJidException e) {
+								//ignored
+							}
+						}
+					} else {
+						try {
+							jids.add(Jid.fromString(intent.getStringExtra("contact")));
+						} catch (Exception e) {
+							//ignored
+						}
+					}
+					if (account != null && jids.size() > 0) {
+						if (xmppConnectionService.createAdhocConference(account, subject, jids, mAdhocConferenceCallback)) {
+							mToast = Toast.makeText(this, R.string.creating_conference, Toast.LENGTH_LONG);
+							mToast.show();
+						}
+					}
+				}
+			} else {
+				this.mPostponedActivityResult = new Pair<>(requestCode, intent);
+			}
+		}
+		super.onActivityResult(requestCode, requestCode, intent);
+	}
+
+	private void askForContactsPermissions() {
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+			if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
+				if (mRequestedContactsPermission.compareAndSet(false, true)) {
+					if (shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) {
+						AlertDialog.Builder builder = new AlertDialog.Builder(this);
+						builder.setTitle(R.string.sync_with_contacts);
+						builder.setMessage(R.string.sync_with_contacts_long);
+						builder.setPositiveButton(R.string.next, new OnClickListener() {
+							@Override
+							public void onClick(DialogInterface dialog, int which) {
+								if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+									requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
+								}
+							}
+						});
+						if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+							builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
+								@Override
+								public void onDismiss(DialogInterface dialog) {
+									if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+										requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
+									}
+								}
+							});
+						}
+						builder.create().show();
+					} else {
+						requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);
+					}
+				}
+			}
+		}
+	}
+
+	@Override
+	public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+		if (grantResults.length > 0)
+			if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+				if (requestCode == REQUEST_SYNC_CONTACTS && xmppConnectionServiceBound) {
+					xmppConnectionService.loadPhoneContacts();
+				}
+			}
+	}
+
+	@Override
+	protected void onBackendConnected() {
+		if (mPostponedActivityResult != null) {
+			onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
+			this.mPostponedActivityResult = null;
+		}
+		this.mActivatedAccounts.clear();
+		for (Account account : xmppConnectionService.getAccounts()) {
+			if (account.getStatus() != Account.State.DISABLED) {
+				if (Config.DOMAIN_LOCK != null) {
+					this.mActivatedAccounts.add(account.getJid().getLocalpart());
+				} else {
+					this.mActivatedAccounts.add(account.getJid().toBareJid().toString());
+				}
+			}
+		}
+		final Intent intent = getIntent();
+		final ActionBar ab = getSupportActionBar();
+		boolean init = intent != null && intent.getBooleanExtra("init", false);
+		boolean noConversations = xmppConnectionService.getConversations().size() == 0;
+		if ((init || noConversations) && ab != null) {
+			ab.setDisplayShowHomeEnabled(false);
+			ab.setDisplayHomeAsUpEnabled(false);
+			ab.setHomeButtonEnabled(false);
+		}
+		this.mKnownHosts = xmppConnectionService.getKnownHosts();
+		this.mKnownConferenceHosts = xmppConnectionService.getKnownConferenceHosts();
+		if (this.mPendingInvite != null) {
+			mPendingInvite.invite();
+			this.mPendingInvite = null;
+			filter(null);
+		} else if (!handleIntent(getIntent())) {
+			if (mSearchEditText != null) {
+				filter(mSearchEditText.getText().toString());
+			} else {
+				filter(null);
+			}
+		} else {
+			filter(null);
+		}
+		setIntent(null);
+	}
+
+	protected boolean handleIntent(Intent intent) {
+		if (intent == null) {
+			return false;
+		}
+		final String inviteUri = intent.getStringExtra(WelcomeActivity.EXTRA_INVITE_URI);
+		if (inviteUri != null) {
+			Invite invite = new Invite(inviteUri);
+			if (invite.isJidValid()) {
+				return invite.invite();
+			}
+		}
+		if (intent.getAction() == null) {
+			return false;
+		}
+		switch (intent.getAction()) {
+			case Intent.ACTION_SENDTO:
+			case Intent.ACTION_VIEW:
+				Uri uri = intent.getData();
+				if (uri != null) {
+					Invite invite = new Invite(intent.getData(), false);
+					invite.account = intent.getStringExtra("account");
+					return invite.invite();
+				} else {
+					return false;
+				}
+		}
+		return false;
+	}
+
+	private boolean handleJid(Invite invite) {
+		List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid(), invite.account);
+		if (invite.isAction(XmppUri.ACTION_JOIN)) {
+			Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid());
+			if (muc != null) {
+				switchToConversation(muc, invite.getBody(), false);
+				return true;
+			} else {
+				showJoinConferenceDialog(invite.getJid().toBareJid().toString());
+				return false;
+			}
+		} else if (contacts.size() == 0) {
+			showCreateContactDialog(invite.getJid().toString(), invite);
+			return false;
+		} else if (contacts.size() == 1) {
+			Contact contact = contacts.get(0);
+			if (!invite.isSafeSource() && invite.hasFingerprints()) {
+				displayVerificationWarningDialog(contact, invite);
+			} else {
+				if (invite.hasFingerprints()) {
+					if (xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints())) {
+						Toast.makeText(this, R.string.verified_fingerprints, Toast.LENGTH_SHORT).show();
+					}
+				}
+				if (invite.account != null) {
+					xmppConnectionService.getShortcutService().report(contact);
+				}
+				switchToConversation(contact, invite.getBody());
+			}
+			return true;
+		} else {
+			if (mMenuSearchView != null) {
+				mMenuSearchView.expandActionView();
+				mSearchEditText.setText("");
+				mSearchEditText.append(invite.getJid().toString());
+				filter(invite.getJid().toString());
+			} else {
+				mInitialJid = invite.getJid().toString();
+			}
+			return true;
+		}
+	}
+
+	private void displayVerificationWarningDialog(final Contact contact, final Invite invite) {
+		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		builder.setTitle(R.string.verify_omemo_keys);
+		View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
+		final CheckBox isTrustedSource = (CheckBox) view.findViewById(R.id.trusted_source);
+		TextView warning = (TextView) view.findViewById(R.id.warning);
+		String jid = contact.getJid().toBareJid().toString();
+		SpannableString spannable = new SpannableString(getString(R.string.verifying_omemo_keys_trusted_source, jid, contact.getDisplayName()));
+		int start = spannable.toString().indexOf(jid);
+		if (start >= 0) {
+			spannable.setSpan(new TypefaceSpan("monospace"), start, start + jid.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+		}
+		warning.setText(spannable);
+		builder.setView(view);
+		builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
+			if (isTrustedSource.isChecked() && invite.hasFingerprints()) {
+				xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
+			}
+			switchToConversation(contact, invite.getBody());
+		});
+		builder.setNegativeButton(R.string.cancel, (dialog, which) -> StartConversationActivity.this.finish());
+		AlertDialog dialog = builder.create();
+		dialog.setCanceledOnTouchOutside(false);
+		dialog.setOnCancelListener(dialog1 -> StartConversationActivity.this.finish());
+		dialog.show();
+	}
+
+	protected void filter(String needle) {
+		if (xmppConnectionServiceBound) {
+			this.filterContacts(needle);
+			this.filterConferences(needle);
+		}
+	}
+
+	protected void filterContacts(String needle) {
+		this.contacts.clear();
+		for (Account account : xmppConnectionService.getAccounts()) {
+			if (account.getStatus() != Account.State.DISABLED) {
+				for (Contact contact : account.getRoster().getContacts()) {
+					Presence.Status s = contact.getShownStatus();
+					if (contact.showInRoster() && contact.match(this, needle)
+							&& (!this.mHideOfflineContacts
+							|| (needle != null && !needle.trim().isEmpty())
+							|| s.compareTo(Presence.Status.OFFLINE) < 0)) {
+						this.contacts.add(contact);
+					}
+				}
+			}
+		}
+		Collections.sort(this.contacts);
+		mContactsAdapter.notifyDataSetChanged();
+	}
+
+	protected void filterConferences(String needle) {
+		this.conferences.clear();
+		for (Account account : xmppConnectionService.getAccounts()) {
+			if (account.getStatus() != Account.State.DISABLED) {
+				for (Bookmark bookmark : account.getBookmarks()) {
+					if (bookmark.match(this, needle)) {
+						this.conferences.add(bookmark);
+					}
+				}
+			}
+		}
+		Collections.sort(this.conferences);
+		mConferenceAdapter.notifyDataSetChanged();
+	}
+
+	private void onTabChanged() {
+		@DrawableRes final int fabDrawable;
+		if (getSupportActionBar().getSelectedNavigationIndex() == 0) {
+			fabDrawable = R.drawable.ic_person_add_white_24dp;
+		} else {
+			fabDrawable = R.drawable.ic_group_add_white_24dp;
+		}
+		binding.fab.setImageResource(fabDrawable);
+		invalidateOptionsMenu();
+	}
+
+	@Override
+	public void OnUpdateBlocklist(final Status status) {
+		refreshUi();
+	}
+
+	@Override
+	protected void refreshUiReal() {
+		if (mSearchEditText != null) {
+			filter(mSearchEditText.getText().toString());
+		}
+	}
+
+	public static class MyListFragment extends ListFragment {
+		private AdapterView.OnItemClickListener mOnItemClickListener;
+		private int mResContextMenu;
+
+		public void setContextMenu(final int res) {
+			this.mResContextMenu = res;
+		}
+
+		@Override
+		public void onListItemClick(final ListView l, final View v, final int position, final long id) {
+			if (mOnItemClickListener != null) {
+				mOnItemClickListener.onItemClick(l, v, position, id);
+			}
+		}
+
+		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
+			this.mOnItemClickListener = l;
+		}
+
+		@Override
+		public void onViewCreated(@NonNull final View view, final Bundle savedInstanceState) {
+			super.onViewCreated(view, savedInstanceState);
+			registerForContextMenu(getListView());
+			getListView().setFastScrollEnabled(true);
+			getListView().setDivider(null);
+			getListView().setDividerHeight(0);
+		}
+
+		@Override
+		public void onCreateContextMenu(final ContextMenu menu, final View v,
+		                                final ContextMenuInfo menuInfo) {
+			super.onCreateContextMenu(menu, v, menuInfo);
+			final StartConversationActivity activity = (StartConversationActivity) getActivity();
+			if (activity == null) {
+				return;
+			}
+			activity.getMenuInflater().inflate(mResContextMenu, menu);
+			final AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
+			if (mResContextMenu == R.menu.conference_context) {
+				activity.conference_context_id = acmi.position;
+			} else if (mResContextMenu == R.menu.contact_context) {
+				activity.contact_context_id = acmi.position;
+				final Contact contact = (Contact) activity.contacts.get(acmi.position);
+				final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock);
+				final MenuItem showContactDetailsItem = menu.findItem(R.id.context_contact_details);
+				if (contact.isSelf()) {
+					showContactDetailsItem.setVisible(false);
+				}
+				XmppConnection xmpp = contact.getAccount().getXmppConnection();
+				if (xmpp != null && xmpp.getFeatures().blocking() && !contact.isSelf()) {
+					if (contact.isBlocked()) {
+						blockUnblockItem.setTitle(R.string.unblock_contact);
+					} else {
+						blockUnblockItem.setTitle(R.string.block_contact);
+					}
+				} else {
+					blockUnblockItem.setVisible(false);
+				}
+			}
+		}
+
+		@Override
+		public boolean onContextItemSelected(final MenuItem item) {
+			StartConversationActivity activity = (StartConversationActivity) getActivity();
+			if (activity == null) {
+				return true;
+			}
+			switch (item.getItemId()) {
+				case R.id.context_start_conversation:
+					activity.openConversationForContact();
+					break;
+				case R.id.context_contact_details:
+					activity.openDetailsForContact();
+					break;
+				case R.id.context_contact_block_unblock:
+					activity.toggleContactBlock();
+					break;
+				case R.id.context_delete_contact:
+					activity.deleteContact();
+					break;
+				case R.id.context_join_conference:
+					activity.openConversationForBookmark();
+					break;
+				case R.id.context_share_uri:
+					activity.shareBookmarkUri();
+					break;
+				case R.id.context_delete_conference:
+					activity.deleteConference();
+			}
+			return true;
+		}
+	}
+
+	public class ListPagerAdapter extends PagerAdapter {
+		FragmentManager fragmentManager;
+		MyListFragment[] fragments;
+
+		public ListPagerAdapter(FragmentManager fm) {
+			fragmentManager = fm;
+			fragments = new MyListFragment[2];
+		}
+
+		public void requestFocus(int pos) {
+			if (fragments.length > pos) {
+				fragments[pos].getListView().requestFocus();
+			}
+		}
+
+		@Override
+		public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
+			assert (0 <= position && position < fragments.length);
+			FragmentTransaction trans = fragmentManager.beginTransaction();
+			trans.remove(fragments[position]);
+			trans.commit();
+			fragments[position] = null;
+		}
+
+		@Override
+		public Fragment instantiateItem(@NonNull ViewGroup container, int position) {
+			Fragment fragment = getItem(position);
+			FragmentTransaction trans = fragmentManager.beginTransaction();
+			trans.add(container.getId(), fragment, "fragment:" + position);
+			trans.commit();
+			return fragment;
+		}
+
+		@Override
+		public int getCount() {
+			return fragments.length;
+		}
+
+		@Override
+		public boolean isViewFromObject(@NonNull View view, @NonNull Object fragment) {
+			return ((Fragment) fragment).getView() == view;
+		}
+
+		public Fragment getItem(int position) {
+			assert (0 <= position && position < fragments.length);
+			if (fragments[position] == null) {
+				final MyListFragment listFragment = new MyListFragment();
+				if (position == 1) {
+					listFragment.setListAdapter(mConferenceAdapter);
+					listFragment.setContextMenu(R.menu.conference_context);
+					listFragment.setOnListItemClickListener((arg0, arg1, p, arg3) -> openConversationForBookmark(p));
+				} else {
+
+					listFragment.setListAdapter(mContactsAdapter);
+					listFragment.setContextMenu(R.menu.contact_context);
+					listFragment.setOnListItemClickListener((arg0, arg1, p, arg3) -> openConversationForContact(p));
+				}
+				fragments[position] = listFragment;
+			}
+			return fragments[position];
+		}
+	}
+
+	private class Invite extends XmppUri {
+
+		public String account;
+
+		public Invite(final Uri uri) {
+			super(uri);
+		}
+
+		public Invite(final String uri) {
+			super(uri);
+		}
+
+		public Invite(Uri uri, boolean safeSource) {
+			super(uri, safeSource);
+		}
+
+		boolean invite() {
+			if (!isJidValid()) {
+				Toast.makeText(StartConversationActivity.this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
+				return false;
+			}
+			if (getJid() != null) {
+				return handleJid(this);
+			}
+			return false;
+		}
+	}
 }

src/main/res/menu/start_conversation.xml 🔗

@@ -15,7 +15,8 @@
     <item
         android:id="@+id/action_scan_qr_code"
         android:title="@string/scan_qr_code"
-        app:showAsAction="never"/>
+        android:icon="?attr/icon_scan_qr_code"
+        app:showAsAction="always"/>
 
     <item
         android:id="@+id/action_hide_offline"