made file transfers cancelable

iNPUTmice created

Change summary

src/main/java/eu/siacs/conversations/entities/Downloadable.java             |  2 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java    |  5 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java           | 17 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java      | 48 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java | 18 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java       |  2 
src/main/res/menu/message_context.xml                                       |  3 
src/main/res/values/strings.xml                                             |  3 
8 files changed, 76 insertions(+), 22 deletions(-)

Detailed changes

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

@@ -43,6 +43,7 @@ import eu.siacs.conversations.crypto.PgpEngine;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Downloadable;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions;
 import eu.siacs.conversations.entities.Presences;
@@ -343,6 +344,7 @@ public class ConversationFragment extends Fragment {
 			MenuItem sendAgain = menu.findItem(R.id.send_again);
 			MenuItem copyUrl = menu.findItem(R.id.copy_url);
 			MenuItem downloadImage = menu.findItem(R.id.download_image);
+			MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission);
 			if (this.selectedMessage.getType() != Message.TYPE_TEXT
 					|| this.selectedMessage.getDownloadable() != null) {
 				copyText.setVisible(false);
@@ -359,12 +361,15 @@ public class ConversationFragment extends Fragment {
 					|| this.selectedMessage.getImageParams().url == null) {
 				copyUrl.setVisible(false);
 			}
-
 			if (this.selectedMessage.getType() != Message.TYPE_TEXT
 					|| this.selectedMessage.getDownloadable() != null
 					|| !this.selectedMessage.bodyContainsDownloadable()) {
 				downloadImage.setVisible(false);
 			}
+			if (this.selectedMessage.getDownloadable() == null
+					|| this.selectedMessage.getDownloadable().getStatus() == Downloadable.STATUS_DELETED) {
+				cancelTransmission.setVisible(false);
+			}
 		}
 	}
 
@@ -386,6 +391,9 @@ public class ConversationFragment extends Fragment {
 			case R.id.download_image:
 				downloadImage(selectedMessage);
 				return true;
+			case R.id.cancel_transmission:
+				cancelTransmission(selectedMessage);
+				return true;
 			default:
 				return super.onContextItemSelected(item);
 		}
@@ -428,6 +436,13 @@ public class ConversationFragment extends Fragment {
 				.createNewConnection(message);
 	}
 
+	private void cancelTransmission(Message message) {
+		Downloadable downloadable = message.getDownloadable();
+		if (downloadable!=null) {
+			downloadable.cancel();
+		}
+	}
+
 	protected void privateMessageWith(final Jid counterpart) {
 		this.mEditMessage.setText("");
 		this.conversation.setNextCounterpart(counterpart);

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java 🔗

@@ -10,7 +10,6 @@ import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 
 import android.content.Intent;
-import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.SystemClock;
 import android.util.Log;
@@ -76,7 +75,7 @@ public class JingleConnection implements Downloadable {
 		@Override
 		public void onIqPacketReceived(Account account, IqPacket packet) {
 			if (packet.getType() == IqPacket.TYPE_ERROR) {
-				cancel();
+				fail();
 			}
 		}
 	};
@@ -115,7 +114,7 @@ public class JingleConnection implements Downloadable {
 		@Override
 		public void onFileTransferAborted() {
 			JingleConnection.this.sendCancel();
-			JingleConnection.this.cancel();
+			JingleConnection.this.fail();
 		}
 	};
 
@@ -162,14 +161,14 @@ public class JingleConnection implements Downloadable {
 			Reason reason = packet.getReason();
 			if (reason != null) {
 				if (reason.hasChild("cancel")) {
-					this.cancel();
+					this.fail();
 				} else if (reason.hasChild("success")) {
 					this.receiveSuccess();
 				} else {
-					this.cancel();
+					this.fail();
 				}
 			} else {
-				this.cancel();
+				this.fail();
 			}
 		} else if (packet.isAction("session-accept")) {
 			returnResult = receiveAccept(packet);
@@ -343,7 +342,7 @@ public class JingleConnection implements Downloadable {
 					byte[] key = conversation.getSymmetricKey();
 					if (key == null) {
 						this.sendCancel();
-						this.cancel();
+						this.fail();
 						return;
 					} else {
 						this.file.setKey(key);
@@ -352,11 +351,11 @@ public class JingleConnection implements Downloadable {
 				this.file.setExpectedSize(size);
 			} else {
 				this.sendCancel();
-				this.cancel();
+				this.fail();
 			}
 		} else {
 			this.sendCancel();
-			this.cancel();
+			this.fail();
 		}
 	}
 
@@ -495,7 +494,7 @@ public class JingleConnection implements Downloadable {
 					} else {
 						Log.d(Config.LOGTAG, "activated connection not found");
 						this.sendCancel();
-						this.cancel();
+						this.fail();
 					}
 				}
 				return true;
@@ -542,7 +541,7 @@ public class JingleConnection implements Downloadable {
 		this.transport = connection;
 		if (connection == null) {
 			Log.d(Config.LOGTAG, "could not find suitable candidate");
-			this.disconnect();
+			this.disconnectSocks5Connections();
 			if (this.initiator.equals(account.getJid())) {
 				this.sendFallbackToIbb();
 			}
@@ -633,7 +632,7 @@ public class JingleConnection implements Downloadable {
 		reason.addChild("success");
 		packet.setReason(reason);
 		this.sendJinglePacket(packet);
-		this.disconnect();
+		this.disconnectSocks5Connections();
 		this.mJingleStatus = JINGLE_STATUS_FINISHED;
 		this.message.setStatus(Message.STATUS_RECEIVED);
 		this.message.setDownloadable(null);
@@ -710,13 +709,30 @@ public class JingleConnection implements Downloadable {
 		this.mJingleStatus = JINGLE_STATUS_FINISHED;
 		this.mXmppConnectionService.markMessage(this.message,
 				Message.STATUS_SEND);
-		this.disconnect();
+		this.disconnectSocks5Connections();
 		this.mJingleConnectionManager.finishConnection(this);
 	}
 
 	public void cancel() {
-		this.mJingleStatus = JINGLE_STATUS_CANCELED;
-		this.disconnect();
+		this.disconnectSocks5Connections();
+		if (this.transport != null && this.transport instanceof JingleInbandTransport) {
+			this.transport.disconnect();
+		}
+		this.sendCancel();
+		this.mJingleConnectionManager.finishConnection(this);
+		if (this.responder.equals(account.getJid())) {
+			this.mStatus = Downloadable.STATUS_FAILED;
+			this.mXmppConnectionService.updateConversationUi();
+		} else {
+			this.mXmppConnectionService.markMessage(this.message,
+					Message.STATUS_SEND_FAILED);
+			this.message.setDownloadable(null);
+		}
+	}
+
+	private void fail() {
+		this.mJingleStatus = JINGLE_STATUS_FAILED;
+		this.disconnectSocks5Connections();
 		if (this.message != null) {
 			if (this.responder.equals(account.getJid())) {
 				this.mStatus = Downloadable.STATUS_FAILED;
@@ -772,7 +788,7 @@ public class JingleConnection implements Downloadable {
 		});
 	}
 
-	private void disconnect() {
+	private void disconnectSocks5Connections() {
 		Iterator<Entry<String, JingleSocks5Transport>> it = this.connections
 				.entrySet().iterator();
 		while (it.hasNext()) {

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java 🔗

@@ -28,6 +28,8 @@ public class JingleInbandTransport extends JingleTransport {
 
 	private boolean established = false;
 
+	private boolean connected = true;
+
 	private DownloadableFile file;
 	private JingleConnection connection;
 
@@ -42,7 +44,7 @@ public class JingleInbandTransport extends JingleTransport {
 	private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() {
 		@Override
 		public void onIqPacketReceived(Account account, IqPacket packet) {
-			if (packet.getType() == IqPacket.TYPE_RESULT) {
+			if (connected && packet.getType() == IqPacket.TYPE_RESULT) {
 				sendNextBlock();
 			}
 		}
@@ -64,7 +66,7 @@ public class JingleInbandTransport extends JingleTransport {
 		open.setAttribute("sid", this.sessionId);
 		open.setAttribute("stanza", "iq");
 		open.setAttribute("block-size", Integer.toString(this.blockSize));
-
+		this.connected = true;
 		this.account.getXmppConnection().sendIqPacket(iq,
 				new OnIqPacketReceived() {
 
@@ -116,12 +118,19 @@ public class JingleInbandTransport extends JingleTransport {
 				callback.onFileTransferAborted();
 				return;
 			}
-			this.sendNextBlock();
+			if (this.connected) {
+				this.sendNextBlock();
+			}
 		} catch (NoSuchAlgorithmException e) {
 			callback.onFileTransferAborted();
 		}
 	}
 
+	@Override
+	public void disconnect() {
+		this.connected = false;
+	}
+
 	private void sendNextBlock() {
 		byte[] buffer = new byte[this.bufferSize];
 		try {
@@ -183,13 +192,14 @@ public class JingleInbandTransport extends JingleTransport {
 		if (payload.getName().equals("open")) {
 			if (!established) {
 				established = true;
+				connected = true;
 				this.account.getXmppConnection().sendIqPacket(
 						packet.generateRespone(IqPacket.TYPE_RESULT), null);
 			} else {
 				this.account.getXmppConnection().sendIqPacket(
 						packet.generateRespone(IqPacket.TYPE_ERROR), null);
 			}
-		} else if (payload.getName().equals("data")) {
+		} else if (connected && payload.getName().equals("data")) {
 			this.receiveNextBlock(payload.getContent());
 			this.account.getXmppConnection().sendIqPacket(
 					packet.generateRespone(IqPacket.TYPE_RESULT), null);

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

@@ -16,5 +16,8 @@
     <item
         android:id="@+id/download_image"
         android:title="@string/download_image"/>
+    <item
+        android:id="@+id/cancel_transmission"
+        android:title="@string/cancel_transmission" />
 
 </menu>

src/main/res/values/strings.xml 🔗

@@ -318,5 +318,6 @@
     <string name="sending_file">sending (%1$d%% completed)</string>
     <string name="preparing_file">Preparing file for transmission</string>
     <string name="file_offered_for_download">File offered for download</string>
-    <string name="file">%s file</string>;
+    <string name="file">%s file</string>
+    <string name="cancel_transmission">Cancel transmission</string>
 </resources>