add error message to failed messages. accessible via context menu

This commit is contained in:
Daniel Gultsch 2016-10-26 12:26:04 +02:00
parent a4020e85f6
commit 8557120ef8
10 changed files with 98 additions and 27 deletions

View file

@ -58,6 +58,7 @@ public class Message extends AbstractEntity {
public static final String RELATIVE_FILE_PATH = "relativeFilePath"; public static final String RELATIVE_FILE_PATH = "relativeFilePath";
public static final String FINGERPRINT = "axolotl_fingerprint"; public static final String FINGERPRINT = "axolotl_fingerprint";
public static final String READ = "read"; public static final String READ = "read";
public static final String ERROR_MESSAGE = "errorMsg";
public static final String ME_COMMAND = "/me "; public static final String ME_COMMAND = "/me ";
@ -83,6 +84,7 @@ public class Message extends AbstractEntity {
private Message mNextMessage = null; private Message mNextMessage = null;
private Message mPreviousMessage = null; private Message mPreviousMessage = null;
private String axolotlFingerprint = null; private String axolotlFingerprint = null;
private String errorMessage = null;
private Message() { private Message() {
@ -109,7 +111,8 @@ public class Message extends AbstractEntity {
null, null,
true, true,
null, null,
false); false,
null);
this.conversation = conversation; this.conversation = conversation;
} }
@ -118,7 +121,7 @@ public class Message extends AbstractEntity {
final int encryption, final int status, final int type, final boolean carbon, final int encryption, final int status, final int type, final boolean carbon,
final String remoteMsgId, final String relativeFilePath, final String remoteMsgId, final String relativeFilePath,
final String serverMsgId, final String fingerprint, final boolean read, final String serverMsgId, final String fingerprint, final boolean read,
final String edited, final boolean oob) { final String edited, final boolean oob, final String errorMessage) {
this.uuid = uuid; this.uuid = uuid;
this.conversationUuid = conversationUUid; this.conversationUuid = conversationUUid;
this.counterpart = counterpart; this.counterpart = counterpart;
@ -136,6 +139,7 @@ public class Message extends AbstractEntity {
this.read = read; this.read = read;
this.edited = edited; this.edited = edited;
this.oob = oob; this.oob = oob;
this.errorMessage = errorMessage;
} }
public static Message fromCursor(Cursor cursor) { public static Message fromCursor(Cursor cursor) {
@ -177,7 +181,8 @@ public class Message extends AbstractEntity {
cursor.getString(cursor.getColumnIndex(FINGERPRINT)), cursor.getString(cursor.getColumnIndex(FINGERPRINT)),
cursor.getInt(cursor.getColumnIndex(READ)) > 0, cursor.getInt(cursor.getColumnIndex(READ)) > 0,
cursor.getString(cursor.getColumnIndex(EDITED)), cursor.getString(cursor.getColumnIndex(EDITED)),
cursor.getInt(cursor.getColumnIndex(OOB)) > 0); cursor.getInt(cursor.getColumnIndex(OOB)) > 0,
cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)));
} }
public static Message createStatusMessage(Conversation conversation, String body) { public static Message createStatusMessage(Conversation conversation, String body) {
@ -224,6 +229,7 @@ public class Message extends AbstractEntity {
values.put(READ,read ? 1 : 0); values.put(READ,read ? 1 : 0);
values.put(EDITED, edited); values.put(EDITED, edited);
values.put(OOB, oob ? 1 : 0); values.put(OOB, oob ? 1 : 0);
values.put(ERROR_MESSAGE,errorMessage);
return values; return values;
} }
@ -271,6 +277,17 @@ public class Message extends AbstractEntity {
this.body = body; this.body = body;
} }
public String getErrorMessage() {
return errorMessage;
}
public boolean setErrorMessage(String message) {
boolean changed = (message != null && !message.equals(errorMessage))
|| (message == null && errorMessage != null);
this.errorMessage = message;
return changed;
}
public long getTimeSent() { public long getTimeSent() {
return timeSent; return timeSent;
} }

View file

@ -20,6 +20,7 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
@ -86,10 +87,10 @@ public class HttpUploadConnection implements Transferable {
this.canceled = true; this.canceled = true;
} }
private void fail() { private void fail(String errorMessage) {
mHttpConnectionManager.finishUploadConnection(this); mHttpConnectionManager.finishUploadConnection(this);
message.setTransferable(null); message.setTransferable(null);
mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED); mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, errorMessage);
FileBackend.close(mFileInputStream); FileBackend.close(mFileInputStream);
} }
@ -111,7 +112,7 @@ public class HttpUploadConnection implements Transferable {
pair = AbstractConnectionManager.createInputStream(file, true); pair = AbstractConnectionManager.createInputStream(file, true);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not find file to upload - "+e.getMessage()); Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not find file to upload - "+e.getMessage());
fail(); fail(e.getMessage());
return; return;
} }
this.file.setExpectedSize(pair.second); this.file.setExpectedSize(pair.second);
@ -137,7 +138,7 @@ public class HttpUploadConnection implements Transferable {
} }
} }
Log.d(Config.LOGTAG,account.getJid().toString()+": invalid response to slot request "+packet); Log.d(Config.LOGTAG,account.getJid().toString()+": invalid response to slot request "+packet);
fail(); fail(IqParser.extractErrorMessage(packet));
} }
}); });
message.setTransferable(this); message.setTransferable(this);
@ -206,12 +207,12 @@ public class HttpUploadConnection implements Transferable {
@Override @Override
public void error(int errorCode, Message object) { public void error(int errorCode, Message object) {
Log.d(Config.LOGTAG,"pgp encryption failed"); Log.d(Config.LOGTAG,"pgp encryption failed");
fail(); fail("pgp encryption failed");
} }
@Override @Override
public void userInputRequried(PendingIntent pi, Message object) { public void userInputRequried(PendingIntent pi, Message object) {
fail(); fail("pgp encryption failed");
} }
}); });
} else { } else {
@ -219,12 +220,12 @@ public class HttpUploadConnection implements Transferable {
} }
} else { } else {
Log.d(Config.LOGTAG,"http upload failed because response code was "+code); Log.d(Config.LOGTAG,"http upload failed because response code was "+code);
fail(); fail("http upload failed because response code was "+code);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
Log.d(Config.LOGTAG,"http upload failed "+e.getMessage()); Log.d(Config.LOGTAG,"http upload failed "+e.getMessage());
fail(); fail(e.getMessage());
} finally { } finally {
FileBackend.close(mFileInputStream); FileBackend.close(mFileInputStream);
FileBackend.close(os); FileBackend.close(os);

View file

@ -92,4 +92,18 @@ public abstract class AbstractParser {
user.setRole(role); user.setRole(role);
return user; return user;
} }
public static String extractErrorMessage(Element packet) {
final Element error = packet.findChild("error");
if (error != null && error.getChildren().size() > 0) {
final String text = error.findChildContent("text");
if (text != null && !text.trim().isEmpty()) {
return text;
} else {
return error.getChildren().get(0).getName().replace("-"," ");
}
} else {
return null;
}
}
} }

View file

@ -266,19 +266,15 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
if (packet.getType() == MessagePacket.TYPE_ERROR) { if (packet.getType() == MessagePacket.TYPE_ERROR) {
Jid from = packet.getFrom(); Jid from = packet.getFrom();
if (from != null) { if (from != null) {
Element error = packet.findChild("error");
String text = error == null ? null : error.findChildContent("text");
if (text != null) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": sending message to "+ from+ " failed - " + text);
} else if (error != null) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": sending message to "+ from+ " failed - " + error);
}
Message message = mXmppConnectionService.markMessage(account, Message message = mXmppConnectionService.markMessage(account,
from.toBareJid(), from.toBareJid(),
packet.getId(), packet.getId(),
Message.STATUS_SEND_FAILED); Message.STATUS_SEND_FAILED,
if (message != null && message.getEncryption() == Message.ENCRYPTION_OTR) { extractErrorMessage(packet));
message.getConversation().endOtrIfNeeded(); if (message != null) {
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
message.getConversation().endOtrIfNeeded();
}
} }
} }
return true; return true;

View file

@ -54,7 +54,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
private static DatabaseBackend instance = null; private static DatabaseBackend instance = null;
private static final String DATABASE_NAME = "history"; private static final String DATABASE_NAME = "history";
private static final int DATABASE_VERSION = 28; private static final int DATABASE_VERSION = 29;
private static String CREATE_CONTATCS_STATEMENT = "create table " private static String CREATE_CONTATCS_STATEMENT = "create table "
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
@ -181,6 +181,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ Message.EDITED + " TEXT, " + Message.EDITED + " TEXT, "
+ Message.READ + " NUMBER DEFAULT 1, " + Message.READ + " NUMBER DEFAULT 1, "
+ Message.OOB + " INTEGER, " + Message.OOB + " INTEGER, "
+ Message.ERROR_MESSAGE + " TEXT,"
+ Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY(" + Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY("
+ Message.CONVERSATION + ") REFERENCES " + Message.CONVERSATION + ") REFERENCES "
+ Conversation.TABLENAME + "(" + Conversation.UUID + Conversation.TABLENAME + "(" + Conversation.UUID
@ -333,6 +334,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (oldVersion < 28 && newVersion >= 28) { if (oldVersion < 28 && newVersion >= 28) {
canonicalizeJids(db); canonicalizeJids(db);
} }
if (oldVersion < 29 && newVersion >= 29) {
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.ERROR_MESSAGE + " TEXT");
}
} }
private void canonicalizeJids(SQLiteDatabase db) { private void canonicalizeJids(SQLiteDatabase db) {

View file

@ -2946,6 +2946,10 @@ public class XmppConnectionService extends Service {
} }
public Message markMessage(final Account account, final Jid recipient, final String uuid, final int status) { public Message markMessage(final Account account, final Jid recipient, final String uuid, final int status) {
return markMessage(account, recipient, uuid, status, null);
}
public Message markMessage(final Account account, final Jid recipient, final String uuid, final int status, String errorMessage) {
if (uuid == null) { if (uuid == null) {
return null; return null;
} }
@ -2953,7 +2957,7 @@ public class XmppConnectionService extends Service {
if (conversation.getJid().toBareJid().equals(recipient) && conversation.getAccount() == account) { if (conversation.getJid().toBareJid().equals(recipient) && conversation.getAccount() == account) {
final Message message = conversation.findSentMessageWithUuidOrRemoteId(uuid); final Message message = conversation.findSentMessageWithUuidOrRemoteId(uuid);
if (message != null) { if (message != null) {
markMessage(message, status); markMessage(message, status, errorMessage);
} }
return message; return message;
} }
@ -2976,11 +2980,18 @@ public class XmppConnectionService extends Service {
} }
public void markMessage(Message message, int status) { public void markMessage(Message message, int status) {
markMessage(message, status, null);
}
public void markMessage(Message message, int status, String errorMessage) {
if (status == Message.STATUS_SEND_FAILED if (status == Message.STATUS_SEND_FAILED
&& (message.getStatus() == Message.STATUS_SEND_RECEIVED || message && (message.getStatus() == Message.STATUS_SEND_RECEIVED || message
.getStatus() == Message.STATUS_SEND_DISPLAYED)) { .getStatus() == Message.STATUS_SEND_DISPLAYED)
&& errorMessage == null) {
return; return;
} }
message.setErrorMessage(errorMessage);
message.setStatus(status); message.setStatus(status);
databaseBackend.updateMessage(message); databaseBackend.updateMessage(message);
updateConversationUi(); updateConversationUi();

View file

@ -546,6 +546,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
MenuItem downloadFile = menu.findItem(R.id.download_file); MenuItem downloadFile = menu.findItem(R.id.download_file);
MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission); MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission);
MenuItem deleteFile = menu.findItem(R.id.delete_file); MenuItem deleteFile = menu.findItem(R.id.delete_file);
MenuItem showErrorMessage = menu.findItem(R.id.show_error_message);
if (!treatAsFile if (!treatAsFile
&& !GeoHelper.isGeoUri(m.getBody()) && !GeoHelper.isGeoUri(m.getBody())
&& m.treatAsDownloadable() != Message.Decision.MUST) { && m.treatAsDownloadable() != Message.Decision.MUST) {
@ -589,6 +590,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
deleteFile.setTitle(activity.getString(R.string.delete_x_file, UIHelper.getFileDescriptionString(activity, m))); deleteFile.setTitle(activity.getString(R.string.delete_x_file, UIHelper.getFileDescriptionString(activity, m)));
} }
} }
if (m.getStatus() == Message.STATUS_SEND_FAILED && m.getErrorMessage() != null) {
showErrorMessage.setVisible(true);
}
} }
} }
@ -625,11 +629,22 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
case R.id.delete_file: case R.id.delete_file:
deleteFile(selectedMessage); deleteFile(selectedMessage);
return true; return true;
case R.id.show_error_message:
showErrorMessage(selectedMessage);
return true;
default: default:
return super.onContextItemSelected(item); return super.onContextItemSelected(item);
} }
} }
private void showErrorMessage(final Message message) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.error_message);
builder.setMessage(message.getErrorMessage());
builder.setPositiveButton(R.string.confirm,null);
builder.create().show();
}
private void shareWith(Message message) { private void shareWith(Message message) {
Intent shareIntent = new Intent(); Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setAction(Intent.ACTION_SEND);

View file

@ -25,6 +25,7 @@ import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.entities.ServiceDiscoveryResult; import eu.siacs.conversations.entities.ServiceDiscoveryResult;
import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
@ -87,7 +88,7 @@ public class JingleConnection implements Transferable {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(Account account, IqPacket packet) {
if (packet.getType() != IqPacket.TYPE.RESULT) { if (packet.getType() != IqPacket.TYPE.RESULT) {
fail(); fail(IqParser.extractErrorMessage(packet));
} }
} }
}; };
@ -488,7 +489,7 @@ public class JingleConnection implements Transferable {
mJingleStatus = JINGLE_STATUS_INITIATED; mJingleStatus = JINGLE_STATUS_INITIATED;
mXmppConnectionService.markMessage(message, Message.STATUS_OFFERED); mXmppConnectionService.markMessage(message, Message.STATUS_OFFERED);
} else { } else {
fail(); fail(IqParser.extractErrorMessage(packet));
} }
} }
}); });
@ -846,6 +847,10 @@ public class JingleConnection implements Transferable {
} }
private void fail() { private void fail() {
fail(null);
}
private void fail(String errorMessage) {
this.mJingleStatus = JINGLE_STATUS_FAILED; this.mJingleStatus = JINGLE_STATUS_FAILED;
this.disconnectSocks5Connections(); this.disconnectSocks5Connections();
if (this.transport != null && this.transport instanceof JingleInbandTransport) { if (this.transport != null && this.transport instanceof JingleInbandTransport) {
@ -862,7 +867,8 @@ public class JingleConnection implements Transferable {
this.mXmppConnectionService.updateConversationUi(); this.mXmppConnectionService.updateConversationUi();
} else { } else {
this.mXmppConnectionService.markMessage(this.message, this.mXmppConnectionService.markMessage(this.message,
Message.STATUS_SEND_FAILED); Message.STATUS_SEND_FAILED,
errorMessage);
this.message.setTransferable(null); this.message.setTransferable(null);
} }
} }

View file

@ -25,6 +25,10 @@
android:id="@+id/copy_url" android:id="@+id/copy_url"
android:title="@string/copy_original_url" android:title="@string/copy_original_url"
android:visible="false"/> android:visible="false"/>
<item
android:id="@+id/show_error_message"
android:title="@string/show_error_message"
android:visible="false"/>
<item <item
android:id="@+id/send_again" android:id="@+id/send_again"
android:title="@string/send_again" android:title="@string/send_again"

View file

@ -694,4 +694,6 @@
<string name="pref_delete_omemo_identities_summary">Regenerate your OMEMO keys. All your contacts will have to verify you again. Use this only as a last resort.</string> <string name="pref_delete_omemo_identities_summary">Regenerate your OMEMO keys. All your contacts will have to verify you again. Use this only as a last resort.</string>
<string name="delete_selected_keys">Delete selected keys</string> <string name="delete_selected_keys">Delete selected keys</string>
<string name="error_publish_avatar_offline">You need to be connected to publish your avatar.</string> <string name="error_publish_avatar_offline">You need to be connected to publish your avatar.</string>
<string name="show_error_message">Show error message</string>
<string name="error_message">Error Message</string>
</resources> </resources>