diff --git a/res/values/strings.xml b/res/values/strings.xml index 23d10dcd..2bb61978 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -67,8 +67,14 @@ Tap to open \'%1s\' Incoming file from %1s %1s + Sending file to %1s + %1s Received file from %1s Tap to open \'%1s\' + Sent file to %1s + %1s + Failed to send file %1s + %1s Tap to answer Reconnect Send Right Click diff --git a/src/org/kde/kdeconnect/Backends/BaseLink.java b/src/org/kde/kdeconnect/Backends/BaseLink.java index 242ff679..6891986b 100644 --- a/src/org/kde/kdeconnect/Backends/BaseLink.java +++ b/src/org/kde/kdeconnect/Backends/BaseLink.java @@ -20,6 +20,7 @@ package org.kde.kdeconnect.Backends; +import org.kde.kdeconnect.Device; import org.kde.kdeconnect.NetworkPackage; import java.security.PrivateKey; @@ -71,7 +72,7 @@ public abstract class BaseLink { } //TO OVERRIDE, should be sync - public abstract boolean sendPackage(NetworkPackage np); - public abstract boolean sendPackageEncrypted(NetworkPackage np, PublicKey key); + public abstract boolean sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback); + public abstract boolean sendPackageEncrypted(NetworkPackage np,Device.SendPackageStatusCallback callback, PublicKey key); } diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java index ca81c136..3912e77d 100644 --- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java +++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLink.java @@ -27,6 +27,7 @@ import org.apache.mina.core.session.IoSession; import org.json.JSONObject; import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLinkProvider; +import org.kde.kdeconnect.Device; import org.kde.kdeconnect.NetworkPackage; import java.io.InputStream; @@ -51,7 +52,7 @@ public class LanLink extends BaseLink { this.session = session; } - private Thread sendPayload(NetworkPackage np) { + private Thread sendPayload(NetworkPackage np, final Device.SendPackageStatusCallback callback) { try { @@ -87,10 +88,13 @@ public class LanLink extends BaseLink { socket = server.accept().getOutputStream(); byte[] buffer = new byte[4096]; int bytesRead; + long progress = 0 ; Log.e("LanLink","Beginning to send payload"); while ((bytesRead = stream.read(buffer)) != -1) { //Log.e("ok",""+bytesRead); + progress += bytesRead; socket.write(buffer, 0, bytesRead); + if (callback != null) callback.progressChanged(progress); } Log.e("LanLink","Finished sending payload"); } catch(Exception e) { @@ -122,7 +126,7 @@ public class LanLink extends BaseLink { //Blocking, do not call from main thread @Override - public boolean sendPackage(final NetworkPackage np) { + public boolean sendPackage(final NetworkPackage np,Device.SendPackageStatusCallback callback) { if (session == null) { Log.e("LanLink", "sendPackage failed: not yet connected"); @@ -132,7 +136,7 @@ public class LanLink extends BaseLink { try { Thread thread = null; if (np.hasPayload()) { - thread = sendPayload(np); + thread = sendPayload(np,callback); if (thread == null) return false; } @@ -155,7 +159,7 @@ public class LanLink extends BaseLink { //Blocking, do not call from main thread @Override - public boolean sendPackageEncrypted(NetworkPackage np, PublicKey key) { + public boolean sendPackageEncrypted(NetworkPackage np,Device.SendPackageStatusCallback callback, PublicKey key) { if (session == null) { Log.e("LanLink", "sendPackage failed: not yet connected"); @@ -166,7 +170,7 @@ public class LanLink extends BaseLink { Thread thread = null; if (np.hasPayload()) { - thread = sendPayload(np); + thread = sendPayload(np,callback); if (thread == null) return false; } diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java index 19038bb4..35850eef 100644 --- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java @@ -169,7 +169,7 @@ public class LanLinkProvider extends BaseLinkProvider { @Override public void run() { NetworkPackage np2 = NetworkPackage.createIdentityPackage(context); - link.sendPackage(np2); + link.sendPackage(np2,null); nioSessions.put(session.getId(), link); addLink(identityPackage, link); diff --git a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java index 0461cf1f..f668fd0e 100644 --- a/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java +++ b/src/org/kde/kdeconnect/Backends/LoopbackBackend/LoopbackLink.java @@ -24,6 +24,7 @@ import android.util.Log; import org.kde.kdeconnect.Backends.BaseLink; import org.kde.kdeconnect.Backends.BaseLinkProvider; +import org.kde.kdeconnect.Device; import org.kde.kdeconnect.NetworkPackage; import java.security.PublicKey; @@ -35,7 +36,7 @@ public class LoopbackLink extends BaseLink { } @Override - public boolean sendPackage(NetworkPackage in) { + public boolean sendPackage(NetworkPackage in,Device.SendPackageStatusCallback callback) { String s = in.serialize(); NetworkPackage out= NetworkPackage.unserialize(s); if (in.hasPayload()) out.setPayload(in.getPayload(), in.getPayloadSize()); @@ -44,7 +45,7 @@ public class LoopbackLink extends BaseLink { } @Override - public boolean sendPackageEncrypted(NetworkPackage in, PublicKey key) { + public boolean sendPackageEncrypted(NetworkPackage in,Device.SendPackageStatusCallback callback, PublicKey key) { try { in = in.encrypt(key); String s = in.serialize(); diff --git a/src/org/kde/kdeconnect/Device.java b/src/org/kde/kdeconnect/Device.java index b9a876b5..0c27fef9 100644 --- a/src/org/kde/kdeconnect/Device.java +++ b/src/org/kde/kdeconnect/Device.java @@ -191,7 +191,12 @@ public class Device implements BaseLink.PackageReceiver { //Send our own public key NetworkPackage np = NetworkPackage.createPublicKeyPackage(context); - sendPackage(np, new SendPackageFinishedCallback(){ + sendPackage(np, new SendPackageStatusCallback(){ + + @Override + public void progressChanged(long progress) { + // Do nothing + } @Override public void sendSuccessful() { @@ -278,7 +283,12 @@ public class Device implements BaseLink.PackageReceiver { //Send our own public key NetworkPackage np = NetworkPackage.createPublicKeyPackage(context); - sendPackage(np, new SendPackageFinishedCallback() { + sendPackage(np, new SendPackageStatusCallback() { + @Override + public void progressChanged(long progress) { + // Do nothng + } + @Override public void sendSuccessful() { pairingDone(); @@ -490,7 +500,8 @@ public class Device implements BaseLink.PackageReceiver { } - public interface SendPackageFinishedCallback { + public interface SendPackageStatusCallback { + void progressChanged(long progress); void sendSuccessful(); void sendFailed(); } @@ -500,7 +511,7 @@ public class Device implements BaseLink.PackageReceiver { } //Async - public void sendPackage(final NetworkPackage np, final SendPackageFinishedCallback callback) { + public void sendPackage(final NetworkPackage np, final SendPackageStatusCallback callback) { final Exception backtrace = new Exception(); @@ -520,9 +531,9 @@ public class Device implements BaseLink.PackageReceiver { try { for (BaseLink link : mLinks) { if (useEncryption) { - success = link.sendPackageEncrypted(np, publicKey); + success = link.sendPackageEncrypted(np,callback, publicKey); } else { - success = link.sendPackage(np); + success = link.sendPackage(np,callback); } if (success) break; } diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java index 1e7e5095..9e7c0d63 100644 --- a/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java +++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/SharePlugin.java @@ -143,18 +143,20 @@ public class SharePlugin extends Plugin { public void run() { try { OutputStream output = new FileOutputStream(destinationFullPath.getPath()); - byte data[] = new byte[1024]; - long total = 0; + long progress = 0,prevProgressPercentage = 0; int count; while ((count = input.read(data)) >= 0) { - total += count; + progress += count; output.write(data, 0, count); if (fileLength > 0) { - if (total >= fileLength) break; - float progress = (total * 100 / fileLength); - builder.setProgress(100,(int)progress,false); - notificationManager.notify(notificationId,builder.build()); + if (progress >= fileLength) break; + long progressPercentage = (progress * 100 / fileLength); + if ((progressPercentage - prevProgressPercentage) > 0) { + prevProgressPercentage = progressPercentage; + builder.setProgress(100, (int) progressPercentage, false); + notificationManager.notify(notificationId, builder.build()); + } } //else Log.e("SharePlugin", "Infinite loop? :D"); } diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareToReceiver.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareToReceiver.java index 170b7eb2..d73bea05 100644 --- a/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareToReceiver.java +++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareToReceiver.java @@ -20,12 +20,21 @@ package org.kde.kdeconnect.Plugins.SharePlugin; +import android.app.Notification; +import android.app.NotificationManager; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.preference.PreferenceManager; import android.provider.MediaStore; +import android.support.v4.app.NotificationCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.util.Log; @@ -204,6 +213,21 @@ public class ShareToReceiver extends ActionBarActivity { NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_SHARE); int size = -1; + final NotificationManager notificationManager = (NotificationManager)getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); + final int notificationId = (int)System.currentTimeMillis(); + final NotificationCompat.Builder builder ; + Resources res = getApplicationContext().getResources(); + builder = new NotificationCompat.Builder(getApplicationContext()) + .setContentTitle(res.getString(R.string.outgoing_file_title, device.getName())) + .setTicker(res.getString(R.string.outgoing_file_title, device.getName())) + .setSmallIcon(android.R.drawable.stat_sys_upload) + .setAutoCancel(true) + .setOngoing(true) + .setProgress(100,0,true); + notificationManager.notify(notificationId,builder.build()); + + final Handler progressBarHandler = new Handler(Looper.getMainLooper()); + if (uri.getScheme().equals("file")) { // file:// is a non media uri, so we cannot query the ContentProvider @@ -260,15 +284,83 @@ public class ShareToReceiver extends ActionBarActivity { } - device.sendPackage(np, new Device.SendPackageFinishedCallback() { + final long filesize = size; + final String filename = np.getString("filename"); + + builder.setContentText(res.getString(R.string.outgoing_file_text,filename)); + notificationManager.notify(notificationId,builder.build()); + + device.sendPackage(np, new Device.SendPackageStatusCallback() { + + int prevProgressPercentage = 0,progressPercentage; + + @Override + public void progressChanged(final long progress) { + // update notification progress + progressPercentage = (int)((progress * 100) / filesize); + if (filesize > 0 && (progressPercentage - prevProgressPercentage) > 0) { + prevProgressPercentage = progressPercentage; + progressBarHandler.post(new Runnable() { + @Override + public void run() { + builder.setProgress(100, progressPercentage, false); + notificationManager.notify(notificationId, builder.build()); + } + }); + } + + } + @Override public void sendSuccessful() { + + progressBarHandler.post(new Runnable() { + @Override + public void run() { + Resources res = getApplicationContext().getResources(); + NotificationCompat.Builder builder1 = new NotificationCompat.Builder(getApplicationContext()) + .setContentTitle(res.getString(R.string.sent_file_title, device.getName())) + .setContentText(res.getString(R.string.sent_file_text, filename)) + .setTicker(res.getString(R.string.sent_file_title, device.getName())) + .setSmallIcon(android.R.drawable.stat_sys_upload_done) + .setOngoing(false) + .setAutoCancel(true); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (prefs.getBoolean("share_notification_preference", true)) { + builder1.setDefaults(Notification.DEFAULT_ALL); + } + notificationManager.notify(notificationId, builder1.build()); + } + }); + if (!uriList.isEmpty()) queuedSendUriList(device, uriList); else Log.e("ShareToReceiver", "All files sent"); } @Override public void sendFailed() { + + progressBarHandler.post(new Runnable() { + @Override + public void run() { + Resources res = getApplicationContext().getResources(); + NotificationCompat.Builder builder2 = new NotificationCompat.Builder(getApplicationContext()) + .setContentTitle(res.getString(R.string.sent_file_failed_title, device.getName())) + .setContentText(res.getString(R.string.sent_file_failed_text, filename)) + .setTicker(res.getString(R.string.sent_file_title, device.getName())) + .setSmallIcon(android.R.drawable.stat_notify_error) + .setOngoing(false) + .setAutoCancel(true); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (prefs.getBoolean("share_notification_preference", true)) { + builder2.setDefaults(Notification.DEFAULT_ALL); + } + notificationManager.notify(notificationId, builder2.build()); + } + }); + Log.e("ShareToReceiver", "Failed to send file"); } });