Merge pull request #1513 from fiaxh/pgp_background_decryption

PGP messages background decryption
This commit is contained in:
Daniel Gultsch 2015-10-30 10:18:27 +01:00
commit 6a458b853c
11 changed files with 295 additions and 76 deletions

View file

@ -0,0 +1,162 @@
package eu.siacs.conversations.crypto;
import android.app.PendingIntent;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.UiCallback;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
public class PgpDecryptionService {
private final XmppConnectionService xmppConnectionService;
private final ConcurrentHashMap<String, List<Message>> messages = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Boolean> decryptingMessages = new ConcurrentHashMap<>();
private Boolean keychainLocked = false;
private final Object keychainLockedLock = new Object();
public PgpDecryptionService(XmppConnectionService xmppConnectionService) {
this.xmppConnectionService = xmppConnectionService;
}
public void add(Message message) {
if (isRunning()) {
decryptDirectly(message);
} else {
store(message);
}
}
public void addAll(List<Message> messagesList) {
if (!messagesList.isEmpty()) {
String conversationUuid = messagesList.get(0).getConversation().getUuid();
if (!messages.containsKey(conversationUuid)) {
List<Message> list = Collections.synchronizedList(new LinkedList<Message>());
messages.put(conversationUuid, list);
}
synchronized (messages.get(conversationUuid)) {
messages.get(conversationUuid).addAll(messagesList);
}
decryptAllMessages();
}
}
public void onKeychainUnlocked() {
synchronized (keychainLockedLock) {
keychainLocked = false;
}
decryptAllMessages();
}
public void onKeychainLocked() {
synchronized (keychainLockedLock) {
keychainLocked = true;
}
xmppConnectionService.updateConversationUi();
}
public void onOpenPgpServiceBound() {
decryptAllMessages();
}
public boolean isRunning() {
synchronized (keychainLockedLock) {
return !keychainLocked;
}
}
private void store(Message message) {
if (messages.containsKey(message.getConversation().getUuid())) {
messages.get(message.getConversation().getUuid()).add(message);
} else {
List<Message> messageList = Collections.synchronizedList(new LinkedList<Message>());
messageList.add(message);
messages.put(message.getConversation().getUuid(), messageList);
}
}
private void decryptAllMessages() {
for (String uuid : messages.keySet()) {
decryptMessages(uuid);
}
}
private void decryptMessages(final String uuid) {
synchronized (decryptingMessages) {
Boolean decrypting = decryptingMessages.get(uuid);
if ((decrypting != null && !decrypting) || decrypting == null) {
decryptingMessages.put(uuid, true);
decryptMessage(uuid);
}
}
}
private void decryptMessage(final String uuid) {
Message message = null;
synchronized (messages.get(uuid)) {
while (!messages.get(uuid).isEmpty()) {
if (messages.get(uuid).get(0).getEncryption() == Message.ENCRYPTION_PGP) {
if (isRunning()) {
message = messages.get(uuid).remove(0);
}
break;
} else {
messages.get(uuid).remove(0);
}
}
if (message != null && xmppConnectionService.getPgpEngine() != null) {
xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback<Message>() {
@Override
public void userInputRequried(PendingIntent pi, Message message) {
messages.get(uuid).add(0, message);
decryptingMessages.put(uuid, false);
}
@Override
public void success(Message message) {
xmppConnectionService.updateConversationUi();
decryptMessage(uuid);
}
@Override
public void error(int error, Message message) {
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
xmppConnectionService.updateConversationUi();
decryptMessage(uuid);
}
});
} else {
decryptingMessages.put(uuid, false);
}
}
}
private void decryptDirectly(final Message message) {
if (message.getEncryption() == Message.ENCRYPTION_PGP && xmppConnectionService.getPgpEngine() != null) {
xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback<Message>() {
@Override
public void userInputRequried(PendingIntent pi, Message message) {
store(message);
}
@Override
public void success(Message message) {
xmppConnectionService.updateConversationUi();
xmppConnectionService.getNotificationService().updateNotification(false);
}
@Override
public void error(int error, Message message) {
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
xmppConnectionService.updateConversationUi();
}
});
}
}
}

View file

@ -50,6 +50,7 @@ public class PgpEngine {
@Override @Override
public void onReturn(Intent result) { public void onReturn(Intent result) {
notifyPgpDecryptionService(message.getContact().getAccount(), OpenPgpApi.ACTION_DECRYPT_VERIFY, result);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
OpenPgpApi.RESULT_CODE_ERROR)) { OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
@ -64,6 +65,7 @@ public class PgpEngine {
&& manager.getAutoAcceptFileSize() > 0) { && manager.getAutoAcceptFileSize() > 0) {
manager.createNewDownloadConnection(message); manager.createNewDownloadConnection(message);
} }
mXmppConnectionService.updateMessage(message);
callback.success(message); callback.success(message);
} }
} catch (IOException e) { } catch (IOException e) {
@ -158,6 +160,7 @@ public class PgpEngine {
@Override @Override
public void onReturn(Intent result) { public void onReturn(Intent result) {
notifyPgpDecryptionService(message.getContact().getAccount(), OpenPgpApi.ACTION_ENCRYPT, result);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
OpenPgpApi.RESULT_CODE_ERROR)) { OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
@ -203,6 +206,7 @@ public class PgpEngine {
@Override @Override
public void onReturn(Intent result) { public void onReturn(Intent result) {
notifyPgpDecryptionService(message.getContact().getAccount(), OpenPgpApi.ACTION_ENCRYPT, result);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
OpenPgpApi.RESULT_CODE_ERROR)) { OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
@ -252,6 +256,7 @@ public class PgpEngine {
InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes()); InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
Intent result = api.executeApi(params, is, os); Intent result = api.executeApi(params, is, os);
notifyPgpDecryptionService(account, OpenPgpApi.ACTION_DECRYPT_VERIFY, result);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
OpenPgpApi.RESULT_CODE_ERROR)) { OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
@ -282,6 +287,7 @@ public class PgpEngine {
@Override @Override
public void onReturn(Intent result) { public void onReturn(Intent result) {
notifyPgpDecryptionService(account, OpenPgpApi.ACTION_SIGN, result);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) { switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: case OpenPgpApi.RESULT_CODE_SUCCESS:
StringBuilder signatureBuilder = new StringBuilder(); StringBuilder signatureBuilder = new StringBuilder();
@ -368,4 +374,17 @@ public class PgpEngine {
return (PendingIntent) result return (PendingIntent) result
.getParcelableExtra(OpenPgpApi.RESULT_INTENT); .getParcelableExtra(OpenPgpApi.RESULT_INTENT);
} }
private void notifyPgpDecryptionService(Account account, String action, final Intent result) {
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
case OpenPgpApi.RESULT_CODE_SUCCESS:
if (OpenPgpApi.ACTION_SIGN.equals(action)) {
account.getPgpDecryptionService().onKeychainUnlocked();
}
break;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
account.getPgpDecryptionService().onKeychainLocked();
break;
}
}
} }

View file

@ -4,6 +4,7 @@ import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.os.SystemClock; import android.os.SystemClock;
import eu.siacs.conversations.crypto.PgpDecryptionService;
import net.java.otr4j.crypto.OtrCryptoEngineImpl; import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException; import net.java.otr4j.crypto.OtrCryptoException;
@ -137,6 +138,7 @@ public class Account extends AbstractEntity {
protected boolean online = false; protected boolean online = false;
private OtrService mOtrService = null; private OtrService mOtrService = null;
private AxolotlService axolotlService = null; private AxolotlService axolotlService = null;
private PgpDecryptionService pgpDecryptionService = null;
private XmppConnection xmppConnection = null; private XmppConnection xmppConnection = null;
private long mEndGracePeriod = 0L; private long mEndGracePeriod = 0L;
private String otrFingerprint; private String otrFingerprint;
@ -313,12 +315,17 @@ public class Account extends AbstractEntity {
if (xmppConnection != null) { if (xmppConnection != null) {
xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService); xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
} }
this.pgpDecryptionService = new PgpDecryptionService(context);
} }
public OtrService getOtrService() { public OtrService getOtrService() {
return this.mOtrService; return this.mOtrService;
} }
public PgpDecryptionService getPgpDecryptionService() {
return pgpDecryptionService;
}
public XmppConnection getXmppConnection() { public XmppConnection getXmppConnection() {
return this.xmppConnection; return this.xmppConnection;
} }

View file

@ -777,6 +777,7 @@ public class Conversation extends AbstractEntity implements Blockable {
synchronized (this.messages) { synchronized (this.messages) {
this.messages.addAll(index, messages); this.messages.addAll(index, messages);
} }
account.getPgpDecryptionService().addAll(messages);
} }
public void sort() { public void sort() {

View file

@ -3,6 +3,7 @@ package eu.siacs.conversations.parser;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import eu.siacs.conversations.crypto.PgpDecryptionService;
import net.java.otr4j.session.Session; import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus; import net.java.otr4j.session.SessionStatus;
@ -114,6 +115,13 @@ public class MessageParser extends AbstractParser implements
return finishedMessage; return finishedMessage;
} }
private Message parsePGPChat(final Conversation conversation, String pgpEncrypted, int status) {
final Message message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
PgpDecryptionService pgpDecryptionService = conversation.getAccount().getPgpDecryptionService();
pgpDecryptionService.add(message);
return message;
}
private class Invite { private class Invite {
Jid jid; Jid jid;
String password; String password;
@ -337,7 +345,7 @@ public class MessageParser extends AbstractParser implements
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status); message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
} }
} else if (pgpEncrypted != null) { } else if (pgpEncrypted != null) {
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status); message = parsePGPChat(conversation, pgpEncrypted, status);
} else if (axolotlEncrypted != null) { } else if (axolotlEncrypted != null) {
message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status); message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status);
if (message == null) { if (message == null) {

View file

@ -177,7 +177,7 @@ public class NotificationService {
mBuilder.setColor(mXmppConnectionService.getResources().getColor(R.color.primary)); mBuilder.setColor(mXmppConnectionService.getResources().getColor(R.color.primary));
} }
private void updateNotification(final boolean notify) { public void updateNotification(final boolean notify) {
final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService
.getSystemService(Context.NOTIFICATION_SERVICE); .getSystemService(Context.NOTIFICATION_SERVICE);
final SharedPreferences preferences = mXmppConnectionService.getPreferences(); final SharedPreferences preferences = mXmppConnectionService.getPreferences();

View file

@ -37,6 +37,7 @@ import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionImpl; import net.java.otr4j.session.SessionImpl;
import net.java.otr4j.session.SessionStatus; import net.java.otr4j.session.SessionStatus;
import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection; import org.openintents.openpgp.util.OpenPgpServiceConnection;
@ -659,7 +660,19 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver); getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
this.fileObserver.startWatching(); this.fileObserver.startWatching();
this.pgpServiceConnection = new OpenPgpServiceConnection(getApplicationContext(), "org.sufficientlysecure.keychain"); this.pgpServiceConnection = new OpenPgpServiceConnection(getApplicationContext(), "org.sufficientlysecure.keychain", new OpenPgpServiceConnection.OnBound() {
@Override
public void onBound(IOpenPgpService service) {
for (Account account : accounts) {
if (account.getPgpDecryptionService() != null) {
account.getPgpDecryptionService().onOpenPgpServiceBound();
}
}
}
@Override
public void onError(Exception e) { }
});
this.pgpServiceConnection.bindToService(); this.pgpServiceConnection.bindToService();
this.pm = (PowerManager) getSystemService(Context.POWER_SERVICE); this.pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

View file

@ -1194,8 +1194,7 @@ public class ConversationActivity extends XmppActivity
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_DECRYPT_PGP) { if (requestCode == REQUEST_DECRYPT_PGP) {
mConversationFragment.hideSnackbar(); mConversationFragment.onActivityResult(requestCode, resultCode, data);
mConversationFragment.updateMessages();
} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
mPendingImageUris.clear(); mPendingImageUris.clear();
mPendingImageUris.addAll(extractUriFromIntent(data)); mPendingImageUris.addAll(extractUriFromIntent(data));
@ -1240,6 +1239,9 @@ public class ConversationActivity extends XmppActivity
} else { } else {
mPendingImageUris.clear(); mPendingImageUris.clear();
mPendingFileUris.clear(); mPendingFileUris.clear();
if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
mConversationFragment.onActivityResult(requestCode, resultCode, data);
}
} }
} }

View file

@ -11,6 +11,7 @@ import android.content.Intent;
import android.content.IntentSender; import android.content.IntentSender;
import android.content.IntentSender.SendIntentException; import android.content.IntentSender.SendIntentException;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.InputType; import android.text.InputType;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
@ -199,21 +200,47 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
} }
} }
}; };
private IntentSender askForPassphraseIntent = null; private final int KEYCHAIN_UNLOCK_NOT_REQUIRED = 0;
private final int KEYCHAIN_UNLOCK_REQUIRED = 1;
private final int KEYCHAIN_UNLOCK_PENDING = 2;
private int keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
protected OnClickListener clickToDecryptListener = new OnClickListener() { protected OnClickListener clickToDecryptListener = new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (activity.hasPgp() && askForPassphraseIntent != null) { if (keychainUnlock == KEYCHAIN_UNLOCK_REQUIRED
try { && activity.hasPgp() && !conversation.getAccount().getPgpDecryptionService().isRunning()) {
getActivity().startIntentSenderForResult( keychainUnlock = KEYCHAIN_UNLOCK_PENDING;
askForPassphraseIntent, updateSnackBar(conversation);
ConversationActivity.REQUEST_DECRYPT_PGP, null, 0, Message message = getLastPgpDecryptableMessage();
0, 0); if (message != null) {
askForPassphraseIntent = null; activity.xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback<Message>() {
} catch (SendIntentException e) { @Override
// public void success(Message object) {
conversation.getAccount().getPgpDecryptionService().onKeychainUnlocked();
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
}
@Override
public void error(int errorCode, Message object) {
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
}
@Override
public void userInputRequried(PendingIntent pi, Message object) {
try {
activity.startIntentSenderForResult(pi.getIntentSender(),
ConversationActivity.REQUEST_DECRYPT_PGP, null, 0, 0, 0);
} catch (SendIntentException e) {
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
updatePgpMessages();
}
}
});
} }
} else {
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
updatePgpMessages();
} }
} }
}; };
@ -224,8 +251,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
activity.verifyOtrSessionDialog(conversation, v); activity.verifyOtrSessionDialog(conversation, v);
} }
}; };
private ConcurrentLinkedQueue<Message> mEncryptedMessages = new ConcurrentLinkedQueue<>();
private boolean mDecryptJobRunning = false;
private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() { private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() {
@Override @Override
@ -629,7 +654,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
@Override @Override
public void onStop() { public void onStop() {
mDecryptJobRunning = false;
super.onStop(); super.onStop();
if (this.conversation != null) { if (this.conversation != null) {
final String msg = mEditMessage.getText().toString(); final String msg = mEditMessage.getText().toString();
@ -661,10 +685,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
this.conversation.trim(); this.conversation.trim();
} }
this.askForPassphraseIntent = null; this.keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
this.conversation = conversation; this.conversation = conversation;
this.mDecryptJobRunning = false;
this.mEncryptedMessages.clear();
if (this.conversation.getMode() == Conversation.MODE_MULTI) { if (this.conversation.getMode() == Conversation.MODE_MULTI) {
this.conversation.setNextCounterpart(null); this.conversation.setNextCounterpart(null);
} }
@ -767,7 +789,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
default: default:
break; break;
} }
} else if (askForPassphraseIntent != null) { } else if (keychainUnlock == KEYCHAIN_UNLOCK_REQUIRED) {
showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener); showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener);
} else if (mode == Conversation.MODE_SINGLE } else if (mode == Conversation.MODE_SINGLE
&& conversation.smpRequested()) { && conversation.smpRequested()) {
@ -791,19 +813,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
} }
final ConversationActivity activity = (ConversationActivity) getActivity(); final ConversationActivity activity = (ConversationActivity) getActivity();
if (this.conversation != null) { if (this.conversation != null) {
updateSnackBar(this.conversation);
conversation.populateWithMessages(ConversationFragment.this.messageList); conversation.populateWithMessages(ConversationFragment.this.messageList);
for (final Message message : this.messageList) { updatePgpMessages();
if (message.getEncryption() == Message.ENCRYPTION_PGP updateSnackBar(conversation);
&& (message.getStatus() == Message.STATUS_RECEIVED || message
.getStatus() >= Message.STATUS_SEND)
&& message.getTransferable() == null) {
if (!mEncryptedMessages.contains(message)) {
mEncryptedMessages.add(message);
}
}
}
decryptNext();
updateStatusMessages(); updateStatusMessages();
this.messageListAdapter.notifyDataSetChanged(); this.messageListAdapter.notifyDataSetChanged();
updateChatMsgHint(); updateChatMsgHint();
@ -815,48 +827,29 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
} }
} }
private void decryptNext() { public void updatePgpMessages() {
Message next = this.mEncryptedMessages.peek(); if (keychainUnlock != KEYCHAIN_UNLOCK_PENDING) {
PgpEngine engine = activity.xmppConnectionService.getPgpEngine(); if (getLastPgpDecryptableMessage() != null
&& !conversation.getAccount().getPgpDecryptionService().isRunning()) {
if (next != null && engine != null && !mDecryptJobRunning) { keychainUnlock = KEYCHAIN_UNLOCK_REQUIRED;
mDecryptJobRunning = true; } else {
engine.decrypt(next, new UiCallback<Message>() { keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
}
@Override
public void userInputRequried(PendingIntent pi, Message message) {
mDecryptJobRunning = false;
askForPassphraseIntent = pi.getIntentSender();
updateSnackBar(conversation);
}
@Override
public void success(Message message) {
mDecryptJobRunning = false;
try {
mEncryptedMessages.remove();
} catch (final NoSuchElementException ignored) {
}
askForPassphraseIntent = null;
activity.xmppConnectionService.updateMessage(message);
}
@Override
public void error(int error, Message message) {
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
mDecryptJobRunning = false;
try {
mEncryptedMessages.remove();
} catch (final NoSuchElementException ignored) {
}
activity.refreshUi();
}
});
} }
} }
@Nullable
private Message getLastPgpDecryptableMessage() {
for (final Message message : this.messageList) {
if (message.getEncryption() == Message.ENCRYPTION_PGP
&& (message.getStatus() == Message.STATUS_RECEIVED || message.getStatus() >= Message.STATUS_SEND)
&& message.getTransferable() == null) {
return message;
}
}
return null;
}
private void messageSent() { private void messageSent() {
int size = this.messageList.size(); int size = this.messageList.size();
messagesView.setSelection(size - 1); messagesView.setSelection(size - 1);
@ -1274,7 +1267,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
public void onActivityResult(int requestCode, int resultCode, public void onActivityResult(int requestCode, int resultCode,
final Intent data) { final Intent data) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_TEXT) { if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
activity.getSelectedConversation().getAccount().getPgpDecryptionService().onKeychainUnlocked();
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
updatePgpMessages();
} else if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_TEXT) {
final String body = mEditMessage.getText().toString(); final String body = mEditMessage.getText().toString();
Message message = new Message(conversation, body, conversation.getNextEncryption()); Message message = new Message(conversation, body, conversation.getNextEncryption());
sendAxolotlMessage(message); sendAxolotlMessage(message);
@ -1282,6 +1279,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
int choice = data.getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID); int choice = data.getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID);
activity.selectPresenceToAttachFile(choice, conversation.getNextEncryption()); activity.selectPresenceToAttachFile(choice, conversation.getNextEncryption());
} }
} else {
if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
updatePgpMessages();
}
} }
} }

View file

@ -550,7 +550,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} }
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) { } else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
if (activity.hasPgp()) { if (activity.hasPgp()) {
displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message),darkBackground); if (account.getPgpDecryptionService().isRunning()) {
displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), darkBackground);
} else {
displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), darkBackground);
}
} else { } else {
displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground); displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground);
if (viewHolder != null) { if (viewHolder != null) {

View file

@ -30,7 +30,8 @@
<string name="minutes_ago">%d mins ago</string> <string name="minutes_ago">%d mins ago</string>
<string name="unread_conversations">unread Conversations</string> <string name="unread_conversations">unread Conversations</string>
<string name="sending">sending…</string> <string name="sending">sending…</string>
<string name="encrypted_message">Decrypting message. Please wait…</string> <string name="message_decrypting">Decrypting message. Please wait…</string>
<string name="pgp_message">OpenPGP encrypted message</string>
<string name="nick_in_use">Nickname is already in use</string> <string name="nick_in_use">Nickname is already in use</string>
<string name="admin">Admin</string> <string name="admin">Admin</string>
<string name="owner">Owner</string> <string name="owner">Owner</string>