diff --git a/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java b/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java
--- a/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java
+++ b/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java
@@ -20,7 +20,6 @@
package org.kde.kdeconnect.Backends.BluetoothBackend;
-import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
@@ -102,7 +101,7 @@
UUID transferUuid = UUID.fromString(np.getPayloadTransferInfo().getString("uuid"));
transferSocket = socket.getRemoteDevice().createRfcommSocketToServiceRecord(transferUuid);
transferSocket.connect();
- np.setPayload(transferSocket.getInputStream(), np.getPayloadSize());
+ np.setPayload(new NetworkPacket.Payload(transferSocket.getInputStream(), np.getPayloadSize()));
} catch (Exception e) {
if (transferSocket != null) {
try {
@@ -211,7 +210,7 @@
byte[] buffer = new byte[idealBufferLength];
int bytesRead;
long progress = 0;
- InputStream stream = np.getPayload();
+ InputStream stream = np.getPayload().getInputStream();
while ((bytesRead = stream.read(buffer)) != -1) {
progress += bytesRead;
transferSocket.getOutputStream().write(buffer, 0, bytesRead);
diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java
--- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java
+++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java
@@ -193,7 +193,7 @@
}
outputStream = payloadSocket.getOutputStream();
- inputStream = np.getPayload();
+ inputStream = np.getPayload().getInputStream();
Log.i("KDE/LanLink", "Beginning to send payload");
byte[] buffer = new byte[4096];
@@ -214,12 +214,11 @@
}
}
outputStream.flush();
- outputStream.close();
Log.i("KDE/LanLink", "Finished sending payload ("+progress+" bytes written)");
} finally {
try { server.close(); } catch (Exception e) { }
try { payloadSocket.close(); } catch (Exception e) { }
- try { inputStream.close(); } catch (Exception e) { }
+ np.getPayload().close();
try { outputStream.close(); } catch (Exception e) { }
}
}
@@ -233,8 +232,9 @@
return false;
} finally {
//Make sure we close the payload stream, if any
- InputStream stream = np.getPayload();
- try { stream.close(); } catch (Exception e) { }
+ if (np.hasPayload()) {
+ np.getPayload().close();
+ }
}
}
@@ -272,7 +272,7 @@
if (socket instanceof SSLSocket) {
payloadSocket = SslHelper.convertToSslSocket(context, payloadSocket, getDeviceId(), true, true);
}
- np.setPayload(payloadSocket.getInputStream(), np.getPayloadSize());
+ np.setPayload(new NetworkPacket.Payload(payloadSocket, np.getPayloadSize()));
} catch (Exception e) {
try { payloadSocket.close(); } catch(Exception ignored) { }
e.printStackTrace();
diff --git a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java
--- a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java
+++ b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java
@@ -51,7 +51,7 @@
packageReceived(in);
if (in.hasPayload()) {
callback.onProgressChanged(0);
- in.setPayload(in.getPayload(), in.getPayloadSize());
+ in.setPayload(in.getPayload());
callback.onProgressChanged(100);
}
callback.onSuccess();
diff --git a/src/org/kde/kdeconnect/Helpers/SecurityHelpers/RsaHelper.java b/src/org/kde/kdeconnect/Helpers/SecurityHelpers/RsaHelper.java
--- a/src/org/kde/kdeconnect/Helpers/SecurityHelpers/RsaHelper.java
+++ b/src/org/kde/kdeconnect/Helpers/SecurityHelpers/RsaHelper.java
@@ -116,7 +116,7 @@
NetworkPacket encrypted = new NetworkPacket(NetworkPacket.PACKET_TYPE_ENCRYPTED);
encrypted.set("data", chunks);
- encrypted.setPayload(np.getPayload(), np.getPayloadSize());
+ encrypted.setPayload(np.getPayload());
return encrypted;
}
@@ -136,7 +136,7 @@
}
NetworkPacket decrypted = NetworkPacket.unserialize(decryptedJson.toString());
- decrypted.setPayload(np.getPayload(), np.getPayloadSize());
+ decrypted.setPayload(np.getPayload());
return decrypted;
}
diff --git a/src/org/kde/kdeconnect/NetworkPacket.java b/src/org/kde/kdeconnect/NetworkPacket.java
--- a/src/org/kde/kdeconnect/NetworkPacket.java
+++ b/src/org/kde/kdeconnect/NetworkPacket.java
@@ -30,7 +30,9 @@
import org.kde.kdeconnect.Plugins.PluginFactory;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStream;
+import java.net.Socket;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -53,9 +55,8 @@
private long mId;
String mType;
private JSONObject mBody;
- private InputStream mPayload;
+ private Payload mPayload;
private JSONObject mPayloadTransferInfo;
- private long mPayloadSize;
private NetworkPacket() {
@@ -66,7 +67,6 @@
mType = type;
mBody = new JSONObject();
mPayload = null;
- mPayloadSize = 0;
mPayloadTransferInfo = new JSONObject();
}
@@ -242,7 +242,7 @@
jo.put("type", mType);
jo.put("body", mBody);
if (hasPayload()) {
- jo.put("payloadSize", mPayloadSize);
+ jo.put("payloadSize", mPayload.payloadSize);
jo.put("payloadTransferInfo", mPayloadTransferInfo);
}
//QJSon does not escape slashes, but Java JSONObject does. Converting to QJson format.
@@ -258,10 +258,10 @@
np.mBody = jo.getJSONObject("body");
if (jo.has("payloadSize")) {
np.mPayloadTransferInfo = jo.getJSONObject("payloadTransferInfo");
- np.mPayloadSize = jo.getLong("payloadSize");
+ np.mPayload = new Payload(jo.getLong("payloadSize"));
} else {
np.mPayloadTransferInfo = new JSONObject();
- np.mPayloadSize = 0;
+ np.mPayload = new Payload(0);
}
return np;
}
@@ -287,29 +287,18 @@
}
- public void setPayload(byte[] data) {
- setPayload(new ByteArrayInputStream(data), data.length);
- }
-
- public void setPayload(InputStream stream, long size) {
- mPayload = stream;
- mPayloadSize = size;
- }
+ public void setPayload(Payload payload) { mPayload = payload; }
- /*public void setPayload(InputStream stream) {
- setPayload(stream, -1);
- }*/
-
- public InputStream getPayload() {
+ public Payload getPayload() {
return mPayload;
}
public long getPayloadSize() {
- return mPayloadSize;
+ return mPayload == null ? 0 : mPayload.payloadSize;
}
public boolean hasPayload() {
- return (mPayloadSize != 0);
+ return (mPayload != null && mPayload.payloadSize != 0);
}
public boolean hasPayloadTransferInfo() {
@@ -323,4 +312,54 @@
public void setPayloadTransferInfo(JSONObject payloadTransferInfo) {
mPayloadTransferInfo = payloadTransferInfo;
}
+
+ public static class Payload {
+ private InputStream inputStream;
+ private Socket inputSocket;
+ private long payloadSize;
+
+ public Payload(long payloadSize) {
+ this((InputStream)null, payloadSize);
+ }
+
+ public Payload(byte[] data) {
+ this(new ByteArrayInputStream(data), data.length);
+ }
+
+ /**
+ * NOTE: Do not use this to set an SSLSockets InputStream as the payload, use Payload(Socket, long) instead because of this bug
+ */
+ public Payload(InputStream inputStream, long payloadSize) {
+ this.inputSocket = null;
+ this.inputStream = inputStream;
+ this.payloadSize = payloadSize;
+ }
+
+ public Payload(Socket inputSocket, long payloadSize) throws IOException {
+ this.inputSocket = inputSocket;
+ this.inputStream = inputSocket.getInputStream();
+ this.payloadSize = payloadSize;
+ }
+
+ /**
+ * NOTE: Do not close the InputStream directly call Payload.close() instead, this is because of this bug
+ */
+ public InputStream getInputStream() { return inputStream; }
+ long getPayloadSize() { return payloadSize; }
+
+ public void close() {
+ //TODO: If socket only close socket if that also closes the streams that is
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ } catch(IOException ignored) {}
+
+ try {
+ if (inputSocket != null) {
+ inputSocket.close();
+ }
+ } catch (IOException ignored) {}
+ }
+ }
}
diff --git a/src/org/kde/kdeconnect/Plugins/MprisPlugin/AlbumArtCache.java b/src/org/kde/kdeconnect/Plugins/MprisPlugin/AlbumArtCache.java
--- a/src/org/kde/kdeconnect/Plugins/MprisPlugin/AlbumArtCache.java
+++ b/src/org/kde/kdeconnect/Plugins/MprisPlugin/AlbumArtCache.java
@@ -33,6 +33,8 @@
import com.jakewharton.disklrucache.DiskLruCache;
+import org.kde.kdeconnect.NetworkPacket;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -243,20 +245,20 @@
private static final class FetchURLTask extends AsyncTask {
private final URL url;
- private InputStream input;
+ private NetworkPacket.Payload payload;
private final DiskLruCache.Editor cacheItem;
private OutputStream output;
/**
* Initialize an url fetch
*
* @param url The url being fetched
- * @param payloadInput A payload input stream (if from the connected device). null if fetched from http(s)
+ * @param payload A NetworkPacket Payload (if from the connected device). null if fetched from http(s)
* @param cacheItem The disk cache item to edit
*/
- FetchURLTask(URL url, InputStream payloadInput, DiskLruCache.Editor cacheItem) throws IOException {
+ FetchURLTask(URL url, NetworkPacket.Payload payload, DiskLruCache.Editor cacheItem) throws IOException {
this.url = url;
- this.input = payloadInput;
+ this.payload = payload;
this.cacheItem = cacheItem;
output = cacheItem.newOutputStream(0);
}
@@ -266,7 +268,7 @@
*
* @return True if succeeded
*/
- private boolean openHttp() throws IOException {
+ private InputStream openHttp() throws IOException {
//Default android behaviour does not follow https -> http urls, so do this manually
if (!url.getProtocol().equals("http") && !url.getProtocol().equals("https")) {
throw new AssertionError("Invalid url: not http(s) in background album art fetch");
@@ -287,28 +289,25 @@
currentUrl = new URL(currentUrl, location); // Deal with relative URLs
//Again, only support http(s)
if (!currentUrl.getProtocol().equals("http") && !currentUrl.getProtocol().equals("https")) {
- return false;
+ return null;
}
connection.disconnect();
continue;
}
//Found a non-redirecting connection, so do something with it
- input = connection.getInputStream();
- return true;
+ return connection.getInputStream();
}
- return false;
+ return null;
}
@Override
protected Boolean doInBackground(Void... params) {
- try {
- //See if we need to open a http(s) connection here, or if we use a payload input stream
+ //See if we need to open a http(s) connection here, or if we use a payload input stream
+ try (InputStream input = payload == null ? openHttp() : payload.getInputStream()) {
if (input == null) {
- if (!openHttp()) {
- return false;
- }
+ return false;
}
byte[] buffer = new byte[4096];
@@ -321,6 +320,10 @@
return true;
} catch (IOException e) {
return false;
+ } finally {
+ if (payload != null) {
+ payload.close();
+ }
}
}
@@ -425,59 +428,48 @@
* @param albumUrl The url of the album art (should be a file:// url)
* @param payload The payload input stream
*/
- static void payloadToDiskCache(String albumUrl, InputStream payload) {
+ static void payloadToDiskCache(String albumUrl, NetworkPacket.Payload payload) {
//We need the disk cache for this
- if (diskCache == null) {
- Log.e("KDE/Mpris/AlbumArtCache", "The disk cache is not intialized!");
- try {
- payload.close();
- } catch (IOException ignored) {}
+ if (payload == null) {
return;
}
- if (payload == null) {
+
+ if (diskCache == null) {
+ Log.e("KDE/Mpris/AlbumArtCache", "The disk cache is not intialized!");
+ payload.close();
return;
}
URL url;
try {
url = new URL(albumUrl);
} catch (MalformedURLException e) {
//Shouldn't happen (checked on receival of the url), but just to be sure
- try {
- payload.close();
- } catch (IOException ignored) {}
+ payload.close();
return;
}
if (!"file".equals(url.getProtocol())) {
//Shouldn't happen (otherwise we wouldn't have asked for the payload), but just to be sure
- try {
- payload.close();
- } catch (IOException ignored) {}
+ payload.close();
return;
}
//Only fetch the URL if we're not fetching it already
if (isFetchingList.contains(url)) {
- try {
- payload.close();
- } catch (IOException ignored) {}
+ payload.close();
return;
}
//Check if we already have this art
try {
if (memoryCache.get(albumUrl) != null || diskCache.get(urlToDiskCacheKey(albumUrl)) != null) {
- try {
- payload.close();
- } catch (IOException ignored) {}
+ payload.close();
return;
}
} catch (IOException e) {
Log.e("KDE/Mpris/AlbumArtCache", "Disk cache problem!", e);
- try {
- payload.close();
- } catch (IOException ignored) {}
+ payload.close();
return;
}
@@ -491,9 +483,7 @@
Log.e("KDE/Mpris/AlbumArtCache",
"Two disk cache edits happened at the same time, should be impossible!");
--numFetching;
- try {
- payload.close();
- } catch (IOException ignored) {}
+ payload.close();
return;
}
diff --git a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java
--- a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java
+++ b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java
@@ -232,7 +232,7 @@
Log.e("PAYLOAD", "PAYLOAD: " + getChecksum(bitmapData));
- np.setPayload(bitmapData);
+ np.setPayload(new NetworkPacket.Payload(bitmapData));
np.set("payloadHash", getChecksum(bitmapData));
}
diff --git a/src/org/kde/kdeconnect/Plugins/ReceiveNotificationsPlugin/ReceiveNotificationsPlugin.java b/src/org/kde/kdeconnect/Plugins/ReceiveNotificationsPlugin/ReceiveNotificationsPlugin.java
--- a/src/org/kde/kdeconnect/Plugins/ReceiveNotificationsPlugin/ReceiveNotificationsPlugin.java
+++ b/src/org/kde/kdeconnect/Plugins/ReceiveNotificationsPlugin/ReceiveNotificationsPlugin.java
@@ -86,12 +86,10 @@
int height = 64;
width = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
height = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
- final InputStream input = np.getPayload();
- largeIcon = BitmapFactory.decodeStream(np.getPayload());
- try {
- input.close();
- } catch (Exception e) {
- }
+ final InputStream input = np.getPayload().getInputStream();
+ largeIcon = BitmapFactory.decodeStream(input);
+ np.getPayload().close();
+
if (largeIcon != null) {
//Log.i("NotificationsPlugin", "hasPayload: size=" + largeIcon.getWidth() + "/" + largeIcon.getHeight() + " opti=" + width + "/" + height);
if (largeIcon.getWidth() > width || largeIcon.getHeight() > height) {
@@ -131,5 +129,4 @@
public String[] getOutgoingPacketTypes() {
return new String[]{PACKET_TYPE_NOTIFICATION_REQUEST};
}
-
}
diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/ReceiveFileRunnable.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/ReceiveFileRunnable.java
--- a/src/org/kde/kdeconnect/Plugins/SharePlugin/ReceiveFileRunnable.java
+++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/ReceiveFileRunnable.java
@@ -24,6 +24,7 @@
import android.os.Looper;
import java.io.IOException;
+import java.io.InputStream;
public class ReceiveFileRunnable implements Runnable {
interface CallBack {
@@ -51,7 +52,9 @@
callBack.onProgress(info, 0);
- while ((count = info.inputStream.read(data)) >= 0) {
+ InputStream inputStream = info.payload.getInputStream();
+
+ while ((count = inputStream.read(data)) >= 0) {
received += count;
if (received > info.fileSize) {
@@ -79,14 +82,11 @@
} catch (IOException e) {
handler.post(() -> callBack.onError(info, e));
} finally {
- try {
- info.inputStream.close();
- } catch (IOException e) {
- }
+ info.payload.close();
+
try {
info.outputStream.close();
- } catch (IOException e) {
- }
+ } catch (IOException ignored) {}
}
}
}
diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareInfo.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareInfo.java
--- a/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareInfo.java
+++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareInfo.java
@@ -22,15 +22,16 @@
import android.support.v4.provider.DocumentFile;
-import java.io.InputStream;
+import org.kde.kdeconnect.NetworkPacket;
+
import java.io.OutputStream;
class ShareInfo {
String fileName;
long fileSize;
int currentFileNumber;
DocumentFile fileDocument;
- InputStream inputStream;
+ NetworkPacket.Payload payload;
OutputStream outputStream;
boolean shouldOpen;
diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java
--- a/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java
+++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java
@@ -204,7 +204,7 @@
ShareInfo info = new ShareInfo();
info.currentFileNumber = currentShareInfo == null ? 1 : currentShareInfo.currentFileNumber + 1;
- info.inputStream = np.getPayload();
+ info.payload = np.getPayload();
info.fileSize = np.getPayloadSize();
info.fileName = np.getString("filename", Long.toString(System.currentTimeMillis()));
info.shouldOpen = np.getBoolean("open");
@@ -379,7 +379,7 @@
}
- np.setPayload(inputStream, size);
+ np.setPayload(new NetworkPacket.Payload(inputStream, size));
return np;
} catch (Exception e) {