diff --git a/src/org/kde/kdeconnect/Backends/BaseLink.java b/src/org/kde/kdeconnect/Backends/BaseLink.java index a238a389..bf9507d5 100644 --- a/src/org/kde/kdeconnect/Backends/BaseLink.java +++ b/src/org/kde/kdeconnect/Backends/BaseLink.java @@ -28,6 +28,8 @@ import org.kde.kdeconnect.NetworkPacket; import java.security.PrivateKey; import java.util.ArrayList; +import androidx.annotation.WorkerThread; + public abstract class BaseLink { @@ -88,5 +90,6 @@ public abstract class BaseLink { } //TO OVERRIDE, should be sync + @WorkerThread public abstract boolean sendPacket(NetworkPacket np, Device.SendPacketStatusCallback callback); } diff --git a/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java b/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java index 2623485d..27e9f3f5 100644 --- a/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java +++ b/src/org/kde/kdeconnect/Backends/BluetoothBackend/BluetoothLink.java @@ -43,6 +43,8 @@ import java.io.Reader; import java.nio.charset.Charset; import java.util.UUID; +import androidx.annotation.WorkerThread; + public class BluetoothLink extends BaseLink { private final ConnectionMultiplexer connection; private final InputStream input; @@ -150,6 +152,7 @@ public class BluetoothLink extends BaseLink { Log.i("BluetoothLink", "Finished sending message"); } + @WorkerThread @Override public boolean sendPacket(NetworkPacket np, final Device.SendPacketStatusCallback callback) { diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java index f4847fa0..c8853de3 100644 --- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java +++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java @@ -44,6 +44,8 @@ import java.nio.channels.NotYetConnectedException; import javax.net.ssl.SSLSocket; +import androidx.annotation.WorkerThread; + public class LanLink extends BaseLink { public interface LinkDisconnectedCallback { @@ -137,6 +139,7 @@ public class LanLink extends BaseLink { } //Blocking, do not call from main thread + @WorkerThread @Override public boolean sendPacket(NetworkPacket np, final Device.SendPacketStatusCallback callback) { if (socket == null) { diff --git a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java index bb8bef66..9ee0a753 100644 --- a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java +++ b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java @@ -28,6 +28,8 @@ import org.kde.kdeconnect.Backends.BasePairingHandler; import org.kde.kdeconnect.Device; import org.kde.kdeconnect.NetworkPacket; +import androidx.annotation.WorkerThread; + public class LoopbackLink extends BaseLink { public LoopbackLink(Context context, BaseLinkProvider linkProvider) { @@ -44,6 +46,7 @@ public class LoopbackLink extends BaseLink { return new LoopbackPairingHandler(device, callback); } + @WorkerThread @Override public boolean sendPacket(NetworkPacket in, Device.SendPacketStatusCallback callback) { packageReceived(in); diff --git a/src/org/kde/kdeconnect/Device.java b/src/org/kde/kdeconnect/Device.java index e9d6fc5b..35cdef56 100644 --- a/src/org/kde/kdeconnect/Device.java +++ b/src/org/kde/kdeconnect/Device.java @@ -57,6 +57,8 @@ import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import androidx.annotation.AnyThread; +import androidx.annotation.WorkerThread; import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; @@ -621,18 +623,22 @@ public class Device implements BaseLink.PacketReceiver { } }; + @AnyThread public void sendPacket(NetworkPacket np) { sendPacket(np, -1, defaultCallback); } + @AnyThread public void sendPacket(NetworkPacket np, int replaceID) { sendPacket(np, replaceID, defaultCallback); } + @WorkerThread public boolean sendPacketBlocking(NetworkPacket np) { return sendPacketBlocking(np, defaultCallback); } + @AnyThread public void sendPacket(final NetworkPacket np, final SendPacketStatusCallback callback) { sendPacket(np, -1, callback); } @@ -643,6 +649,7 @@ public class Device implements BaseLink.PacketReceiver { * @param replaceID If positive, replaces all unsent packages with the same replaceID * @param callback A callback for success/failure */ + @AnyThread public void sendPacket(final NetworkPacket np, int replaceID, final SendPacketStatusCallback callback) { if (packetQueue == null) { callback.onFailure(new Exception("Device disconnected!")); @@ -665,6 +672,15 @@ public class Device implements BaseLink.PacketReceiver { } } + /** + * Send {@code np} over one of this device's connected {@link #links}. + * + * @param np the packet to send + * @param callback a callback that can receive realtime updates + * @return true if the packet was sent ok, false otherwise + * @see BaseLink#sendPacket(NetworkPacket, SendPacketStatusCallback) + */ + @WorkerThread public boolean sendPacketBlocking(final NetworkPacket np, final SendPacketStatusCallback callback) { /* diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/CompositeReceiveFileJob.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/CompositeReceiveFileJob.java index 63a67318..1a63081e 100644 --- a/src/org/kde/kdeconnect/Plugins/SharePlugin/CompositeReceiveFileJob.java +++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/CompositeReceiveFileJob.java @@ -43,9 +43,27 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import androidx.annotation.GuardedBy; import androidx.core.content.FileProvider; import androidx.documentfile.provider.DocumentFile; +/** + * A type of {@link BackgroundJob} that reads Files from another device. + * + *
+ * We receive the requests as {@link NetworkPacket}s. + *
+ *+ * Each packet should have a 'filename' property and a payload. If the payload is missing, + * we'll just create an empty file. You can add new packets anytime via + * {@link #addNetworkPacket(NetworkPacket)}. + *
+ *+ * The I/O-part of this file reading is handled by {@link #receiveFile(InputStream, OutputStream)}. + *
+ * + * @see CompositeUploadFileJob + */ public class CompositeReceiveFileJob extends BackgroundJob+ * We represent the individual upload requests as {@link NetworkPacket}s. + *
+ *+ * Each packet should have a 'filename' property and a payload. If the payload is + * missing, we'll just send an empty file. You can add new packets anytime via + * {@link #addNetworkPacket(NetworkPacket)}. + *
+ *+ * The I/O-part of this file sending is handled by + * {@link Device#sendPacketBlocking(NetworkPacket, Device.SendPacketStatusCallback)}. + *
+ * + * @see CompositeReceiveFileJob + * @see SendPacketStatusCallback + */ public class CompositeUploadFileJob extends BackgroundJob+ * All of the associated I/O work is scheduled on background + * threads by {@link BackgroundJobHandler}. + *
+ */ @PluginFactory.LoadablePlugin public class SharePlugin extends Plugin { final static String ACTION_CANCEL_SHARE = "org.kde.kdeconnect.Plugins.SharePlugin.CancelShare"; diff --git a/src/org/kde/kdeconnect/async/BackgroundJobHandler.java b/src/org/kde/kdeconnect/async/BackgroundJobHandler.java index b2891833..ad4172e7 100644 --- a/src/org/kde/kdeconnect/async/BackgroundJobHandler.java +++ b/src/org/kde/kdeconnect/async/BackgroundJobHandler.java @@ -37,6 +37,13 @@ import java.util.concurrent.TimeUnit; import androidx.annotation.Nullable; +/** + * Scheduler for {@link BackgroundJob} objects. + *+ * We use an internal {@link ThreadPoolExecutor} to catch Exceptions and + * pass them along to {@link #handleUncaughtException(Future, Throwable)}. + *
+ */ public class BackgroundJobHandler { private static final String TAG = BackgroundJobHandler.class.getSimpleName();