Detailed changes
@@ -18,8 +18,7 @@ import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Conversation;
public final class BlockContactDialog {
- public static void show(final XmppActivity xmppActivity,
- final Blockable blockable) {
+ public static void show(final XmppActivity xmppActivity, final Blockable blockable) {
final AlertDialog.Builder builder = new AlertDialog.Builder(xmppActivity);
final boolean isBlocked = blockable.isBlocked();
builder.setNegativeButton(R.string.cancel, null);
@@ -6,23 +6,17 @@ import android.app.FragmentTransaction;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
-import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
-import android.provider.MediaStore;
import android.provider.Settings;
import android.support.v4.widget.SlidingPaneLayout;
import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
import android.support.v7.app.ActionBar;
import android.util.Log;
import android.util.Pair;
-import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
@@ -31,10 +25,8 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
import android.widget.Toast;
-import org.openintents.openpgp.util.OpenPgpApi;
import java.util.ArrayList;
import java.util.Iterator;
@@ -48,18 +40,14 @@ import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Blockable;
-import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
-import eu.siacs.conversations.entities.Transferable;
-import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.ui.service.EmojiService;
-import eu.siacs.conversations.ui.util.SendButtonAction;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.XmppConnection;
@@ -69,8 +57,6 @@ import eu.siacs.conversations.xmpp.jid.Jid;
public class ConversationActivity extends XmppActivity
implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast {
- public static final String RECENTLY_USED_QUICK_ACTION = "recently_used_quick_action";
-
public static final String ACTION_VIEW_CONVERSATION = "eu.siacs.conversations.action.VIEW";
public static final String CONVERSATION = "conversationUuid";
public static final String EXTRA_DOWNLOAD_UUID = "eu.siacs.conversations.download_uuid";
@@ -78,20 +64,6 @@ public class ConversationActivity extends XmppActivity
public static final String NICK = "nick";
public static final String PRIVATE_MESSAGE = "pm";
- public static final int REQUEST_SEND_MESSAGE = 0x0201;
- public static final int REQUEST_DECRYPT_PGP = 0x0202;
- public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
- public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208;
- public static final int REQUEST_TRUST_KEYS_MENU = 0x0209;
- public static final int REQUEST_START_DOWNLOAD = 0x0210;
- public static final int REQUEST_ADD_EDITOR_CONTENT = 0x0211;
- public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
- public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
- public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
- public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304;
- public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305;
- public static final int ATTACHMENT_CHOICE_INVALID = 0x0306;
- public static final int ATTACHMENT_CHOICE_RECORD_VIDEO = 0x0307;
private static final String STATE_OPEN_CONVERSATION = "state_open_conversation";
private static final String STATE_PANEL_OPEN = "state_panel_open";
private static final String STATE_PENDING_URI = "state_pending_uri";
@@ -102,17 +74,10 @@ public class ConversationActivity extends XmppActivity
private boolean mPanelOpen = true;
private AtomicBoolean mShouldPanelBeOpen = new AtomicBoolean(false);
private Pair<Integer, Integer> mScrollPosition = null;
- final private List<Uri> mPendingImageUris = new ArrayList<>();
- final private List<Uri> mPendingFileUris = new ArrayList<>();
- private Uri mPendingGeoUri = null;
private boolean forbidProcessingPendings = false;
- private Message mPendingDownloadableMessage = null;
private boolean conversationWasSelectedByKeyboard = false;
- private boolean showSoundRecorderAttachment = false;
- private boolean showLocationAttachment = false;
-
private View mContentView;
private List<Conversation> conversationList = new ArrayList<>();
@@ -125,9 +90,7 @@ public class ConversationActivity extends XmppActivity
private boolean mActivityPaused = false;
private AtomicBoolean mRedirected = new AtomicBoolean(false);
- private Pair<Integer, Intent> mPostponedActivityResult;
private boolean mUnprocessedNewIntent = false;
- public Uri mPendingEditorContent = null;
public Conversation getSelectedConversation() {
return this.mSelectedConversation;
@@ -193,12 +156,6 @@ public class ConversationActivity extends XmppActivity
} else {
mScrollPosition = null;
}
- String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
- if (pending != null) {
- Log.d(Config.LOGTAG, "ConversationsActivity.onCreate() - restoring pending image uri");
- mPendingImageUris.clear();
- mPendingImageUris.add(Uri.parse(pending));
- }
}
setContentView(R.layout.fragment_conversations_overview);
@@ -395,271 +352,10 @@ public class ConversationActivity extends XmppActivity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.conversations, menu);
- final MenuItem menuSecure = menu.findItem(R.id.action_security);
- final MenuItem menuArchive = menu.findItem(R.id.action_archive);
- final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
- final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
- final MenuItem menuAttach = menu.findItem(R.id.action_attach_file);
- final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history);
- final MenuItem menuAdd = menu.findItem(R.id.action_add);
- final MenuItem menuInviteContact = menu.findItem(R.id.action_invite);
- final MenuItem menuMute = menu.findItem(R.id.action_mute);
- final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
- final MenuItem menuAttachSoundRecorder = menu.findItem(R.id.attach_record_voice);
- final MenuItem menuAttachLocation = menu.findItem(R.id.attach_location);
-
- if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) {
- menuArchive.setVisible(false);
- menuMucDetails.setVisible(false);
- menuContactDetails.setVisible(false);
- menuSecure.setVisible(false);
- menuInviteContact.setVisible(false);
- menuAttach.setVisible(false);
- menuClearHistory.setVisible(false);
- menuMute.setVisible(false);
- menuUnmute.setVisible(false);
- } else {
- menuAdd.setVisible(!isConversationsOverviewHideable());
- if (this.getSelectedConversation() != null) {
- if (this.getSelectedConversation().getNextEncryption() != Message.ENCRYPTION_NONE) {
- menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
- }
- if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
- menuContactDetails.setVisible(false);
- menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating());
- menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite());
- menuSecure.setVisible((Config.supportOpenPgp() || Config.supportOmemo()) && Config.multipleEncryptionChoices()); //only if pgp is supported we have a choice
- } else {
- menuContactDetails.setVisible(!this.getSelectedConversation().withSelf());
- menuMucDetails.setVisible(false);
- menuSecure.setVisible(Config.multipleEncryptionChoices());
- menuInviteContact.setVisible(xmppConnectionService != null && xmppConnectionService.findConferenceServer(getSelectedConversation().getAccount()) != null);
- }
- if (this.getSelectedConversation().isMuted()) {
- menuMute.setVisible(false);
- } else {
- menuUnmute.setVisible(false);
- }
- menuAttachLocation.setVisible(showLocationAttachment);
- menuAttachSoundRecorder.setVisible(showSoundRecorderAttachment);
- configureEncryptionMenu(getSelectedConversation(), menu);
- }
- }
+ getMenuInflater().inflate(R.menu.activity_conversations, menu);
return super.onCreateOptionsMenu(menu);
}
- private static void configureEncryptionMenu(Conversation conversation, Menu menu) {
- MenuItem none = menu.findItem(R.id.encryption_choice_none);
- MenuItem pgp = menu.findItem(R.id.encryption_choice_pgp);
- MenuItem axolotl = menu.findItem(R.id.encryption_choice_axolotl);
- pgp.setVisible(Config.supportOpenPgp());
- none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
- axolotl.setVisible(Config.supportOmemo());
- final AxolotlService axolotlService = conversation.getAccount().getAxolotlService();
- if (axolotlService == null || !axolotlService.isConversationAxolotlCapable(conversation)) {
- axolotl.setEnabled(false);
- }
- switch (conversation.getNextEncryption()) {
- case Message.ENCRYPTION_NONE:
- none.setChecked(true);
- break;
- case Message.ENCRYPTION_PGP:
- pgp.setChecked(true);
- break;
- case Message.ENCRYPTION_AXOLOTL:
- axolotl.setChecked(true);
- break;
- default:
- none.setChecked(true);
- break;
- }
- }
-
- protected void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) {
- final Conversation conversation = getSelectedConversation();
- final Account account = conversation.getAccount();
- final OnPresenceSelected callback = () -> {
- Intent intent = new Intent();
- boolean chooser = false;
- String fallbackPackageId = null;
- switch (attachmentChoice) {
- case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
- intent.setAction(Intent.ACTION_GET_CONTENT);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
- }
- intent.setType("image/*");
- chooser = true;
- break;
- case ATTACHMENT_CHOICE_RECORD_VIDEO:
- intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
- break;
- case ATTACHMENT_CHOICE_TAKE_PHOTO:
- Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri();
- mPendingImageUris.clear();
- mPendingImageUris.add(uri);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
- intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
- break;
- case ATTACHMENT_CHOICE_CHOOSE_FILE:
- chooser = true;
- intent.setType("*/*");
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setAction(Intent.ACTION_GET_CONTENT);
- break;
- case ATTACHMENT_CHOICE_RECORD_VOICE:
- intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
- fallbackPackageId = "eu.siacs.conversations.voicerecorder";
- break;
- case ATTACHMENT_CHOICE_LOCATION:
- intent.setAction("eu.siacs.conversations.location.request");
- fallbackPackageId = "eu.siacs.conversations.sharelocation";
- break;
- }
- if (intent.resolveActivity(getPackageManager()) != null) {
- if (chooser) {
- startActivityForResult(
- Intent.createChooser(intent, getString(R.string.perform_action_with)),
- attachmentChoice);
- } else {
- startActivityForResult(intent, attachmentChoice);
- }
- } else if (fallbackPackageId != null) {
- startActivity(getInstallApkIntent(fallbackPackageId));
- }
- };
- if (account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) {
- conversation.setNextCounterpart(null);
- callback.onPresenceSelected();
- } else {
- selectPresence(conversation, callback);
- }
- }
-
- private Intent getInstallApkIntent(final String packageId) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse("market://details?id=" + packageId));
- if (intent.resolveActivity(getPackageManager()) != null) {
- return intent;
- } else {
- intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId));
- return intent;
- }
- }
-
- public void attachFile(final int attachmentChoice) {
- if (attachmentChoice != ATTACHMENT_CHOICE_LOCATION) {
- if (!Config.ONLY_INTERNAL_STORAGE && !hasStoragePermission(attachmentChoice)) {
- return;
- }
- }
- try {
- getPreferences().edit()
- .putString(RECENTLY_USED_QUICK_ACTION, SendButtonAction.of(attachmentChoice).toString())
- .apply();
- } catch (IllegalArgumentException e) {
- //just do not save
- }
- final Conversation conversation = getSelectedConversation();
- final int encryption = conversation.getNextEncryption();
- final int mode = conversation.getMode();
- if (encryption == Message.ENCRYPTION_PGP) {
- if (hasPgp()) {
- if (mode == Conversation.MODE_SINGLE && conversation.getContact().getPgpKeyId() != 0) {
- xmppConnectionService.getPgpEngine().hasKey(
- conversation.getContact(),
- new UiCallback<Contact>() {
-
- @Override
- public void userInputRequried(PendingIntent pi, Contact contact) {
- ConversationActivity.this.runIntent(pi, attachmentChoice);
- }
-
- @Override
- public void success(Contact contact) {
- selectPresenceToAttachFile(attachmentChoice, encryption);
- }
-
- @Override
- public void error(int error, Contact contact) {
- replaceToast(getString(error));
- }
- });
- } else if (mode == Conversation.MODE_MULTI && conversation.getMucOptions().pgpKeysInUse()) {
- if (!conversation.getMucOptions().everybodyHasKeys()) {
- Toast warning = Toast
- .makeText(this,
- R.string.missing_public_keys,
- Toast.LENGTH_LONG);
- warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
- warning.show();
- }
- selectPresenceToAttachFile(attachmentChoice, encryption);
- } else {
- final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
- .findFragmentByTag("conversation");
- if (fragment != null) {
- fragment.showNoPGPKeyDialog(false,
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- conversation.setNextEncryption(Message.ENCRYPTION_NONE);
- xmppConnectionService.updateConversation(conversation);
- selectPresenceToAttachFile(attachmentChoice, Message.ENCRYPTION_NONE);
- }
- });
- }
- }
- } else {
- showInstallPgpDialog();
- }
- } else {
- if (encryption != Message.ENCRYPTION_AXOLOTL || !trustKeysIfNeeded(REQUEST_TRUST_KEYS_MENU, attachmentChoice)) {
- selectPresenceToAttachFile(attachmentChoice, encryption);
- }
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
- if (grantResults.length > 0)
- if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- if (requestCode == REQUEST_START_DOWNLOAD) {
- if (this.mPendingDownloadableMessage != null) {
- startDownloadable(this.mPendingDownloadableMessage);
- }
- } else if (requestCode == REQUEST_ADD_EDITOR_CONTENT) {
- if (this.mPendingEditorContent != null) {
- attachImageToConversation(this.mPendingEditorContent);
- }
- } else {
- attachFile(requestCode);
- }
- } else {
- Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
- }
- }
-
- public void startDownloadable(Message message) {
- if (!Config.ONLY_INTERNAL_STORAGE && !hasStoragePermission(ConversationActivity.REQUEST_START_DOWNLOAD)) {
- this.mPendingDownloadableMessage = message;
- return;
- }
- Transferable transferable = message.getTransferable();
- if (transferable != null) {
- if (!transferable.start()) {
- Toast.makeText(this, R.string.not_connected_try_again, Toast.LENGTH_SHORT).show();
- }
- } else if (message.treatAsDownloadable()) {
- xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, true);
- }
- }
-
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == android.R.id.home) {
@@ -668,56 +364,6 @@ public class ConversationActivity extends XmppActivity
} else if (item.getItemId() == R.id.action_add) {
startActivity(new Intent(this, StartConversationActivity.class));
return true;
- } else if (getSelectedConversation() != null) {
- switch (item.getItemId()) {
- case R.id.encryption_choice_axolotl:
- case R.id.encryption_choice_pgp:
- case R.id.encryption_choice_none:
- handleEncryptionSelection(item);
- break;
- case R.id.attach_choose_picture:
- case R.id.attach_take_picture:
- case R.id.attach_record_video:
- case R.id.attach_choose_file:
- case R.id.attach_record_voice:
- case R.id.attach_location:
- handleAttachmentSelection(item);
- break;
- case R.id.action_archive:
- this.endConversation(getSelectedConversation());
- break;
- case R.id.action_contact_details:
- switchToContactDetails(getSelectedConversation().getContact());
- break;
- case R.id.action_muc_details:
- Intent intent = new Intent(this,
- ConferenceDetailsActivity.class);
- intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
- intent.putExtra("uuid", getSelectedConversation().getUuid());
- startActivity(intent);
- break;
- case R.id.action_invite:
- inviteToConversation(getSelectedConversation());
- break;
- case R.id.action_clear_history:
- clearHistoryDialog(getSelectedConversation());
- break;
- case R.id.action_mute:
- muteConversationDialog(getSelectedConversation());
- break;
- case R.id.action_unmute:
- unmuteConversation(getSelectedConversation());
- break;
- case R.id.action_block:
- BlockContactDialog.show(this, getSelectedConversation());
- break;
- case R.id.action_unblock:
- BlockContactDialog.show(this, getSelectedConversation());
- break;
- default:
- break;
- }
- return super.onOptionsItemSelected(item);
} else {
return super.onOptionsItemSelected(item);
}
@@ -748,116 +394,6 @@ public class ConversationActivity extends XmppActivity
}
}
- @SuppressLint("InflateParams")
- protected void clearHistoryDialog(final Conversation conversation) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.clear_conversation_history));
- final View dialogView = getLayoutInflater().inflate(R.layout.dialog_clear_history, null);
- final CheckBox endConversationCheckBox = dialogView.findViewById(R.id.end_conversation_checkbox);
- builder.setView(dialogView);
- builder.setNegativeButton(getString(R.string.cancel), null);
- builder.setPositiveButton(getString(R.string.delete_messages), (dialog, which) -> {
- ConversationActivity.this.xmppConnectionService.clearConversationHistory(conversation);
- if (endConversationCheckBox.isChecked()) {
- endConversation(conversation);
- } else {
- updateConversationList();
- ConversationActivity.this.mConversationFragment.updateMessages();
- }
- });
- builder.create().show();
- }
-
- private void handleAttachmentSelection(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.attach_choose_picture:
- attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
- break;
- case R.id.attach_take_picture:
- attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
- break;
- case R.id.attach_record_video:
- attachFile(ATTACHMENT_CHOICE_RECORD_VIDEO);
- break;
- case R.id.attach_choose_file:
- attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE);
- break;
- case R.id.attach_record_voice:
- attachFile(ATTACHMENT_CHOICE_RECORD_VOICE);
- break;
- case R.id.attach_location:
- attachFile(ATTACHMENT_CHOICE_LOCATION);
- break;
- }
- }
-
- private void handleEncryptionSelection(MenuItem item) {
- Conversation conversation = getSelectedConversation();
- if (conversation == null) {
- return;
- }
- final ConversationFragment fragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
- switch (item.getItemId()) {
- case R.id.encryption_choice_none:
- conversation.setNextEncryption(Message.ENCRYPTION_NONE);
- item.setChecked(true);
- break;
- case R.id.encryption_choice_pgp:
- if (hasPgp()) {
- if (conversation.getAccount().getPgpSignature() != null) {
- conversation.setNextEncryption(Message.ENCRYPTION_PGP);
- item.setChecked(true);
- } else {
- announcePgp(conversation.getAccount(), conversation, null, onOpenPGPKeyPublished);
- }
- } else {
- showInstallPgpDialog();
- }
- break;
- case R.id.encryption_choice_axolotl:
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(conversation.getAccount())
- + "Enabled axolotl for Contact " + conversation.getContact().getJid());
- conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL);
- item.setChecked(true);
- break;
- default:
- conversation.setNextEncryption(Message.ENCRYPTION_NONE);
- break;
- }
- xmppConnectionService.updateConversation(conversation);
- fragment.updateChatMsgHint();
- invalidateOptionsMenu();
- refreshUi();
- }
-
- protected void muteConversationDialog(final Conversation conversation) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.disable_notifications);
- final int[] durations = getResources().getIntArray(R.array.mute_options_durations);
- builder.setItems(R.array.mute_options_descriptions, (dialog, which) -> {
- final long till;
- if (durations[which] == -1) {
- till = Long.MAX_VALUE;
- } else {
- till = System.currentTimeMillis() + (durations[which] * 1000);
- }
- conversation.setMutedTill(till);
- ConversationActivity.this.xmppConnectionService.updateConversation(conversation);
- updateConversationList();
- ConversationActivity.this.mConversationFragment.updateMessages();
- invalidateOptionsMenu();
- });
- builder.create().show();
- }
-
- public void unmuteConversation(final Conversation conversation) {
- conversation.setMutedTill(0);
- this.xmppConnectionService.updateConversation(conversation);
- updateConversationList();
- ConversationActivity.this.mConversationFragment.updateMessages();
- invalidateOptionsMenu();
- }
-
@Override
public void onBackPressed() {
if (!isConversationsOverviewVisable()) {
@@ -1025,11 +561,6 @@ public class ConversationActivity extends XmppActivity
if (!isConversationsOverviewVisable() || !isConversationsOverviewHideable()) {
sendReadMarkerIfNecessary(getSelectedConversation());
}
- new Handler().post(() -> {
- showSoundRecorderAttachment = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION).resolveActivity(getPackageManager()) != null;
- showLocationAttachment = new Intent("eu.siacs.conversations.location.request").resolveActivity(getPackageManager()) != null;
- invalidateOptionsMenu();
- });
}
@Override
@@ -1046,20 +577,17 @@ public class ConversationActivity extends XmppActivity
savedInstanceState.remove(STATE_OPEN_CONVERSATION);
}
savedInstanceState.putBoolean(STATE_PANEL_OPEN, isConversationsOverviewVisable());
- if (this.mPendingImageUris.size() >= 1) {
+ /*if (this.mPendingImageUris.size() >= 1) {
Log.d(Config.LOGTAG, "ConversationsActivity.onSaveInstanceState() - saving pending image uri");
savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString());
} else {
savedInstanceState.remove(STATE_PENDING_URI);
- }
+ }*/
super.onSaveInstanceState(savedInstanceState);
}
private void clearPending() {
- mPendingImageUris.clear();
- mPendingFileUris.clear();
- mPendingGeoUri = null;
- mPostponedActivityResult = null;
+ mConversationFragment.clearPending();
}
private void redirectToStartConversationActivity(boolean noAnimation) {
@@ -1142,30 +670,7 @@ public class ConversationActivity extends XmppActivity
this.mConversationFragment.setupIme();
}
- if (this.mPostponedActivityResult != null) {
- this.onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
- }
-
- final boolean stopping = isStopping();
-
- if (!forbidProcessingPendings) {
- for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
- Uri foo = i.next();
- Log.d(Config.LOGTAG, "ConversationsActivity.onBackendConnected() - attaching image to conversations. stopping=" + Boolean.toString(stopping));
- attachImageToConversation(getSelectedConversation(), foo);
- }
-
- for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
- Log.d(Config.LOGTAG, "ConversationsActivity.onBackendConnected() - attaching file to conversations. stopping=" + Boolean.toString(stopping));
- attachFileToConversation(getSelectedConversation(), i.next());
- }
-
- if (mPendingGeoUri != null) {
- attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
- mPendingGeoUri = null;
- }
- }
- forbidProcessingPendings = false;
+ mConversationFragment.onBackendConnected();
if (!ExceptionHelper.checkForCrash(this, this.xmppConnectionService) && !mRedirected.get()) {
openBatteryOptimizationDialogIfNeeded();
@@ -1225,7 +730,7 @@ public class ConversationActivity extends XmppActivity
if (downloadUuid != null) {
final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid);
if (message != null) {
- startDownloadable(message);
+ //startDownloadable(message);
}
}
} else {
@@ -1252,134 +757,17 @@ public class ConversationActivity extends XmppActivity
xmppConnectionService.getNotificationService().setOpenConversation(null);
}
- @SuppressLint("NewApi")
- private static List<Uri> extractUriFromIntent(final Intent intent) {
- List<Uri> uris = new ArrayList<>();
- if (intent == null) {
- return uris;
- }
- Uri uri = intent.getData();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) {
- final ClipData clipData = intent.getClipData();
- if (clipData != null) {
- for (int i = 0; i < clipData.getItemCount(); ++i) {
- uris.add(clipData.getItemAt(i).getUri());
- }
- }
- } else {
- uris.add(uri);
- }
- return uris;
- }
-
@Override
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- if (resultCode == RESULT_OK) {
- if (requestCode == REQUEST_DECRYPT_PGP) {
- mConversationFragment.onActivityResult(requestCode, resultCode, data);
- } else if (requestCode == REQUEST_CHOOSE_PGP_ID) {
- // the user chose OpenPGP for encryption and selected his key in the PGP provider
- if (xmppConnectionServiceBound) {
- if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) {
- // associate selected PGP keyId with the account
- mSelectedConversation.getAccount().setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID));
- // we need to announce the key as described in XEP-027
- announcePgp(mSelectedConversation.getAccount(), null, null, onOpenPGPKeyPublished);
- } else {
- choosePgpSignId(mSelectedConversation.getAccount());
- }
- this.mPostponedActivityResult = null;
- } else {
- this.mPostponedActivityResult = new Pair<>(requestCode, data);
- }
- } else if (requestCode == REQUEST_ANNOUNCE_PGP) {
- if (xmppConnectionServiceBound) {
- announcePgp(mSelectedConversation.getAccount(), mSelectedConversation, data, onOpenPGPKeyPublished);
- this.mPostponedActivityResult = null;
- } else {
- this.mPostponedActivityResult = new Pair<>(requestCode, data);
- }
- } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
- mPendingImageUris.clear();
- mPendingImageUris.addAll(extractUriFromIntent(data));
- if (xmppConnectionServiceBound) {
- for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
- Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching image to conversations. CHOOSE_IMAGE");
- attachImageToConversation(getSelectedConversation(), i.next());
- }
- }
- } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE || requestCode == ATTACHMENT_CHOICE_RECORD_VIDEO) {
- final List<Uri> uris = extractUriFromIntent(data);
- Log.d(Config.LOGTAG, "uris " + uris.toString());
- final Conversation c = getSelectedConversation();
- final OnPresenceSelected callback = new OnPresenceSelected() {
- @Override
- public void onPresenceSelected() {
- mPendingFileUris.clear();
- mPendingFileUris.addAll(uris);
- if (xmppConnectionServiceBound) {
- for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
- Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching file to conversations. CHOOSE_FILE/RECORD_VOICE/RECORD_VIDEO");
- attachFileToConversation(c, i.next());
- }
- }
- }
- };
- if (c == null || c.getMode() == Conversation.MODE_MULTI
- || FileBackend.allFilesUnderSize(this, uris, getMaxHttpUploadSize(c))) {
- callback.onPresenceSelected();
- } else {
- selectPresence(c, callback);
- }
- } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
- if (mPendingImageUris.size() == 1) {
- Uri uri = FileBackend.getIndexableTakePhotoUri(mPendingImageUris.get(0));
- mPendingImageUris.set(0, uri);
- if (xmppConnectionServiceBound) {
- Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching image to conversations. TAKE_PHOTO");
- attachImageToConversation(getSelectedConversation(), uri);
- mPendingImageUris.clear();
- }
- if (!Config.ONLY_INTERNAL_STORAGE) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- intent.setData(uri);
- sendBroadcast(intent);
- }
- } else {
- mPendingImageUris.clear();
- }
- } else if (requestCode == ATTACHMENT_CHOICE_LOCATION) {
- double latitude = data.getDoubleExtra("latitude", 0);
- double longitude = data.getDoubleExtra("longitude", 0);
- this.mPendingGeoUri = Uri.parse("geo:" + String.valueOf(latitude) + "," + String.valueOf(longitude));
- if (xmppConnectionServiceBound) {
- attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
- this.mPendingGeoUri = null;
- }
- } else if (requestCode == REQUEST_TRUST_KEYS_TEXT || requestCode == REQUEST_TRUST_KEYS_MENU) {
- this.forbidProcessingPendings = true;
- if (xmppConnectionServiceBound) {
- mConversationFragment.onActivityResult(requestCode, resultCode, data);
- this.mPostponedActivityResult = null;
- } else {
- this.mPostponedActivityResult = new Pair<>(requestCode, data);
- }
-
- }
- } else {
- mPendingImageUris.clear();
- mPendingFileUris.clear();
- if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
- mConversationFragment.onActivityResult(requestCode, resultCode, data);
- }
+ if (resultCode != RESULT_OK) {
if (requestCode == REQUEST_BATTERY_OP) {
setNeverAskForBatteryOptimizationsAgain();
}
}
}
- private long getMaxHttpUploadSize(Conversation conversation) {
+ public long getMaxHttpUploadSize(Conversation conversation) {
final XmppConnection connection = conversation.getAccount().getXmppConnection();
return connection == null ? -1 : connection.getFeatures().getMaxHttpUploadSize();
}
@@ -1428,108 +816,6 @@ public class ConversationActivity extends XmppActivity
return false;
}
- private void attachLocationToConversation(Conversation conversation, Uri uri) {
- if (conversation == null) {
- return;
- }
- xmppConnectionService.attachLocationToConversation(conversation, uri, new UiCallback<Message>() {
-
- @Override
- public void success(Message message) {
- xmppConnectionService.sendMessage(message);
- }
-
- @Override
- public void error(int errorCode, Message object) {
-
- }
-
- @Override
- public void userInputRequried(PendingIntent pi, Message object) {
-
- }
- });
- }
-
- private void attachFileToConversation(Conversation conversation, Uri uri) {
- if (conversation == null) {
- return;
- }
- final Toast prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_file), Toast.LENGTH_LONG);
- prepareFileToast.show();
- delegateUriPermissionsToService(uri);
- xmppConnectionService.attachFileToConversation(conversation, uri, new UiInformableCallback<Message>() {
- @Override
- public void inform(final String text) {
- hidePrepareFileToast(prepareFileToast);
- runOnUiThread(() -> replaceToast(text));
- }
-
- @Override
- public void success(Message message) {
- runOnUiThread(() -> hideToast());
- hidePrepareFileToast(prepareFileToast);
- xmppConnectionService.sendMessage(message);
- }
-
- @Override
- public void error(final int errorCode, Message message) {
- hidePrepareFileToast(prepareFileToast);
- runOnUiThread(() -> replaceToast(getString(errorCode)));
-
- }
-
- @Override
- public void userInputRequried(PendingIntent pi, Message message) {
- hidePrepareFileToast(prepareFileToast);
- }
- });
- }
-
- public void attachImageToConversation(Uri uri) {
- this.attachImageToConversation(getSelectedConversation(), uri);
- }
-
- private void attachImageToConversation(Conversation conversation, Uri uri) {
- if (conversation == null) {
- return;
- }
- final Toast prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), Toast.LENGTH_LONG);
- prepareFileToast.show();
- delegateUriPermissionsToService(uri);
- xmppConnectionService.attachImageToConversation(conversation, uri,
- new UiCallback<Message>() {
-
- @Override
- public void userInputRequried(PendingIntent pi, Message object) {
- hidePrepareFileToast(prepareFileToast);
- }
-
- @Override
- public void success(Message message) {
- hidePrepareFileToast(prepareFileToast);
- xmppConnectionService.sendMessage(message);
- }
-
- @Override
- public void error(final int error, Message message) {
- hidePrepareFileToast(prepareFileToast);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- replaceToast(getString(error));
- }
- });
- }
- });
- }
-
- private void hidePrepareFileToast(final Toast prepareFileToast) {
- if (prepareFileToast != null) {
- runOnUiThread(() -> prepareFileToast.cancel());
- }
- }
-
public void updateConversationList() {
xmppConnectionService.populateWithOrderedConversations(conversationList);
if (!conversationList.contains(mSelectedConversation)) {
@@ -1553,44 +839,6 @@ public class ConversationActivity extends XmppActivity
}
}
- public void encryptTextMessage(Message message) {
- xmppConnectionService.getPgpEngine().encrypt(message,
- new UiCallback<Message>() {
-
- @Override
- public void userInputRequried(PendingIntent pi, Message message) {
- ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_MESSAGE);
- }
-
- @Override
- public void success(Message message) {
- message.setEncryption(Message.ENCRYPTION_DECRYPTED);
- xmppConnectionService.sendMessage(message);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mConversationFragment.messageSent();
- }
- });
- }
-
- @Override
- public void error(final int error, Message message) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mConversationFragment.doneSendingPgpMessage();
- Toast.makeText(ConversationActivity.this,
- R.string.unable_to_connect_to_keychain,
- Toast.LENGTH_SHORT
- ).show();
- }
- });
-
- }
- });
- }
-
public boolean useSendButtonToIndicateStatus() {
return getPreferences().getBoolean("send_button_status", getResources().getBoolean(R.bool.send_button_status));
}
@@ -1603,36 +851,6 @@ public class ConversationActivity extends XmppActivity
return getPreferences().getBoolean("use_green_background", getResources().getBoolean(R.bool.use_green_background));
}
- protected boolean trustKeysIfNeeded(int requestCode) {
- return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID);
- }
-
- protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) {
- AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService();
- final List<Jid> targets = axolotlService.getCryptoTargets(mSelectedConversation);
- boolean hasUnaccepted = !mSelectedConversation.getAcceptedCryptoTargets().containsAll(targets);
- boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(FingerprintStatus.createActiveUndecided()).isEmpty();
- boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), targets).isEmpty();
- boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty();
- boolean hasNoTrustedKeys = axolotlService.anyTargetHasNoTrustedKeys(targets);
- if (hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys || hasUnaccepted) {
- axolotlService.createSessionsIfNeeded(mSelectedConversation);
- Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class);
- String[] contacts = new String[targets.size()];
- for (int i = 0; i < contacts.length; ++i) {
- contacts[i] = targets.get(i).toString();
- }
- intent.putExtra("contacts", contacts);
- intent.putExtra(EXTRA_ACCOUNT, mSelectedConversation.getAccount().getJid().toBareJid().toString());
- intent.putExtra("choice", attachmentChoice);
- intent.putExtra("conversation", mSelectedConversation.getUuid());
- startActivityForResult(intent, requestCode);
- return true;
- } else {
- return false;
- }
- }
-
@Override
protected void refreshUiReal() {
updateConversationList();
@@ -1675,9 +893,6 @@ public class ConversationActivity extends XmppActivity
this.refreshUi();
}
- public void unblockConversation(final Blockable conversation) {
- xmppConnectionService.sendUnblockRequest(conversation);
- }
public boolean enterIsSend() {
return getPreferences().getBoolean("enter_is_send", getResources().getBoolean(R.bool.enter_is_send));
@@ -1,6 +1,11 @@
package eu.siacs.conversations.ui;
+import android.annotation.SuppressLint;
import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.MediaStore;
import android.support.v7.app.AlertDialog;
import android.app.Fragment;
import android.app.PendingIntent;
@@ -21,8 +26,9 @@ import android.util.Pair;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
@@ -34,6 +40,7 @@ import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.PopupMenu;
@@ -42,17 +49,24 @@ import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
+import org.openintents.openpgp.util.OpenPgpApi;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
+import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Contact;
@@ -61,6 +75,7 @@ import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presence;
+import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.entities.ReadByMarker;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder;
@@ -68,10 +83,13 @@ import eu.siacs.conversations.http.HttpDownloadConnection;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.XmppConnectionService;
-import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected;
-import eu.siacs.conversations.ui.XmppActivity.OnValueEdited;
import eu.siacs.conversations.ui.adapter.MessageAdapter;
+import eu.siacs.conversations.ui.util.ActivityResult;
+import eu.siacs.conversations.ui.util.AttachmentTool;
+import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
+import eu.siacs.conversations.ui.util.PresenceSelector;
import eu.siacs.conversations.ui.util.SendButtonAction;
+import eu.siacs.conversations.ui.util.SendButtonTool;
import eu.siacs.conversations.ui.widget.EditMessage;
import eu.siacs.conversations.utils.MessageUtils;
import eu.siacs.conversations.utils.NickValidityChecker;
@@ -79,16 +97,35 @@ import eu.siacs.conversations.utils.StylingHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_CHOOSE_IMAGE;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_LOCATION;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_RECORD_VIDEO;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_RECORD_VOICE;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_TAKE_PHOTO;
+import static eu.siacs.conversations.ui.XmppActivity.EXTRA_ACCOUNT;
+import static eu.siacs.conversations.ui.XmppActivity.REQUEST_ANNOUNCE_PGP;
+import static eu.siacs.conversations.ui.XmppActivity.REQUEST_CHOOSE_PGP_ID;
+
public class ConversationFragment extends Fragment implements EditMessage.KeyboardListener {
+
+ public static final int REQUEST_SEND_MESSAGE = 0x0201;
+ public static final int REQUEST_DECRYPT_PGP = 0x0202;
+ public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
+ public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208;
+ public static final int REQUEST_TRUST_KEYS_MENU = 0x0209;
+ public static final int REQUEST_START_DOWNLOAD = 0x0210;
+ public static final int REQUEST_ADD_EDITOR_CONTENT = 0x0211;
+ public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
+ public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
+ public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
+ public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304;
+ public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305;
+ public static final int ATTACHMENT_CHOICE_INVALID = 0x0306;
+ public static final int ATTACHMENT_CHOICE_RECORD_VIDEO = 0x0307;
+
+ public static final String RECENTLY_USED_QUICK_ACTION = "recently_used_quick_action";
+
+
final protected List<Message> messageList = new ArrayList<>();
protected Conversation conversation;
protected ListView messagesView;
@@ -99,6 +136,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
private TextView snackbarMessage;
private TextView snackbarAction;
private Toast messageLoaderToast;
+
+ private ActivityResult postponedActivityResult = null;
+ public Uri mPendingEditorContent = null;
+
+ private ConversationActivity activity;
+
private OnClickListener clickToMuc = new OnClickListener() {
@Override
@@ -109,7 +152,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
startActivity(intent);
}
};
- private ConversationActivity activity;
private OnClickListener leaveMuc = new OnClickListener() {
@Override
@@ -133,13 +175,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (password == null) {
password = "";
}
- activity.quickPasswordEdit(password, new OnValueEdited() {
-
- @Override
- public String onValueEdited(String value) {
- activity.xmppConnectionService.providePasswordForMuc(conversation, value);
- return null;
- }
+ activity.quickPasswordEdit(password, value -> {
+ activity.xmppConnectionService.providePasswordForMuc(conversation, value);
+ return null;
});
}
};
@@ -168,53 +206,47 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
conversation.messagesLoaded.set(true);
return;
}
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- final int oldPosition = messagesView.getFirstVisiblePosition();
- Message message = null;
- int childPos;
- for (childPos = 0; childPos + oldPosition < messageList.size(); ++childPos) {
- message = messageList.get(oldPosition + childPos);
- if (message.getType() != Message.TYPE_STATUS) {
- break;
- }
+ getActivity().runOnUiThread(() -> {
+ final int oldPosition = messagesView.getFirstVisiblePosition();
+ Message message = null;
+ int childPos;
+ for (childPos = 0; childPos + oldPosition < messageList.size(); ++childPos) {
+ message = messageList.get(oldPosition + childPos);
+ if (message.getType() != Message.TYPE_STATUS) {
+ break;
}
- final String uuid = message != null ? message.getUuid() : null;
- View v = messagesView.getChildAt(childPos);
- final int pxOffset = (v == null) ? 0 : v.getTop();
- ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList);
- try {
- updateStatusMessages();
- } catch (IllegalStateException e) {
- Log.d(Config.LOGTAG, "caught illegal state exception while updating status messages");
- }
- messageListAdapter.notifyDataSetChanged();
- int pos = Math.max(getIndexOf(uuid, messageList), 0);
- messagesView.setSelectionFromTop(pos, pxOffset);
- if (messageLoaderToast != null) {
- messageLoaderToast.cancel();
- }
- conversation.messagesLoaded.set(true);
}
+ final String uuid = message != null ? message.getUuid() : null;
+ View v = messagesView.getChildAt(childPos);
+ final int pxOffset = (v == null) ? 0 : v.getTop();
+ ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList);
+ try {
+ updateStatusMessages();
+ } catch (IllegalStateException e) {
+ Log.d(Config.LOGTAG, "caught illegal state exception while updating status messages");
+ }
+ messageListAdapter.notifyDataSetChanged();
+ int pos = Math.max(getIndexOf(uuid, messageList), 0);
+ messagesView.setSelectionFromTop(pos, pxOffset);
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ conversation.messagesLoaded.set(true);
});
}
@Override
public void informUser(final int resId) {
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (messageLoaderToast != null) {
- messageLoaderToast.cancel();
- }
- if (ConversationFragment.this.conversation != conversation) {
- return;
- }
- messageLoaderToast = Toast.makeText(view.getContext(), resId, Toast.LENGTH_LONG);
- messageLoaderToast.show();
+ getActivity().runOnUiThread(() -> {
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ if (ConversationFragment.this.conversation != conversation) {
+ return;
}
+ messageLoaderToast = Toast.makeText(view.getContext(), resId, Toast.LENGTH_LONG);
+ messageLoaderToast.show();
});
}
@@ -234,18 +266,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
inputContentInfo.requestPermission();
} catch (Exception e) {
Log.e(Config.LOGTAG, "InputContentInfoCompat#requestPermission() failed.", e);
- Toast.makeText(
- activity,
- activity.getString(R.string.no_permission_to_access_x, inputContentInfo.getDescription()),
- Toast.LENGTH_LONG
+ Toast.makeText(getActivity(),activity.getString(R.string.no_permission_to_access_x, inputContentInfo.getDescription()), Toast.LENGTH_LONG
).show();
return false;
}
}
- if (activity.hasStoragePermission(ConversationActivity.REQUEST_ADD_EDITOR_CONTENT)) {
- activity.attachImageToConversation(inputContentInfo.getContentUri());
+ if (activity.hasStoragePermission(REQUEST_ADD_EDITOR_CONTENT)) {
+ attachImageToConversation(inputContentInfo.getContentUri());
} else {
- activity.mPendingEditorContent = inputContentInfo.getContentUri();
+ mPendingEditorContent = inputContentInfo.getContentUri();
}
return true;
}
@@ -264,25 +293,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
private OnClickListener mUnblockClickListener = new OnClickListener() {
@Override
public void onClick(final View v) {
- v.post(new Runnable() {
- @Override
- public void run() {
- v.setVisibility(View.INVISIBLE);
- }
- });
+ v.post(() -> v.setVisibility(View.INVISIBLE));
if (conversation.isDomainBlocked()) {
BlockContactDialog.show(activity, conversation);
} else {
- activity.unblockConversation(conversation);
+ unblockConversation(conversation);
}
}
};
- private OnClickListener mBlockClickListener = new OnClickListener() {
- @Override
- public void onClick(final View view) {
- showBlockSubmenu(view);
- }
- };
+ private OnClickListener mBlockClickListener = this::showBlockSubmenu;
private OnClickListener mAddBackClickListener = new OnClickListener() {
@Override
@@ -294,13 +313,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
};
- private View.OnLongClickListener mLongPressBlockListener = new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- showBlockSubmenu(v);
- return true;
- }
- };
+ private View.OnLongClickListener mLongPressBlockListener = this::showBlockSubmenu;
private OnClickListener mAllowPresenceSubscription = new OnClickListener() {
@Override
public void onClick(View v) {
@@ -321,14 +334,14 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
PendingIntent pendingIntent = conversation.getAccount().getPgpDecryptionService().getPendingIntent();
if (pendingIntent != null) {
try {
- activity.startIntentSenderForResult(pendingIntent.getIntentSender(),
- ConversationActivity.REQUEST_DECRYPT_PGP,
+ getActivity().startIntentSenderForResult(pendingIntent.getIntentSender(),
+ REQUEST_DECRYPT_PGP,
null,
0,
0,
0);
} catch (SendIntentException e) {
- Toast.makeText(activity, R.string.unable_to_connect_to_keychain, Toast.LENGTH_SHORT).show();
+ Toast.makeText(getActivity(), R.string.unable_to_connect_to_keychain, Toast.LENGTH_SHORT).show();
conversation.getAccount().getPgpDecryptionService().continueDecryption(true);
}
}
@@ -336,21 +349,17 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
};
private AtomicBoolean mSendingPgpMessage = new AtomicBoolean(false);
- private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() {
-
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_SEND) {
- InputMethodManager imm = (InputMethodManager) v.getContext()
- .getSystemService(Context.INPUT_METHOD_SERVICE);
- if (imm.isFullscreenMode()) {
- imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
- }
- sendMessage();
- return true;
- } else {
- return false;
+ private OnEditorActionListener mEditorActionListener = (v, actionId, event) -> {
+ if (actionId == EditorInfo.IME_ACTION_SEND) {
+ InputMethodManager imm = (InputMethodManager) v.getContext()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm.isFullscreenMode()) {
+ imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
+ sendMessage();
+ return true;
+ } else {
+ return false;
}
};
private OnClickListener mSendButtonListener = new OnClickListener() {
@@ -366,7 +375,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
case SEND_LOCATION:
case RECORD_VOICE:
case CHOOSE_PICTURE:
- activity.attachFile(action.toChoice());
+ attachFile(action.toChoice());
break;
case CANCEL:
if (conversation != null) {
@@ -395,6 +404,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
private String incomplete;
private int lastCompletionCursor;
private boolean firstWord = false;
+ private Message mPendingDownloadableMessage;
private int getIndexOf(String uuid, List<Message> messages) {
if (uuid == null) {
@@ -438,6 +448,104 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
+
+ private void attachLocationToConversation(Conversation conversation, Uri uri) {
+ if (conversation == null) {
+ return;
+ }
+ activity.xmppConnectionService.attachLocationToConversation(conversation, uri, new UiCallback<Message>() {
+
+ @Override
+ public void success(Message message) {
+ activity.xmppConnectionService.sendMessage(message);
+ }
+
+ @Override
+ public void error(int errorCode, Message object) {
+
+ }
+
+ @Override
+ public void userInputRequried(PendingIntent pi, Message object) {
+
+ }
+ });
+ }
+
+ private void attachFileToConversation(Conversation conversation, Uri uri) {
+ if (conversation == null) {
+ return;
+ }
+ final Toast prepareFileToast = Toast.makeText(getActivity(), getText(R.string.preparing_file), Toast.LENGTH_LONG);
+ prepareFileToast.show();
+ activity.delegateUriPermissionsToService(uri);
+ activity.xmppConnectionService.attachFileToConversation(conversation, uri, new UiInformableCallback<Message>() {
+ @Override
+ public void inform(final String text) {
+ hidePrepareFileToast(prepareFileToast);
+ getActivity().runOnUiThread(() -> activity.replaceToast(text));
+ }
+
+ @Override
+ public void success(Message message) {
+ getActivity().runOnUiThread(() -> activity.hideToast());
+ hidePrepareFileToast(prepareFileToast);
+ activity.xmppConnectionService.sendMessage(message);
+ }
+
+ @Override
+ public void error(final int errorCode, Message message) {
+ hidePrepareFileToast(prepareFileToast);
+ getActivity().runOnUiThread(() -> activity.replaceToast(getString(errorCode)));
+
+ }
+
+ @Override
+ public void userInputRequried(PendingIntent pi, Message message) {
+ hidePrepareFileToast(prepareFileToast);
+ }
+ });
+ }
+
+ public void attachImageToConversation(Uri uri) {
+ this.attachImageToConversation(conversation, uri);
+ }
+
+ private void attachImageToConversation(Conversation conversation, Uri uri) {
+ if (conversation == null) {
+ return;
+ }
+ final Toast prepareFileToast = Toast.makeText(getActivity(), getText(R.string.preparing_image), Toast.LENGTH_LONG);
+ prepareFileToast.show();
+ activity.delegateUriPermissionsToService(uri);
+ activity.xmppConnectionService.attachImageToConversation(conversation, uri,
+ new UiCallback<Message>() {
+
+ @Override
+ public void userInputRequried(PendingIntent pi, Message object) {
+ hidePrepareFileToast(prepareFileToast);
+ }
+
+ @Override
+ public void success(Message message) {
+ hidePrepareFileToast(prepareFileToast);
+ activity.xmppConnectionService.sendMessage(message);
+ }
+
+ @Override
+ public void error(final int error, Message message) {
+ hidePrepareFileToast(prepareFileToast);
+ activity.runOnUiThread(() -> activity.replaceToast(getString(error)));
+ }
+ });
+ }
+
+ private void hidePrepareFileToast(final Toast prepareFileToast) {
+ if (prepareFileToast != null) {
+ activity.runOnUiThread(prepareFileToast::cancel);
+ }
+ }
+
private void sendMessage() {
final String body = mEditMessage.getText().toString();
final Conversation conversation = this.conversation;
@@ -466,7 +574,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
sendPgpMessage(message);
break;
case Message.ENCRYPTION_AXOLOTL:
- if (!activity.trustKeysIfNeeded(ConversationActivity.REQUEST_TRUST_KEYS_TEXT)) {
+ if (!trustKeysIfNeeded(REQUEST_TRUST_KEYS_TEXT)) {
sendAxolotlMessage(message);
}
break;
@@ -475,6 +583,36 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
+ protected boolean trustKeysIfNeeded(int requestCode) {
+ return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID);
+ }
+
+ protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) {
+ AxolotlService axolotlService = conversation.getAccount().getAxolotlService();
+ final List<Jid> targets = axolotlService.getCryptoTargets(conversation);
+ boolean hasUnaccepted = !conversation.getAcceptedCryptoTargets().containsAll(targets);
+ boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(FingerprintStatus.createActiveUndecided()).isEmpty();
+ boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), targets).isEmpty();
+ boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(conversation).isEmpty();
+ boolean hasNoTrustedKeys = axolotlService.anyTargetHasNoTrustedKeys(targets);
+ if (hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys || hasUnaccepted) {
+ axolotlService.createSessionsIfNeeded(conversation);
+ Intent intent = new Intent(getActivity(), TrustKeysActivity.class);
+ String[] contacts = new String[targets.size()];
+ for (int i = 0; i < contacts.length; ++i) {
+ contacts[i] = targets.get(i).toString();
+ }
+ intent.putExtra("contacts", contacts);
+ intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().toBareJid().toString());
+ intent.putExtra("choice", attachmentChoice);
+ intent.putExtra("conversation", conversation.getUuid());
+ startActivityForResult(intent, requestCode);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public void updateChatMsgHint() {
final boolean multi = conversation.getMode() == Conversation.MODE_MULTI;
if (conversation.getCorrectingMessage() != null) {
@@ -486,12 +624,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
} else if (multi && !conversation.getMucOptions().participating()) {
this.mEditMessage.setHint(R.string.you_are_not_participating);
} else {
- this.mEditMessage.setHint(UIHelper.getMessageHint(activity, conversation));
+ this.mEditMessage.setHint(UIHelper.getMessageHint(getActivity(), conversation));
getActivity().invalidateOptionsMenu();
}
}
- public void setupIme() {
+ public void setupIme() {;
if (activity != null) {
if (activity.usingEnterKey() && activity.enterIsSend()) {
mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE));
@@ -506,19 +644,153 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
+ private void handleActivityResult(ActivityResult activityResult) {
+ if (activityResult.resultCode == Activity.RESULT_OK) {
+ handlePositiveActivityResult(activityResult.requestCode, activityResult.data);
+ } else {
+ handleNegativeActivityResult(activityResult.requestCode);
+ }
+ }
+
+ private void handlePositiveActivityResult(int requestCode, final Intent data) {
+ switch (requestCode) {
+ case REQUEST_DECRYPT_PGP:
+ conversation.getAccount().getPgpDecryptionService().continueDecryption(data);
+ break;
+ case REQUEST_TRUST_KEYS_TEXT:
+ final String body = mEditMessage.getText().toString();
+ Message message = new Message(conversation, body, conversation.getNextEncryption());
+ sendAxolotlMessage(message);
+ break;
+ case REQUEST_TRUST_KEYS_MENU:
+ int choice = data.getIntExtra("choice", ATTACHMENT_CHOICE_INVALID);
+ selectPresenceToAttachFile(choice);
+ break;
+ case REQUEST_CHOOSE_PGP_ID:
+ long id = data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID,0);
+ if (id != 0) {
+ conversation.getAccount().setPgpSignId(id);
+ activity.announcePgp(conversation.getAccount(),null,null,activity.onOpenPGPKeyPublished);
+ } else {
+ activity.choosePgpSignId(conversation.getAccount());
+ }
+ break;
+ case REQUEST_ANNOUNCE_PGP:
+ activity.announcePgp(conversation.getAccount(), conversation, data, activity.onOpenPGPKeyPublished);
+ break;
+ case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
+ List<Uri> imageUris = AttachmentTool.extractUriFromIntent(data);
+ for (Iterator<Uri> i = imageUris.iterator(); i.hasNext(); i.remove()) {
+ Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching image to conversations. CHOOSE_IMAGE");
+ attachImageToConversation(conversation, i.next());
+ }
+ break;
+ case ATTACHMENT_CHOICE_CHOOSE_FILE:
+ case ATTACHMENT_CHOICE_RECORD_VIDEO:
+ case ATTACHMENT_CHOICE_RECORD_VOICE:
+ final List<Uri> fileUris = AttachmentTool.extractUriFromIntent(data);
+ final PresenceSelector.OnPresenceSelected callback = () -> {
+ for (Iterator<Uri> i = fileUris.iterator(); i.hasNext(); i.remove()) {
+ Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching file to conversations. CHOOSE_FILE/RECORD_VOICE/RECORD_VIDEO");
+ attachFileToConversation(conversation, i.next());
+ }
+ };
+ if (conversation == null || conversation.getMode() == Conversation.MODE_MULTI || FileBackend.allFilesUnderSize(getActivity(), fileUris, activity.getMaxHttpUploadSize(conversation))) {
+ callback.onPresenceSelected();
+ } else {
+ activity.selectPresence(conversation, callback);
+ }
+ break;
+ case ATTACHMENT_CHOICE_LOCATION:
+ double latitude = data.getDoubleExtra("latitude", 0);
+ double longitude = data.getDoubleExtra("longitude", 0);
+ Uri geo = Uri.parse("geo:" + String.valueOf(latitude) + "," + String.valueOf(longitude));
+ attachLocationToConversation(conversation, geo);
+ break;
+ }
+ }
+
+ private void handleNegativeActivityResult(int requestCode) {
+ switch (requestCode) {
+ case REQUEST_DECRYPT_PGP:
+ // discard the message to prevent decryption being blocked
+ conversation.getAccount().getPgpDecryptionService().giveUpCurrentDecryption();
+ break;
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, final Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ ActivityResult activityResult = ActivityResult.of(requestCode,resultCode,data);
+ if (activity != null && activity.xmppConnectionService != null) {
+ handleActivityResult(activityResult);
+ } else {
+ this.postponedActivityResult = activityResult;
+ }
+ }
+
+ public void unblockConversation(final Blockable conversation) {
+ activity.xmppConnectionService.sendUnblockRequest(conversation);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ if (context instanceof ConversationActivity) {
+ this.activity = (ConversationActivity) context;
+ } else {
+ throw new IllegalStateException("Trying to attach fragment to activity that is not the ConversationActivity");
+ }
+ super.onAttach(context);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.fragment_conversation, menu);
+ final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
+ final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
+ final MenuItem menuInviteContact = menu.findItem(R.id.action_invite);
+ final MenuItem menuMute = menu.findItem(R.id.action_mute);
+ final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
+
+
+ if (conversation != null) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ menuContactDetails.setVisible(false);
+ menuInviteContact.setVisible(conversation.getMucOptions().canInvite());
+ } else {
+ menuContactDetails.setVisible(!this.conversation.withSelf());
+ menuMucDetails.setVisible(false);
+ final XmppConnectionService service = activity.xmppConnectionService;
+ menuInviteContact.setVisible(service != null && service.findConferenceServer(conversation.getAccount()) != null);
+ }
+ if (conversation.isMuted()) {
+ menuMute.setVisible(false);
+ } else {
+ menuUnmute.setVisible(false);
+ }
+ ConversationMenuConfigurator.configureAttachmentMenu(conversation, menu);
+ ConversationMenuConfigurator.configureEncryptionMenu(conversation, menu);
+ }
+ super.onCreateOptionsMenu(menu, menuInflater);
+ }
+
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_conversation, container, false);
view.setOnClickListener(null);
mEditMessage = (EditMessage) view.findViewById(R.id.textinput);
- mEditMessage.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (activity != null) {
- activity.hideConversationsOverview();
- }
+ mEditMessage.setOnClickListener(v -> {
+ if (activity != null) {
+ activity.hideConversationsOverview();
}
});
@@ -545,7 +817,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
Jid user = message.getCounterpart();
if (user != null && !user.isBareJid()) {
if (!message.getConversation().getMucOptions().isUserInRoom(user)) {
- Toast.makeText(activity, activity.getString(R.string.user_has_left_conference, user.getResourcepart()), Toast.LENGTH_SHORT).show();
+ Toast.makeText(getActivity(), activity.getString(R.string.user_has_left_conference, user.getResourcepart()), Toast.LENGTH_SHORT).show();
}
highlightInConference(user.getResourcepart());
}
@@ -568,7 +840,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
Intent intent;
if (activity.manuallyChangePresence() && !received) {
intent = new Intent(activity, SetPresenceActivity.class);
- intent.putExtra(SetPresenceActivity.EXTRA_ACCOUNT, account.getJid().toBareJid().toString());
+ intent.putExtra(EXTRA_ACCOUNT, account.getJid().toBareJid().toString());
} else {
intent = new Intent(activity, EditAccountActivity.class);
intent.putExtra("jid", account.getJid().toBareJid().toString());
@@ -588,7 +860,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
final MucOptions mucOptions = conversation.getMucOptions();
if (!mucOptions.allowPm()) {
- Toast.makeText(activity, R.string.private_messages_are_disabled, Toast.LENGTH_SHORT).show();
+ Toast.makeText(getActivity(), R.string.private_messages_are_disabled, Toast.LENGTH_SHORT).show();
return;
}
Jid user = message.getCounterpart();
@@ -596,7 +868,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (mucOptions.isUserInRoom(user)) {
privateMessageWith(user);
} else {
- Toast.makeText(activity, activity.getString(R.string.user_has_left_conference, user.getResourcepart()), Toast.LENGTH_SHORT).show();
+ Toast.makeText(getActivity(), activity.getString(R.string.user_has_left_conference, user.getResourcepart()), Toast.LENGTH_SHORT).show();
}
}
}
@@ -765,8 +1037,356 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ if (conversation == null) {
+ return super.onOptionsItemSelected(item);
+ }
+ switch (item.getItemId()) {
+ case R.id.encryption_choice_axolotl:
+ case R.id.encryption_choice_pgp:
+ case R.id.encryption_choice_none:
+ handleEncryptionSelection(item);
+ break;
+ case R.id.attach_choose_picture:
+ case R.id.attach_take_picture:
+ case R.id.attach_record_video:
+ case R.id.attach_choose_file:
+ case R.id.attach_record_voice:
+ case R.id.attach_location:
+ handleAttachmentSelection(item);
+ break;
+ case R.id.action_archive:
+ activity.endConversation(conversation);
+ break;
+ case R.id.action_contact_details:
+ activity.switchToContactDetails(conversation.getContact());
+ break;
+ case R.id.action_muc_details:
+ Intent intent = new Intent(getActivity(), ConferenceDetailsActivity.class);
+ intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
+ intent.putExtra("uuid", conversation.getUuid());
+ startActivity(intent);
+ break;
+ case R.id.action_invite:
+ activity.inviteToConversation(conversation);
+ break;
+ case R.id.action_clear_history:
+ clearHistoryDialog(conversation);
+ break;
+ case R.id.action_mute:
+ muteConversationDialog(conversation);
+ break;
+ case R.id.action_unmute:
+ unmuteConversation(conversation);
+ break;
+ case R.id.action_block:
+ case R.id.action_unblock:
+ final Activity activity = getActivity();
+ if (activity instanceof XmppActivity) {
+ BlockContactDialog.show((XmppActivity) activity, conversation);
+ }
+ break;
+ default:
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void handleAttachmentSelection(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.attach_choose_picture:
+ attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
+ break;
+ case R.id.attach_take_picture:
+ attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
+ break;
+ case R.id.attach_record_video:
+ attachFile(ATTACHMENT_CHOICE_RECORD_VIDEO);
+ break;
+ case R.id.attach_choose_file:
+ attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE);
+ break;
+ case R.id.attach_record_voice:
+ attachFile(ATTACHMENT_CHOICE_RECORD_VOICE);
+ break;
+ case R.id.attach_location:
+ attachFile(ATTACHMENT_CHOICE_LOCATION);
+ break;
+ }
+ }
+
+ private void handleEncryptionSelection(MenuItem item) {
+ if (conversation == null) {
+ return;
+ }
+ final ConversationFragment fragment = (ConversationFragment) getFragmentManager().findFragmentByTag("conversation");
+ switch (item.getItemId()) {
+ case R.id.encryption_choice_none:
+ conversation.setNextEncryption(Message.ENCRYPTION_NONE);
+ item.setChecked(true);
+ break;
+ case R.id.encryption_choice_pgp:
+ if (activity.hasPgp()) {
+ if (conversation.getAccount().getPgpSignature() != null) {
+ conversation.setNextEncryption(Message.ENCRYPTION_PGP);
+ item.setChecked(true);
+ } else {
+ activity.announcePgp(conversation.getAccount(), conversation, null, activity.onOpenPGPKeyPublished);
+ }
+ } else {
+ activity.showInstallPgpDialog();
+ }
+ break;
+ case R.id.encryption_choice_axolotl:
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(conversation.getAccount())
+ + "Enabled axolotl for Contact " + conversation.getContact().getJid());
+ conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL);
+ item.setChecked(true);
+ break;
+ default:
+ conversation.setNextEncryption(Message.ENCRYPTION_NONE);
+ break;
+ }
+ activity.xmppConnectionService.updateConversation(conversation);
+ fragment.updateChatMsgHint();
+ getActivity().invalidateOptionsMenu();
+ activity.refreshUi();
+ }
+
+ public void attachFile(final int attachmentChoice) {
+ if (attachmentChoice != ATTACHMENT_CHOICE_LOCATION) {
+ if (!Config.ONLY_INTERNAL_STORAGE && !activity.hasStoragePermission(attachmentChoice)) {
+ return;
+ }
+ }
+ try {
+ activity.getPreferences().edit()
+ .putString(RECENTLY_USED_QUICK_ACTION, SendButtonAction.of(attachmentChoice).toString())
+ .apply();
+ } catch (IllegalArgumentException e) {
+ //just do not save
+ }
+ final int encryption = conversation.getNextEncryption();
+ final int mode = conversation.getMode();
+ if (encryption == Message.ENCRYPTION_PGP) {
+ if (activity.hasPgp()) {
+ if (mode == Conversation.MODE_SINGLE && conversation.getContact().getPgpKeyId() != 0) {
+ activity.xmppConnectionService.getPgpEngine().hasKey(
+ conversation.getContact(),
+ new UiCallback<Contact>() {
+
+ @Override
+ public void userInputRequried(PendingIntent pi, Contact contact) {
+ activity.runIntent(pi, attachmentChoice);
+ }
+
+ @Override
+ public void success(Contact contact) {
+ selectPresenceToAttachFile(attachmentChoice);
+ }
+
+ @Override
+ public void error(int error, Contact contact) {
+ activity.replaceToast(getString(error));
+ }
+ });
+ } else if (mode == Conversation.MODE_MULTI && conversation.getMucOptions().pgpKeysInUse()) {
+ if (!conversation.getMucOptions().everybodyHasKeys()) {
+ Toast warning = Toast.makeText(getActivity(), R.string.missing_public_keys, Toast.LENGTH_LONG);
+ warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
+ warning.show();
+ }
+ selectPresenceToAttachFile(attachmentChoice);
+ } else {
+ final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
+ .findFragmentByTag("conversation");
+ if (fragment != null) {
+ fragment.showNoPGPKeyDialog(false, (dialog, which) -> {
+ conversation.setNextEncryption(Message.ENCRYPTION_NONE);
+ activity.xmppConnectionService.updateConversation(conversation);
+ selectPresenceToAttachFile(attachmentChoice);
+ });
+ }
+ }
+ } else {
+ activity.showInstallPgpDialog();
+ }
+ } else {
+ if (encryption != Message.ENCRYPTION_AXOLOTL || !trustKeysIfNeeded(REQUEST_TRUST_KEYS_MENU, attachmentChoice)) {
+ selectPresenceToAttachFile(attachmentChoice);
+ }
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
+ if (grantResults.length > 0)
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (requestCode == REQUEST_START_DOWNLOAD) {
+ if (this.mPendingDownloadableMessage != null) {
+ startDownloadable(this.mPendingDownloadableMessage);
+ }
+ } else if (requestCode == REQUEST_ADD_EDITOR_CONTENT) {
+ if (this.mPendingEditorContent != null) {
+ attachImageToConversation(this.mPendingEditorContent);
+ }
+ } else {
+ attachFile(requestCode);
+ }
+ } else {
+ Toast.makeText(getActivity(), R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ public void startDownloadable(Message message) {
+ if (!Config.ONLY_INTERNAL_STORAGE && !activity.hasStoragePermission(REQUEST_START_DOWNLOAD)) {
+ this.mPendingDownloadableMessage = message;
+ return;
+ }
+ Transferable transferable = message.getTransferable();
+ if (transferable != null) {
+ if (!transferable.start()) {
+ Toast.makeText(getActivity(), R.string.not_connected_try_again, Toast.LENGTH_SHORT).show();
+ }
+ } else if (message.treatAsDownloadable()) {
+ activity.xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, true);
+ }
+ }
+
+ @SuppressLint("InflateParams")
+ protected void clearHistoryDialog(final Conversation conversation) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(getString(R.string.clear_conversation_history));
+ final View dialogView = getActivity().getLayoutInflater().inflate(R.layout.dialog_clear_history, null);
+ final CheckBox endConversationCheckBox = dialogView.findViewById(R.id.end_conversation_checkbox);
+ builder.setView(dialogView);
+ builder.setNegativeButton(getString(R.string.cancel), null);
+ builder.setPositiveButton(getString(R.string.delete_messages), (dialog, which) -> {
+ this.activity.xmppConnectionService.clearConversationHistory(conversation);
+ if (endConversationCheckBox.isChecked()) {
+ this.activity.endConversation(conversation);
+ } else {
+ activity.updateConversationList();
+ updateMessages();
+ }
+ });
+ builder.create().show();
+ }
+
+ protected void muteConversationDialog(final Conversation conversation) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.disable_notifications);
+ final int[] durations = getResources().getIntArray(R.array.mute_options_durations);
+ builder.setItems(R.array.mute_options_descriptions, (dialog, which) -> {
+ final long till;
+ if (durations[which] == -1) {
+ till = Long.MAX_VALUE;
+ } else {
+ till = System.currentTimeMillis() + (durations[which] * 1000);
+ }
+ conversation.setMutedTill(till);
+ activity.xmppConnectionService.updateConversation(conversation);
+ activity.updateConversationList();
+ updateMessages();
+ getActivity().invalidateOptionsMenu();
+ });
+ builder.create().show();
+ }
+
+ public void unmuteConversation(final Conversation conversation) {
+ conversation.setMutedTill(0);
+ this.activity.xmppConnectionService.updateConversation(conversation);
+ this.activity.updateConversationList();
+ updateMessages();
+ getActivity().invalidateOptionsMenu();
+ }
+
+ protected void selectPresenceToAttachFile(final int attachmentChoice) {
+ final Account account = conversation.getAccount();
+ final PresenceSelector.OnPresenceSelected callback = () -> {
+ Intent intent = new Intent();
+ boolean chooser = false;
+ String fallbackPackageId = null;
+ switch (attachmentChoice) {
+ case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ intent.setType("image/*");
+ chooser = true;
+ break;
+ case ATTACHMENT_CHOICE_RECORD_VIDEO:
+ intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
+ break;
+ case ATTACHMENT_CHOICE_TAKE_PHOTO:
+ Uri uri = activity.xmppConnectionService.getFileBackend().getTakePhotoUri();
+ //mPendingImageUris.clear();
+ //mPendingImageUris.add(uri);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
+ break;
+ case ATTACHMENT_CHOICE_CHOOSE_FILE:
+ chooser = true;
+ intent.setType("*/*");
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ break;
+ case ATTACHMENT_CHOICE_RECORD_VOICE:
+ intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
+ fallbackPackageId = "eu.siacs.conversations.voicerecorder";
+ break;
+ case ATTACHMENT_CHOICE_LOCATION:
+ intent.setAction("eu.siacs.conversations.location.request");
+ fallbackPackageId = "eu.siacs.conversations.sharelocation";
+ break;
+ }
+ if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
+ if (chooser) {
+ startActivityForResult(
+ Intent.createChooser(intent, getString(R.string.perform_action_with)),
+ attachmentChoice);
+ } else {
+ startActivityForResult(intent, attachmentChoice);
+ }
+ } else if (fallbackPackageId != null) {
+ startActivity(getInstallApkIntent(fallbackPackageId));
+ }
+ };
+ if (account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) {
+ conversation.setNextCounterpart(null);
+ callback.onPresenceSelected();
+ } else {
+ activity.selectPresence(conversation, callback);
+ }
+ }
+
+ private Intent getInstallApkIntent(final String packageId) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse("market://details?id=" + packageId));
+ if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
+ return intent;
+ } else {
+ intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId));
+ return intent;
+ }
+ }
+
+ @Override
+ public void onResume() {
+ new Handler().post(() -> {
+ final PackageManager packageManager = getActivity().getPackageManager();
+ ConversationMenuConfigurator.updateAttachmentAvailability(packageManager);
+ getActivity().invalidateOptionsMenu();
+ });
+ super.onResume();
+ }
+
private void showErrorMessage(final Message message) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.error_message);
builder.setMessage(message.getErrorMessage());
builder.setPositiveButton(R.string.confirm, null);
@@ -29,6 +29,7 @@ import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.ui.service.EmojiService;
+import eu.siacs.conversations.ui.util.PresenceSelector;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -312,7 +313,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
return;
}
if (share.uris.size() != 0) {
- OnPresenceSelected callback = () -> {
+ PresenceSelector.OnPresenceSelected callback = () -> {
attachmentCounter.set(share.uris.size());
if (share.image) {
share.multiple = share.uris.size() > 1;
@@ -339,7 +340,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
}
} else {
if (mReturnToPrevious && this.share.text != null && !this.share.text.isEmpty() ) {
- final OnPresenceSelected callback = new OnPresenceSelected() {
+ final PresenceSelector.OnPresenceSelected callback = new PresenceSelector.OnPresenceSelected() {
private void finishAndSend(Message message) {
xmppConnectionService.sendMessage(message);
@@ -388,7 +388,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
private void finishOk() {
Intent data = new Intent();
- data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID));
+ data.putExtra("choice", getIntent().getIntExtra("choice", ConversationFragment.ATTACHMENT_CHOICE_INVALID));
setResult(RESULT_OK, data);
finish();
}
@@ -70,6 +70,7 @@ import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.BarcodeProvider;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
+import eu.siacs.conversations.ui.util.PresenceSelector;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.UIHelper;
@@ -103,7 +104,7 @@ public abstract class XmppActivity extends AppCompatActivity {
protected int mTheme;
protected boolean mUsingEnterKey = false;
protected Toast mToast;
- protected Runnable onOpenPGPKeyPublished = () -> Toast.makeText(XmppActivity.this, R.string.openpgp_has_been_published, Toast.LENGTH_SHORT).show();
+ public Runnable onOpenPGPKeyPublished = () -> Toast.makeText(XmppActivity.this, R.string.openpgp_has_been_published, Toast.LENGTH_SHORT).show();
protected ConferenceInvite mPendingConferenceInvite = null;
protected ServiceConnection mConnection = new ServiceConnection() {
@@ -375,6 +376,38 @@ public abstract class XmppActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
+ public void selectPresence(final Conversation conversation, final PresenceSelector.OnPresenceSelected listener) {
+ final Contact contact = conversation.getContact();
+ if (!contact.showInRoster()) {
+ showAddToRosterDialog(conversation.getContact());
+ } else {
+ final Presences presences = contact.getPresences();
+ if (presences.size() == 0) {
+ if (!contact.getOption(Contact.Options.TO)
+ && !contact.getOption(Contact.Options.ASKING)
+ && contact.getAccount().getStatus() == Account.State.ONLINE) {
+ showAskForPresenceDialog(contact);
+ } else if (!contact.getOption(Contact.Options.TO)
+ || !contact.getOption(Contact.Options.FROM)) {
+ PresenceSelector.warnMutualPresenceSubscription(this, conversation, listener);
+ } else {
+ conversation.setNextCounterpart(null);
+ listener.onPresenceSelected();
+ }
+ } else if (presences.size() == 1) {
+ String presence = presences.toResourceArray()[0];
+ try {
+ conversation.setNextCounterpart(Jid.fromParts(contact.getJid().getLocalpart(), contact.getJid().getDomainpart(), presence));
+ } catch (InvalidJidException e) {
+ conversation.setNextCounterpart(null);
+ }
+ listener.onPresenceSelected();
+ } else {
+ PresenceSelector.showPresenceSelectionDialog(this, conversation, listener);
+ }
+ }
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -665,10 +698,6 @@ public abstract class XmppActivity extends AppCompatActivity {
}
- protected void showAddToRosterDialog(final Conversation conversation) {
- showAddToRosterDialog(conversation.getContact());
- }
-
protected void showAddToRosterDialog(final Contact contact) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(contact.getJid().toString());
@@ -701,21 +730,6 @@ public abstract class XmppActivity extends AppCompatActivity {
builder.create().show();
}
- private void warnMutalPresenceSubscription(final Conversation conversation,
- final OnPresenceSelected listener) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(conversation.getContact().getJid().toString());
- builder.setMessage(R.string.without_mutual_presence_updates);
- builder.setNegativeButton(R.string.cancel, null);
- builder.setPositiveButton(R.string.ignore, (dialog, which) -> {
- conversation.setNextCounterpart(null);
- if (listener != null) {
- listener.onPresenceSelected();
- }
- });
- builder.create().show();
- }
-
protected void quickEdit(String previousValue, int hint, OnValueEdited callback) {
quickEdit(previousValue, callback, hint, false);
}
@@ -776,89 +790,6 @@ public abstract class XmppActivity extends AppCompatActivity {
}
}
- public void selectPresence(final Conversation conversation,
- final OnPresenceSelected listener) {
- final Contact contact = conversation.getContact();
- if (!contact.showInRoster()) {
- showAddToRosterDialog(conversation);
- } else {
- final Presences presences = contact.getPresences();
- if (presences.size() == 0) {
- if (!contact.getOption(Contact.Options.TO)
- && !contact.getOption(Contact.Options.ASKING)
- && contact.getAccount().getStatus() == Account.State.ONLINE) {
- showAskForPresenceDialog(contact);
- } else if (!contact.getOption(Contact.Options.TO)
- || !contact.getOption(Contact.Options.FROM)) {
- warnMutalPresenceSubscription(conversation, listener);
- } else {
- conversation.setNextCounterpart(null);
- listener.onPresenceSelected();
- }
- } else if (presences.size() == 1) {
- String presence = presences.toResourceArray()[0];
- try {
- conversation.setNextCounterpart(Jid.fromParts(contact.getJid().getLocalpart(), contact.getJid().getDomainpart(), presence));
- } catch (InvalidJidException e) {
- conversation.setNextCounterpart(null);
- }
- listener.onPresenceSelected();
- } else {
- showPresenceSelectionDialog(presences, conversation, listener);
- }
- }
- }
-
- private void showPresenceSelectionDialog(Presences presences, final Conversation conversation, final OnPresenceSelected listener) {
- final Contact contact = conversation.getContact();
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.choose_presence));
- final String[] resourceArray = presences.toResourceArray();
- Pair<Map<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
- final Map<String, String> resourceTypeMap = typeAndName.first;
- final Map<String, String> resourceNameMap = typeAndName.second;
- final String[] readableIdentities = new String[resourceArray.length];
- final AtomicInteger selectedResource = new AtomicInteger(0);
- for (int i = 0; i < resourceArray.length; ++i) {
- String resource = resourceArray[i];
- if (resource.equals(contact.getLastResource())) {
- selectedResource.set(i);
- }
- String type = resourceTypeMap.get(resource);
- String name = resourceNameMap.get(resource);
- if (type != null) {
- if (Collections.frequency(resourceTypeMap.values(), type) == 1) {
- readableIdentities[i] = UIHelper.tranlasteType(this, type);
- } else if (name != null) {
- if (Collections.frequency(resourceNameMap.values(), name) == 1
- || CryptoHelper.UUID_PATTERN.matcher(resource).matches()) {
- readableIdentities[i] = UIHelper.tranlasteType(this, type) + " (" + name + ")";
- } else {
- readableIdentities[i] = UIHelper.tranlasteType(this, type) + " (" + name + " / " + resource + ")";
- }
- } else {
- readableIdentities[i] = UIHelper.tranlasteType(this, type) + " (" + resource + ")";
- }
- } else {
- readableIdentities[i] = resource;
- }
- }
- builder.setSingleChoiceItems(readableIdentities,
- selectedResource.get(),
- (dialog, which) -> selectedResource.set(which));
- builder.setNegativeButton(R.string.cancel, null);
- builder.setPositiveButton(R.string.ok, (dialog, which) -> {
- try {
- Jid next = Jid.fromParts(contact.getJid().getLocalpart(), contact.getJid().getDomainpart(), resourceArray[selectedResource.get()]);
- conversation.setNextCounterpart(next);
- } catch (InvalidJidException e) {
- conversation.setNextCounterpart(null);
- }
- listener.onPresenceSelected();
- });
- builder.create().show();
- }
-
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) {
@@ -1048,10 +979,6 @@ public abstract class XmppActivity extends AppCompatActivity {
String onValueEdited(String value);
}
- public interface OnPresenceSelected {
- void onPresenceSelected();
- }
-
public static class ConferenceInvite {
private String uuid;
private List<Jid> jids = new ArrayList<>();
@@ -533,7 +533,8 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
@Override
public void onClick(View v) {
- activity.startDownloadable(message);
+ //TODO make proper reference to fragment
+ //activity.startDownloadable(message);
}
});
}
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package eu.siacs.conversations.ui.util;
+
+import android.content.Intent;
+
+public class ActivityResult {
+
+ public final int requestCode;
+ public final int resultCode;
+ public final Intent data;
+
+ private ActivityResult(int requestCode, int resultCode, final Intent data) {
+ this.requestCode = requestCode;
+ this.resultCode = resultCode;
+ this.data = data;
+ }
+
+ public static ActivityResult of(int requestCode, int resultCode, Intent data) {
+ return new ActivityResult(requestCode,resultCode,data);
+ }
+
+}
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package eu.siacs.conversations.ui.util;
+
+import android.annotation.SuppressLint;
+import android.content.ClipData;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AttachmentTool {
+ @SuppressLint("NewApi")
+ public static List<Uri> extractUriFromIntent(final Intent intent) {
+ List<Uri> uris = new ArrayList<>();
+ if (intent == null) {
+ return uris;
+ }
+ Uri uri = intent.getData();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) {
+ final ClipData clipData = intent.getClipData();
+ if (clipData != null) {
+ for (int i = 0; i < clipData.getItemCount(); ++i) {
+ uris.add(clipData.getItemAt(i).getUri());
+ }
+ }
+ } else {
+ uris.add(uri);
+ }
+ return uris;
+ }
+}
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2018, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package eu.siacs.conversations.ui.util;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.provider.MediaStore;
+import android.support.annotation.NonNull;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+
+public class ConversationMenuConfigurator {
+
+ private static boolean showSoundRecorderAttachment = false;
+ private static boolean showLocationAttachment = false;
+
+
+ public static void configureAttachmentMenu(@NonNull Conversation conversation, Menu menu) {
+ final MenuItem menuAttachSoundRecorder = menu.findItem(R.id.attach_record_voice);
+ final MenuItem menuAttachLocation = menu.findItem(R.id.attach_location);
+ final MenuItem menuAttach = menu.findItem(R.id.action_attach_file);
+
+ final boolean visible;
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ visible = conversation.getAccount().httpUploadAvailable() && conversation.getMucOptions().participating();
+ } else {
+ visible = true;
+ }
+
+ menuAttach.setVisible(visible);
+
+ if (!visible) {
+ return;
+ }
+
+ menuAttachLocation.setVisible(showLocationAttachment);
+ menuAttachSoundRecorder.setVisible(showSoundRecorderAttachment);
+ }
+
+ public static void configureEncryptionMenu(@NonNull Conversation conversation, Menu menu) {
+ final MenuItem menuSecure = menu.findItem(R.id.action_security);
+ final MenuItem none = menu.findItem(R.id.encryption_choice_none);
+ final MenuItem pgp = menu.findItem(R.id.encryption_choice_pgp);
+ final MenuItem axolotl = menu.findItem(R.id.encryption_choice_axolotl);
+
+ boolean visible;
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ visible = (Config.supportOpenPgp() || Config.supportOmemo()) && Config.multipleEncryptionChoices();
+ } else {
+ visible = Config.multipleEncryptionChoices();
+ }
+
+ menuSecure.setVisible(visible);
+
+ if (!visible) {
+ return;
+ }
+
+ if (conversation.getNextEncryption() != Message.ENCRYPTION_NONE) {
+ menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
+ }
+
+ pgp.setVisible(Config.supportOpenPgp());
+ none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
+ axolotl.setVisible(Config.supportOmemo());
+ final AxolotlService axolotlService = conversation.getAccount().getAxolotlService();
+ if (axolotlService == null || !axolotlService.isConversationAxolotlCapable(conversation)) {
+ axolotl.setEnabled(false);
+ }
+ switch (conversation.getNextEncryption()) {
+ case Message.ENCRYPTION_NONE:
+ none.setChecked(true);
+ break;
+ case Message.ENCRYPTION_PGP:
+ pgp.setChecked(true);
+ break;
+ case Message.ENCRYPTION_AXOLOTL:
+ axolotl.setChecked(true);
+ break;
+ default:
+ none.setChecked(true);
+ break;
+ }
+ }
+
+ public static void updateAttachmentAvailability(PackageManager packageManager) {
+ showSoundRecorderAttachment = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION).resolveActivity(packageManager) != null;
+ showLocationAttachment = new Intent("eu.siacs.conversations.location.request").resolveActivity(packageManager) != null;
+ }
+}
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2018, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package eu.siacs.conversations.ui.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.support.v7.app.AlertDialog;
+import android.util.Pair;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.utils.CryptoHelper;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
+public class PresenceSelector {
+
+ public static void showPresenceSelectionDialog(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
+ final Contact contact = conversation.getContact();
+ final Presences presences = contact.getPresences();
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(activity.getString(R.string.choose_presence));
+ final String[] resourceArray = presences.toResourceArray();
+ Pair<Map<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
+ final Map<String, String> resourceTypeMap = typeAndName.first;
+ final Map<String, String> resourceNameMap = typeAndName.second;
+ final String[] readableIdentities = new String[resourceArray.length];
+ final AtomicInteger selectedResource = new AtomicInteger(0);
+ for (int i = 0; i < resourceArray.length; ++i) {
+ String resource = resourceArray[i];
+ if (resource.equals(contact.getLastResource())) {
+ selectedResource.set(i);
+ }
+ String type = resourceTypeMap.get(resource);
+ String name = resourceNameMap.get(resource);
+ if (type != null) {
+ if (Collections.frequency(resourceTypeMap.values(), type) == 1) {
+ readableIdentities[i] = translateType(activity, type);
+ } else if (name != null) {
+ if (Collections.frequency(resourceNameMap.values(), name) == 1
+ || CryptoHelper.UUID_PATTERN.matcher(resource).matches()) {
+ readableIdentities[i] = translateType(activity, type) + " (" + name + ")";
+ } else {
+ readableIdentities[i] = translateType(activity, type) + " (" + name + " / " + resource + ")";
+ }
+ } else {
+ readableIdentities[i] = translateType(activity, type) + " (" + resource + ")";
+ }
+ } else {
+ readableIdentities[i] = resource;
+ }
+ }
+ builder.setSingleChoiceItems(readableIdentities,
+ selectedResource.get(),
+ (dialog, which) -> selectedResource.set(which));
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.ok, (dialog, which) -> {
+ try {
+ Jid next = Jid.fromParts(contact.getJid().getLocalpart(), contact.getJid().getDomainpart(), resourceArray[selectedResource.get()]);
+ conversation.setNextCounterpart(next);
+ } catch (InvalidJidException e) {
+ conversation.setNextCounterpart(null);
+ }
+ listener.onPresenceSelected();
+ });
+ builder.create().show();
+ }
+
+ public static void warnMutualPresenceSubscription(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(conversation.getContact().getJid().toString());
+ builder.setMessage(R.string.without_mutual_presence_updates);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.ignore, (dialog, which) -> {
+ conversation.setNextCounterpart(null);
+ if (listener != null) {
+ listener.onPresenceSelected();
+ }
+ });
+ builder.create().show();
+ }
+
+ private static String translateType(Context context, String type) {
+ switch (type.toLowerCase()) {
+ case "pc":
+ return context.getString(R.string.type_pc);
+ case "phone":
+ return context.getString(R.string.type_phone);
+ case "tablet":
+ return context.getString(R.string.type_tablet);
+ case "web":
+ return context.getString(R.string.type_web);
+ case "console":
+ return context.getString(R.string.type_console);
+ default:
+ return type;
+ }
+ }
+
+ public interface OnPresenceSelected {
+ void onPresenceSelected();
+ }
+}
@@ -29,11 +29,11 @@
package eu.siacs.conversations.ui.util;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_CHOOSE_IMAGE;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_LOCATION;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_RECORD_VIDEO;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_RECORD_VOICE;
-import static eu.siacs.conversations.ui.ConversationActivity.ATTACHMENT_CHOICE_TAKE_PHOTO;
+import static eu.siacs.conversations.ui.ConversationFragment.ATTACHMENT_CHOICE_CHOOSE_IMAGE;
+import static eu.siacs.conversations.ui.ConversationFragment.ATTACHMENT_CHOICE_LOCATION;
+import static eu.siacs.conversations.ui.ConversationFragment.ATTACHMENT_CHOICE_RECORD_VIDEO;
+import static eu.siacs.conversations.ui.ConversationFragment.ATTACHMENT_CHOICE_RECORD_VOICE;
+import static eu.siacs.conversations.ui.ConversationFragment.ATTACHMENT_CHOICE_TAKE_PHOTO;
public enum SendButtonAction {
TEXT, TAKE_PHOTO, SEND_LOCATION, RECORD_VOICE, CANCEL, CHOOSE_PICTURE, RECORD_VIDEO;
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2018, Daniel Gultsch All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package eu.siacs.conversations.ui.util;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.preference.PreferenceManager;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Presence;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.ConversationFragment;
+import eu.siacs.conversations.utils.UIHelper;
+
+public class SendButtonTool {
+
+ public static SendButtonAction getAction(Activity activity, Conversation c, String text) {
+ final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
+ final boolean empty = text.length() == 0;
+ final boolean conference = c.getMode() == Conversation.MODE_MULTI;
+ if (c.getCorrectingMessage() != null && (empty || text.equals(c.getCorrectingMessage().getBody()))) {
+ return SendButtonAction.CANCEL;
+ } else if (conference && !c.getAccount().httpUploadAvailable()) {
+ if (empty && c.getNextCounterpart() != null) {
+ return SendButtonAction.CANCEL;
+ } else {
+ return SendButtonAction.TEXT;
+ }
+ } else {
+ if (empty) {
+ if (conference && c.getNextCounterpart() != null) {
+ return SendButtonAction.CANCEL;
+ } else {
+ String setting = preferences.getString("quick_action", activity.getResources().getString(R.string.quick_action));
+ if (!setting.equals("none") && UIHelper.receivedLocationQuestion(c.getLatestMessage())) {
+ return SendButtonAction.SEND_LOCATION;
+ } else {
+ if (setting.equals("recent")) {
+ setting = preferences.getString(ConversationFragment.RECENTLY_USED_QUICK_ACTION, SendButtonAction.TEXT.toString());
+ return SendButtonAction.valueOfOrDefault(setting, SendButtonAction.TEXT);
+ } else {
+ return SendButtonAction.valueOfOrDefault(setting, SendButtonAction.TEXT);
+ }
+ }
+ }
+ } else {
+ return SendButtonAction.TEXT;
+ }
+ }
+ }
+
+ public static int getSendButtonImageResource(Activity activity, SendButtonAction action, Presence.Status status) {
+ switch (action) {
+ case TEXT:
+ switch (status) {
+ case CHAT:
+ case ONLINE:
+ return R.drawable.ic_send_text_online;
+ case AWAY:
+ return R.drawable.ic_send_text_away;
+ case XA:
+ case DND:
+ return R.drawable.ic_send_text_dnd;
+ default:
+ return getThemeResource(activity, R.attr.ic_send_text_offline, R.drawable.ic_send_text_offline);
+ }
+ case RECORD_VIDEO:
+ switch (status) {
+ case CHAT:
+ case ONLINE:
+ return R.drawable.ic_send_videocam_online;
+ case AWAY:
+ return R.drawable.ic_send_videocam_away;
+ case XA:
+ case DND:
+ return R.drawable.ic_send_videocam_dnd;
+ default:
+ return getThemeResource(activity, R.attr.ic_send_videocam_offline, R.drawable.ic_send_videocam_offline);
+ }
+ case TAKE_PHOTO:
+ switch (status) {
+ case CHAT:
+ case ONLINE:
+ return R.drawable.ic_send_photo_online;
+ case AWAY:
+ return R.drawable.ic_send_photo_away;
+ case XA:
+ case DND:
+ return R.drawable.ic_send_photo_dnd;
+ default:
+ return getThemeResource(activity, R.attr.ic_send_photo_offline, R.drawable.ic_send_photo_offline);
+ }
+ case RECORD_VOICE:
+ switch (status) {
+ case CHAT:
+ case ONLINE:
+ return R.drawable.ic_send_voice_online;
+ case AWAY:
+ return R.drawable.ic_send_voice_away;
+ case XA:
+ case DND:
+ return R.drawable.ic_send_voice_dnd;
+ default:
+ return getThemeResource(activity, R.attr.ic_send_voice_offline, R.drawable.ic_send_voice_offline);
+ }
+ case SEND_LOCATION:
+ switch (status) {
+ case CHAT:
+ case ONLINE:
+ return R.drawable.ic_send_location_online;
+ case AWAY:
+ return R.drawable.ic_send_location_away;
+ case XA:
+ case DND:
+ return R.drawable.ic_send_location_dnd;
+ default:
+ return getThemeResource(activity, R.attr.ic_send_location_offline, R.drawable.ic_send_location_offline);
+ }
+ case CANCEL:
+ switch (status) {
+ case CHAT:
+ case ONLINE:
+ return R.drawable.ic_send_cancel_online;
+ case AWAY:
+ return R.drawable.ic_send_cancel_away;
+ case XA:
+ case DND:
+ return R.drawable.ic_send_cancel_dnd;
+ default:
+ return getThemeResource(activity, R.attr.ic_send_cancel_offline, R.drawable.ic_send_cancel_offline);
+ }
+ case CHOOSE_PICTURE:
+ switch (status) {
+ case CHAT:
+ case ONLINE:
+ return R.drawable.ic_send_picture_online;
+ case AWAY:
+ return R.drawable.ic_send_picture_away;
+ case XA:
+ case DND:
+ return R.drawable.ic_send_picture_dnd;
+ default:
+ return getThemeResource(activity, R.attr.ic_send_picture_offline, R.drawable.ic_send_picture_offline);
+ }
+ }
+ return getThemeResource(activity, R.attr.ic_send_text_offline, R.drawable.ic_send_text_offline);
+ }
+
+ private static int getThemeResource(Activity activity, int r_attr_name, int r_drawable_def) {
+ int[] attrs = {r_attr_name};
+ TypedArray ta = activity.getTheme().obtainStyledAttributes(attrs);
+
+ int res = ta.getResourceId(0, r_drawable_def);
+ ta.recycle();
+
+ return res;
+ }
+
+}
@@ -532,21 +532,4 @@ public class UIHelper {
return new ListItem.Tag(context.getString(R.string.presence_online), 0xff259b24);
}
}
-
- public static String tranlasteType(Context context, String type) {
- switch (type.toLowerCase()) {
- case "pc":
- return context.getString(R.string.type_pc);
- case "phone":
- return context.getString(R.string.type_phone);
- case "tablet":
- return context.getString(R.string.type_tablet);
- case "web":
- return context.getString(R.string.type_web);
- case "console":
- return context.getString(R.string.type_console);
- default:
- return type;
- }
- }
}
@@ -0,0 +1,22 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/action_add"
+ android:icon="?attr/icon_new"
+ android:orderInCategory="10"
+ app:showAsAction="always"
+ android:title="@string/action_add"/>
+
+ <item
+ android:id="@+id/action_accounts"
+ android:orderInCategory="90"
+ app:showAsAction="never"
+ android:title="@string/action_accounts"/>
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ app:showAsAction="never"
+ android:title="@string/action_settings"/>
+
+</menu>
@@ -1,12 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
- <item
- android:id="@+id/action_add"
- android:icon="?attr/icon_new"
- android:orderInCategory="10"
- app:showAsAction="always"
- android:title="@string/action_add"/>
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_security"
android:icon="?attr/icon_not_secure"
@@ -103,16 +97,4 @@
android:orderInCategory="71"
app:showAsAction="never"
android:title="@string/enable_notifications"/>
-
- <item
- android:id="@+id/action_accounts"
- android:orderInCategory="90"
- app:showAsAction="never"
- android:title="@string/action_accounts"/>
- <item
- android:id="@+id/action_settings"
- android:orderInCategory="100"
- app:showAsAction="never"
- android:title="@string/action_settings"/>
-
</menu>