diff options
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java | 4 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java | 2003 |
3 files changed, 1031 insertions, 977 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 606b6daa..56ed5c76 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -51,7 +51,6 @@ </activity> <activity android:name=".ui.StartConversationActivity" - android:configChanges="orientation|screenSize" android:label="@string/title_activity_start_conversation" android:launchMode="singleTask"> <intent-filter> diff --git a/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java b/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java index f77d9c0a..261f93b0 100644 --- a/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java +++ b/src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.ui; import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -120,8 +121,9 @@ public class EnterJidDialog { this.listener = listener; } - public void show() { + public Dialog show() { this.dialog.show(); this.dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(this.dialogOnClick); + return this.dialog; } } diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index ee380ea4..768961c1 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -7,7 +7,9 @@ import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.ActionBar.TabListener; import android.app.AlertDialog; +import android.app.Dialog; import android.app.Fragment; +import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.ListFragment; import android.app.PendingIntent; @@ -24,6 +26,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.support.v13.app.FragmentPagerAdapter; +import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.text.Editable; import android.text.TextWatcher; @@ -35,6 +38,7 @@ import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; @@ -78,979 +82,1028 @@ 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 Tab mContactsTab; - private Tab mConferencesTab; - private ViewPager mViewPager; - private MyListFragment mContactsListFragment = new MyListFragment(); - private List<ListItem> contacts = new ArrayList<>(); - private ArrayAdapter<ListItem> mContactsAdapter; - private MyListFragment mConferenceListFragment = new MyListFragment(); - private List<ListItem> conferences = new ArrayList<ListItem>(); - private ArrayAdapter<ListItem> mConferenceAdapter; - private List<String> mActivatedAccounts = new ArrayList<String>(); - 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 = 0x3b28cf; - private final int REQUEST_CREATE_CONFERENCE = 0x3b39da; - - private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() { - - @Override - public boolean onMenuItemActionExpand(MenuItem item) { - mSearchEditText.post(new Runnable() { - - @Override - public void run() { - 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 TabListener mTabListener = new TabListener() { - - @Override - public void onTabUnselected(Tab tab, FragmentTransaction ft) { - return; - } - - @Override - public void onTabSelected(Tab tab, FragmentTransaction ft) { - mViewPager.setCurrentItem(tab.getPosition()); - onTabChanged(); - } - - @Override - public void onTabReselected(Tab tab, FragmentTransaction ft) { - return; - } - }; - private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() { - @Override - public void onPageSelected(int position) { - if (getActionBar() != null) { - getActionBar().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) { - if (getActionBar().getSelectedNavigationIndex() == 0) { - if (contacts.size() == 1) { - openConversationForContact((Contact) contacts.get(0)); - } else { - hideKeyboard(); - mContactsListFragment.getListView().requestFocus(); - } - } else { - if (conferences.size() == 1) { - openConversationsForBookmark((Bookmark) conferences.get(0)); - } else { - hideKeyboard(); - mConferenceListFragment.getListView().requestFocus(); - } - } - 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(new Runnable() { - @Override - public void run() { - hideToast(); - switchToConversation(conversation); - } - }); - } - - @Override - public void error(final int errorCode, Conversation object) { - runOnUiThread(new Runnable() { - @Override - public void run() { - replaceToast(getString(errorCode)); - } - }); - } - - @Override - public void userInputRequried(PendingIntent pi, Conversation object) { - - } - }; - private Toast mToast; - - 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); - setContentView(R.layout.activity_start_conversation); - mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager); - ActionBar actionBar = getActionBar(); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - - mContactsTab = actionBar.newTab().setText(R.string.contacts) - .setTabListener(mTabListener); - mConferencesTab = actionBar.newTab().setText(R.string.conferences) - .setTabListener(mTabListener); - actionBar.addTab(mContactsTab); - actionBar.addTab(mConferencesTab); - - mViewPager.setOnPageChangeListener(mOnPageChangeListener); - mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) { - - @Override - public int getCount() { - return 2; - } - - @Override - public Fragment getItem(int position) { - if (position == 0) { - return mContactsListFragment; - } else { - return mConferenceListFragment; - } - } - }); - - mConferenceAdapter = new ListItemAdapter(this, conferences); - mConferenceListFragment.setListAdapter(mConferenceAdapter); - mConferenceListFragment.setContextMenu(R.menu.conference_context); - mConferenceListFragment - .setOnListItemClickListener(new OnItemClickListener() { - - @Override - public void onItemClick(AdapterView<?> arg0, View arg1, - int position, long arg3) { - openConversationForBookmark(position); - } - }); - - mContactsAdapter = new ListItemAdapter(this, contacts); - ((ListItemAdapter) mContactsAdapter).setOnTagClickedListener(this.mOnTagClickedListener); - mContactsListFragment.setListAdapter(mContactsAdapter); - mContactsListFragment.setContextMenu(R.menu.contact_context); - mContactsListFragment - .setOnListItemClickListener(new OnItemClickListener() { - - @Override - public void onItemClick(AdapterView<?> arg0, View arg1, - int position, long arg3) { - openConversationForContact(position); - } - }); - - this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false); - - } - - @Override - public void onStart() { - super.onStart(); - askForContactsPermissions(); - } - - 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); - 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 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); - conversation.setBookmark(bookmark); - if (!conversation.getMucOptions().online()) { - xmppConnectionService.joinMuc(conversation); - } - if (!bookmark.autojoin() && getPreferences().getBoolean("autojoin", true)) { - 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, xmppConnectionService, (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.unregisterConversation(); - 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 String fingerprint) { - EnterJidDialog dialog = new EnterJidDialog( - this, mKnownHosts, mActivatedAccounts, - getString(R.string.create_contact), getString(R.string.create), - prefilledJid, null, fingerprint == null - ); - - dialog.setOnEnterJidDialogPositiveListener(new EnterJidDialog.OnEnterJidDialogPositiveListener() { - @Override - public boolean onEnterJidDialogPositive(Jid accountJid, Jid contactJid) throws EnterJidDialog.JidError { - if (!xmppConnectionServiceBound) { - return false; - } - - final Account account = xmppConnectionService.findAccountByJid(accountJid); - if (account == null) { - return true; - } - - final Contact contact = account.getRoster().getContact(contactJid); - if (contact.showInRoster()) { - throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists)); - } else { - contact.addOtrFingerprint(fingerprint); - xmppConnectionService.createContact(contact); - switchToConversation(contact); - return true; - } - } - }); - - dialog.show(); - } - - @SuppressLint("InflateParams") - protected void showJoinConferenceDialog(final String prefilledJid) { - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.join_conference); - final View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null); - final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); - final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid); - final TextView jabberIdDesc = (TextView) 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(); - 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", true)); - 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); - conversation.setBookmark(bookmark); - if (!conversation.getMucOptions().online()) { - xmppConnectionService.joinMuc(conversation); - } - dialog.dismiss(); - switchToConversation(conversation); - } - } else { - final Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, - conferenceJid, true); - if (!conversation.getMucOptions().online()) { - xmppConnectionService.joinMuc(conversation); - } - dialog.dismiss(); - switchToConversation(conversation); - } - } - }); - } - - private void showCreateConferenceDialog() { - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.create_conference); - final View dialogView = getLayoutInflater().inflate(R.layout.create_conference_dialog, null); - final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); - final EditText subject = (EditText) 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); - builder.create().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) { - Conversation conversation = xmppConnectionService - .findOrCreateConversation(contact.getAccount(), - contact.getJid(), false); - switchToConversation(conversation); - } - - 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(new String[]{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 menuCreateContact = menu.findItem(R.id.action_create_contact); - MenuItem menuCreateConference = menu.findItem(R.id.action_conference); - 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 = (EditText) mSearchView - .findViewById(R.id.search_field); - mSearchEditText.addTextChangedListener(mSearchTextWatcher); - mSearchEditText.setOnEditorActionListener(mSearchDone); - if (getActionBar().getSelectedNavigationIndex() == 0) { - menuCreateConference.setVisible(false); - } else { - menuCreateContact.setVisible(false); - } - if (mInitialJid != null) { - mMenuSearchView.expandActionView(); - mSearchEditText.append(mInitialJid); - filter(mInitialJid); - } - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_create_contact: - showCreateContactDialog(null,null); - return true; - case R.id.action_join_conference: - showJoinConferenceDialog(null); - return true; - case R.id.action_create_conference: - showCreateConferenceDialog(); - return true; - case R.id.action_scan_qr_code: - new IntentIntegrator(this).initiateScan(); - 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 ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) { - IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); - if (scanResult != null && scanResult.getFormatName() != null) { - String data = scanResult.getContents(); - Invite invite = new Invite(data); - if (xmppConnectionServiceBound) { - invite.invite(); - } else if (invite.getJid() != null) { - this.mPendingInvite = invite; - } else { - this.mPendingInvite = null; - } - } - } else 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) { - 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, String permissions[], 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 = getActionBar(); - 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; - } else if (!handleIntent(getIntent())) { - if (mSearchEditText != null) { - filter(mSearchEditText.getText().toString()); - } else { - filter(null); - } - } - setIntent(null); - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - Invite getInviteJellyBean(NdefRecord record) { - return new Invite(record.toUri()); - } - - protected boolean handleIntent(Intent intent) { - if (intent == null || intent.getAction() == null) { - return false; - } - switch (intent.getAction()) { - case Intent.ACTION_SENDTO: - case Intent.ACTION_VIEW: - Uri uri = intent.getData(); - if (uri != null) { - Log.d(Config.LOGTAG, "received uri=" + intent.getData()); - return new Invite(intent.getData()).invite(); - } else { - return false; - } - case NfcAdapter.ACTION_NDEF_DISCOVERED: - for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) { - if (message instanceof NdefMessage) { - Log.d(Config.LOGTAG, "received message=" + message); - for (NdefRecord record : ((NdefMessage) message).getRecords()) { - switch (record.getTnf()) { - case NdefRecord.TNF_WELL_KNOWN: - if (Arrays.equals(record.getType(), NdefRecord.RTD_URI)) { - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - return getInviteJellyBean(record).invite(); - } else { - byte[] payload = record.getPayload(); - if (payload[0] == 0) { - return new Invite(Uri.parse(new String(Arrays.copyOfRange( - payload, 1, payload.length)))).invite(); - } - } - } - } - } - } - } - } - return false; - } - - private boolean handleJid(Invite invite) { - List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid()); - if (invite.isMuc()) { - Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid()); - if (muc != null) { - switchToConversation(muc); - return true; - } else { - showJoinConferenceDialog(invite.getJid().toBareJid().toString()); - return false; - } - } else if (contacts.size() == 0) { - showCreateContactDialog(invite.getJid().toString(),invite.getFingerprint()); - return false; - } else if (contacts.size() == 1) { - Contact contact = contacts.get(0); - if (invite.getFingerprint() != null) { - if (contact.addOtrFingerprint(invite.getFingerprint())) { - Log.d(Config.LOGTAG,"added new fingerprint"); - xmppConnectionService.syncRosterToDisk(contact.getAccount()); - } - } - switchToConversation(contact); - 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; - } - } - - 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() { - 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(final View view, final Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - registerForContextMenu(getListView()); - getListView().setFastScrollEnabled(true); - } - - @Override - public void onCreateContextMenu(final ContextMenu menu, final View v, - final ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - final StartConversationActivity activity = (StartConversationActivity) getActivity(); - 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 Blockable contact = (Contact) activity.contacts.get(acmi.position); - final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock); - XmppConnection xmpp = contact.getAccount().getXmppConnection(); - if (xmpp != null && xmpp.getFeatures().blocking()) { - 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(); - 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_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); - } - - boolean invite() { - if (getJid() != null) { - return handleJid(this); - } - return false; - } - - public boolean isMuc() { - return muc; - } - } + public int conference_context_id; + public int contact_context_id; + private Tab mContactsTab; + private Tab mConferencesTab; + private ViewPager mViewPager; + private ListPagerAdapter mListPagerAdapter; + private List<ListItem> contacts = new ArrayList<>(); + private ArrayAdapter<ListItem> mContactsAdapter; + private List<ListItem> conferences = new ArrayList<>(); + private ArrayAdapter<ListItem> 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 = 0x3b28cf; + private final int REQUEST_CREATE_CONFERENCE = 0x3b39da; + private Dialog mCurrentDialog = null; + + private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() { + + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + mSearchEditText.post(new Runnable() { + + @Override + public void run() { + 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 TabListener mTabListener = new TabListener() { + + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + return; + } + + @Override + public void onTabSelected(Tab tab, FragmentTransaction ft) { + mViewPager.setCurrentItem(tab.getPosition()); + onTabChanged(); + } + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + return; + } + }; + private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + if (getActionBar() != null) { + getActionBar().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 = getActionBar().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(new Runnable() { + @Override + public void run() { + hideToast(); + switchToConversation(conversation); + } + }); + } + + @Override + public void error(final int errorCode, Conversation object) { + runOnUiThread(new Runnable() { + @Override + public void run() { + replaceToast(getString(errorCode)); + } + }); + } + + @Override + public void userInputRequried(PendingIntent pi, Conversation object) { + + } + }; + private Toast mToast; + + 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); + setContentView(R.layout.activity_start_conversation); + mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager); + ActionBar actionBar = getActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + + mContactsTab = actionBar.newTab().setText(R.string.contacts) + .setTabListener(mTabListener); + mConferencesTab = actionBar.newTab().setText(R.string.conferences) + .setTabListener(mTabListener); + actionBar.addTab(mContactsTab); + actionBar.addTab(mConferencesTab); + + mViewPager.setOnPageChangeListener(mOnPageChangeListener); + mListPagerAdapter = new ListPagerAdapter(getFragmentManager()); + mViewPager.setAdapter(mListPagerAdapter); + + mConferenceAdapter = new ListItemAdapter(this, conferences); + mContactsAdapter = new ListItemAdapter(this, contacts); + ((ListItemAdapter) mContactsAdapter).setOnTagClickedListener(this.mOnTagClickedListener); + this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false); + + } + + @Override + public void onStart() { + super.onStart(); + askForContactsPermissions(); + } + + @Override + public void onStop() { + if (mCurrentDialog != null) { + mCurrentDialog.dismiss(); + } + super.onStop(); + } + + 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); + 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 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); + conversation.setBookmark(bookmark); + if (!conversation.getMucOptions().online()) { + xmppConnectionService.joinMuc(conversation); + } + if (!bookmark.autojoin() && getPreferences().getBoolean("autojoin", true)) { + 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, xmppConnectionService, (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.unregisterConversation(); + 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 String fingerprint) { + EnterJidDialog dialog = new EnterJidDialog( + this, mKnownHosts, mActivatedAccounts, + getString(R.string.create_contact), getString(R.string.create), + prefilledJid, null, fingerprint == null + ); + + dialog.setOnEnterJidDialogPositiveListener(new EnterJidDialog.OnEnterJidDialogPositiveListener() { + @Override + public boolean onEnterJidDialogPositive(Jid accountJid, Jid contactJid) throws EnterJidDialog.JidError { + if (!xmppConnectionServiceBound) { + return false; + } + + final Account account = xmppConnectionService.findAccountByJid(accountJid); + if (account == null) { + return true; + } + + final Contact contact = account.getRoster().getContact(contactJid); + if (contact.showInRoster()) { + throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists)); + } else { + contact.addOtrFingerprint(fingerprint); + xmppConnectionService.createContact(contact); + switchToConversation(contact); + 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.join_conference); + final View dialogView = getLayoutInflater().inflate(R.layout.join_conference_dialog, null); + final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); + final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid); + final TextView jabberIdDesc = (TextView) 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", true)); + 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); + conversation.setBookmark(bookmark); + if (!conversation.getMucOptions().online()) { + xmppConnectionService.joinMuc(conversation); + } + dialog.dismiss(); + mCurrentDialog = null; + switchToConversation(conversation); + } + } else { + final Conversation conversation = xmppConnectionService + .findOrCreateConversation(account, + conferenceJid, true); + if (!conversation.getMucOptions().online()) { + xmppConnectionService.joinMuc(conversation); + } + dialog.dismiss(); + mCurrentDialog = null; + switchToConversation(conversation); + } + } + }); + } + + private void showCreateConferenceDialog() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.create_conference); + final View dialogView = getLayoutInflater().inflate(R.layout.create_conference_dialog, null); + final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account); + final EditText subject = (EditText) 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) { + Conversation conversation = xmppConnectionService + .findOrCreateConversation(contact.getAccount(), + contact.getJid(), false); + switchToConversation(conversation); + } + + 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(new String[]{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 menuCreateContact = menu.findItem(R.id.action_create_contact); + MenuItem menuCreateConference = menu.findItem(R.id.action_conference); + 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 = (EditText) mSearchView + .findViewById(R.id.search_field); + mSearchEditText.addTextChangedListener(mSearchTextWatcher); + mSearchEditText.setOnEditorActionListener(mSearchDone); + if (getActionBar().getSelectedNavigationIndex() == 0) { + menuCreateConference.setVisible(false); + } else { + menuCreateContact.setVisible(false); + } + if (mInitialJid != null) { + mMenuSearchView.expandActionView(); + mSearchEditText.append(mInitialJid); + filter(mInitialJid); + } + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_create_contact: + showCreateContactDialog(null, null); + return true; + case R.id.action_join_conference: + showJoinConferenceDialog(null); + return true; + case R.id.action_create_conference: + showCreateConferenceDialog(); + return true; + case R.id.action_scan_qr_code: + new IntentIntegrator(this).initiateScan(); + 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 ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) { + IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); + if (scanResult != null && scanResult.getFormatName() != null) { + String data = scanResult.getContents(); + Invite invite = new Invite(data); + if (xmppConnectionServiceBound) { + invite.invite(); + } else if (invite.getJid() != null) { + this.mPendingInvite = invite; + } else { + this.mPendingInvite = null; + } + } + } else 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) { + 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, String permissions[], 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 = getActionBar(); + 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; + } else if (!handleIntent(getIntent())) { + if (mSearchEditText != null) { + filter(mSearchEditText.getText().toString()); + } else { + filter(null); + } + } + setIntent(null); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + Invite getInviteJellyBean(NdefRecord record) { + return new Invite(record.toUri()); + } + + protected boolean handleIntent(Intent intent) { + if (intent == null || intent.getAction() == null) { + return false; + } + switch (intent.getAction()) { + case Intent.ACTION_SENDTO: + case Intent.ACTION_VIEW: + Uri uri = intent.getData(); + if (uri != null) { + Log.d(Config.LOGTAG, "received uri=" + intent.getData()); + return new Invite(intent.getData()).invite(); + } else { + return false; + } + case NfcAdapter.ACTION_NDEF_DISCOVERED: + for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) { + if (message instanceof NdefMessage) { + Log.d(Config.LOGTAG, "received message=" + message); + for (NdefRecord record : ((NdefMessage) message).getRecords()) { + switch (record.getTnf()) { + case NdefRecord.TNF_WELL_KNOWN: + if (Arrays.equals(record.getType(), NdefRecord.RTD_URI)) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + return getInviteJellyBean(record).invite(); + } else { + byte[] payload = record.getPayload(); + if (payload[0] == 0) { + return new Invite(Uri.parse(new String(Arrays.copyOfRange( + payload, 1, payload.length)))).invite(); + } + } + } + } + } + } + } + } + return false; + } + + private boolean handleJid(Invite invite) { + List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid()); + if (invite.isMuc()) { + Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid()); + if (muc != null) { + switchToConversation(muc); + return true; + } else { + showJoinConferenceDialog(invite.getJid().toBareJid().toString()); + return false; + } + } else if (contacts.size() == 0) { + showCreateContactDialog(invite.getJid().toString(), invite.getFingerprint()); + return false; + } else if (contacts.size() == 1) { + Contact contact = contacts.get(0); + if (invite.getFingerprint() != null) { + if (contact.addOtrFingerprint(invite.getFingerprint())) { + Log.d(Config.LOGTAG, "added new fingerprint"); + xmppConnectionService.syncRosterToDisk(contact.getAccount()); + } + } + switchToConversation(contact); + 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; + } + } + + 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() { + invalidateOptionsMenu(); + } + + @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(ViewGroup container, int position, 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(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(View view, 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(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView<?> arg0, View arg1, + int position, long arg3) { + openConversationForBookmark(position); + } + }); + } else { + + listFragment.setListAdapter(mContactsAdapter); + listFragment.setContextMenu(R.menu.contact_context); + listFragment.setOnListItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView<?> arg0, View arg1, + int position, long arg3) { + openConversationForContact(position); + } + }); + } + 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(final View view, final Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + registerForContextMenu(getListView()); + getListView().setFastScrollEnabled(true); + } + + @Override + public void onCreateContextMenu(final ContextMenu menu, final View v, + final ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + final StartConversationActivity activity = (StartConversationActivity) getActivity(); + 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 Blockable contact = (Contact) activity.contacts.get(acmi.position); + final MenuItem blockUnblockItem = menu.findItem(R.id.context_contact_block_unblock); + XmppConnection xmpp = contact.getAccount().getXmppConnection(); + if (xmpp != null && xmpp.getFeatures().blocking()) { + 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(); + 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_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); + } + + boolean invite() { + if (getJid() != null) { + return handleJid(this); + } + return false; + } + + public boolean isMuc() { + return muc; + } + } } |