diff --git a/Android.iml b/Android.iml index a6b20cc8..b996df8c 100644 --- a/Android.iml +++ b/Android.iml @@ -1,12 +1,5 @@ - - - - - - diff --git a/KdeConnect/KdeConnect.iml b/KdeConnect/KdeConnect.iml index bdbb99c8..e79ec377 100644 --- a/KdeConnect/KdeConnect.iml +++ b/KdeConnect/KdeConnect.iml @@ -3,8 +3,9 @@ - - + + diff --git a/KdeConnect/build.gradle b/KdeConnect/build.gradle index 423a9cf4..e3d81fa5 100644 --- a/KdeConnect/build.gradle +++ b/KdeConnect/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:0.4' + classpath 'com.android.tools.build:gradle:0.5.+' } } apply plugin: 'android' diff --git a/KdeConnect/src/main/java/org/kde/connect/BackgroundService.java b/KdeConnect/src/main/java/org/kde/connect/BackgroundService.java index dbda41b4..94ffd78c 100644 --- a/KdeConnect/src/main/java/org/kde/connect/BackgroundService.java +++ b/KdeConnect/src/main/java/org/kde/connect/BackgroundService.java @@ -11,6 +11,7 @@ import android.os.IBinder; import android.util.Log; import org.kde.connect.ComputerLinks.BaseComputerLink; +import org.kde.connect.LinkProviders.AvahiTcpLinkProvider; import org.kde.connect.LinkProviders.BaseLinkProvider; import org.kde.connect.LinkProviders.AvahiLinkProvider; import org.kde.connect.PackageEmitters.BasePackageEmitter; @@ -20,38 +21,22 @@ import org.kde.connect.PackageReceivers.BasePackageReceiver; import org.kde.connect.PackageReceivers.PingPackageReceiver; import java.util.ArrayList; +import java.util.Dictionary; +import java.util.HashMap; public class BackgroundService extends Service { SharedPreferences settings; ArrayList locators = new ArrayList(); - ArrayList computerLinks = new ArrayList(); ArrayList emitters = new ArrayList(); ArrayList receivers = new ArrayList(); + HashMap devices = new HashMap(); + PingPackageEmitter pingEmitter; - private void clearComputerLinks() { - Log.i("BackgroundService","clearComputerLinks"); - for(BasePackageEmitter pe : emitters) pe.clearComputerLinks(); - computerLinks.clear(); - } - - private void removeComputerLink(BaseComputerLink cl) { - Log.i("BackgroundService","removeComputerLink"); - for(BasePackageEmitter pe : emitters) pe.removeComputerLink(cl); - computerLinks.remove(cl); - } - - private void addComputerLink(BaseComputerLink cl) { - Log.i("BackgroundService","addComputerLink"); - computerLinks.add(cl); - for(BasePackageEmitter pe : emitters) pe.addComputerLink(cl); - for(BasePackageReceiver pr : receivers) cl.addPackageReceiver(pr); - } - private void registerEmitters() { if (settings.getBoolean("emit_call", true)) { emitters.add(new CallPackageEmitter(getApplicationContext())); @@ -69,11 +54,22 @@ public class BackgroundService extends Service { } public void registerAnnouncers() { - if (settings.getBoolean("announce_avahi", true)) { + /*if (settings.getBoolean("announce_avahi", true)) { locators.add(new AvahiLinkProvider(this)); + }*/ + if (settings.getBoolean("announce_avahi_tcp", true)) { + locators.add(new AvahiTcpLinkProvider(this)); } } + public ArrayList getVisibleDevices() { + ArrayList list = new ArrayList(); + for(Device d : devices.values()) { + list.add(d.getName()); + } + return list; + } + //This will be called for each intent launch, even if the service is already started and is reused @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -85,15 +81,36 @@ public class BackgroundService extends Service { return Service.START_STICKY; } - public void reachComputers() { - clearComputerLinks(); + private void startDiscovery() { + Log.e("StartDiscovery","Registering connection receivers"); for (BaseLinkProvider a : locators) { + Log.e("Registerign", a.toString()); a.reachComputers(new BaseLinkProvider.ConnectionReceiver() { @Override - public void onConnectionAccepted(BaseComputerLink link) { + public void onConnectionAccepted(String deviceId, String name, BaseComputerLink link) { Log.e("BackgroundService", "Connection accepted!"); - //TODO: Check if there are other links available, and keep the best one - addComputerLink(link); + + if (devices.containsKey(deviceId)) { + Log.e("BackgroundService", "known device"); + devices.get(deviceId).addLink(link); + } else { + Log.e("BackgroundService", "unknown device"); + Device device = new Device(deviceId, name, link); + devices.put(deviceId, device); + for (BasePackageEmitter pe : emitters) pe.addDevice(device); + for (BasePackageReceiver pr : receivers) device.addPackageReceiver(pr); + } + + } + + @Override + public void onConnectionLost(BaseComputerLink link) { + Device d = devices.get(link.getDeviceId()); + if (d != null) { + d.removeLink(link); + //if (d.countLinkedDevices() == 0) devices.remove(link.getDeviceId); + } + } }); } @@ -117,9 +134,15 @@ public class BackgroundService extends Service { registerEmitters(); registerReceivers(); registerAnnouncers(); + startDiscovery(); } + public void restart() { + devices.clear(); + startDiscovery(); + } + @Override public void onDestroy() { Log.e("BackgroundService", "Destroying"); @@ -141,11 +164,11 @@ public class BackgroundService extends Service { } private static ArrayList callbacks = new ArrayList(); -/* + public static void Start(Context c) { RunCommand(c, null); } -*/ + public static void RunCommand(Context c, final InstanceCallback callback) { if (callback != null) callbacks.add(callback); Intent serviceIntent = new Intent(c, BackgroundService.class); diff --git a/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/BaseComputerLink.java b/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/BaseComputerLink.java index 9a93c917..57528920 100644 --- a/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/BaseComputerLink.java +++ b/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/BaseComputerLink.java @@ -1,5 +1,7 @@ package org.kde.connect.ComputerLinks; +import org.kde.connect.Device; +import org.kde.connect.LinkProviders.BaseLinkProvider; import org.kde.connect.PackageReceivers.BasePackageReceiver; import org.kde.connect.NetworkPackage; @@ -8,6 +10,27 @@ import java.util.ArrayList; public abstract class BaseComputerLink { + private BaseLinkProvider linkProvider; + + private String deviceId; + + public BaseComputerLink(BaseLinkProvider linkProvider) { + this.linkProvider = linkProvider; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public BaseLinkProvider getLinkProvider() { + return linkProvider; + } + + ArrayList receivers = new ArrayList(); public void addPackageReceiver(BasePackageReceiver pr) { @@ -18,17 +41,13 @@ public abstract class BaseComputerLink { } //Should be called from a background thread listening to packages - protected void packageReceived(NetworkPackage np) { + protected void packageReceived(Device d, NetworkPackage np) { for(BasePackageReceiver pr : receivers) { - pr.onPackageReceived(np); + pr.onPackageReceived(d, np); } } //TO OVERRIDE - - - //Should be async - public abstract void sendPackage(NetworkPackage np); - + public abstract boolean sendPackage(NetworkPackage np); //Should be async } diff --git a/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/TcpComputerLink.java b/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/TcpComputerLink.java new file mode 100644 index 00000000..05f6b690 --- /dev/null +++ b/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/TcpComputerLink.java @@ -0,0 +1,148 @@ +package org.kde.connect.ComputerLinks; + +import android.os.AsyncTask; +import android.util.Log; + +import org.kde.connect.LinkProviders.BaseLinkProvider; +import org.kde.connect.NetworkPackage; +import org.kde.connect.PackageReceivers.BasePackageReceiver; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.Iterator; + +public class TcpComputerLink extends BaseComputerLink { + + private boolean listenign = false; + private SocketChannel sChannel; + private Charset charset = Charset.forName("US-ASCII"); + + public TcpComputerLink(BaseLinkProvider linkProvider, InetAddress ip, int port) throws java.io.IOException { + super(linkProvider); + + sChannel = SocketChannel.open(); + sChannel.connect(new InetSocketAddress(ip, port)); + sChannel.configureBlocking(false); + + } + + @Override + public boolean sendPackage(NetworkPackage np) { + Log.e("TcpComputerLink","sendPackage"); + try { + String s = np.serialize(); + Log.e("SendPackage",s); + + CharsetEncoder enc = charset.newEncoder(); + ByteBuffer bytes = enc.encode(CharBuffer.wrap(s)); + Log.e("asdads",""+bytes.array().length); + int written = sChannel.write(bytes); + + Log.e("SendPackage","sent "+written+" bytes"); + } catch(Exception e) { + Log.e("TcpComputerLink","Exception"); + e.printStackTrace(); + } + return true; + } + + @Override + public void addPackageReceiver(BasePackageReceiver pr) { + Log.e("TcpComputerLink","addPacakgeReceiver"); + super.addPackageReceiver(pr); + if (!listenign) startReceivingPackages(); + } + + public void startReceivingPackages() { + listenign = true; + + try { + + /* + Log.e("TcpComputerLink","start receiving packages"); + InputStreamReader reader = new InputStreamReader(socket.getInputStream()); + Log.e("TcpComputerLink","Entering loop"); + + while (socket.isConnected()) { + if (serverMessage == null) { + //wait(100); + continue; + } + NetworkPackage np = NetworkPackage.unserialize(serverMessage); + Log.e("TcpComputerLink",serverMessage); + packageReceived(np); + }*/ + + + final Selector selector = Selector.open(); + sChannel.register(selector, SelectionKey.OP_CONNECT + SelectionKey.OP_READ); + + new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + selector.select(); //blocking + Iterator it = selector.selectedKeys().iterator(); + // Process each key at a time + while (it.hasNext()) { + // Get the selection key + SelectionKey selKey = (SelectionKey)it.next(); + + // Remove it from the list to indicate that it is being processed + it.remove(); + + if (selKey.isValid() && selKey.isConnectable()) { + // Get channel with connection request + SocketChannel sChannel = (SocketChannel)selKey.channel(); + + boolean success = sChannel.finishConnect(); + if (!success) { + // An error occurred; handle it + + // Unregister the channel with this selector + selKey.cancel(); + } + } + if (selKey.isValid() && selKey.isReadable()) { + // Get channel with bytes to read + + SocketChannel sChannel = (SocketChannel)selKey.channel(); + + ByteBuffer buffer = ByteBuffer.allocate(4096); + int read = sChannel.read(buffer); + //TODO: Check if there is more to read (or we have read more than one package) + String s = new String( buffer.array(), 0, read, charset ); + Log.e("readable","Read "+read+" bytes: "+s); + + NetworkPackage np = NetworkPackage.unserialize(s); + packageReceived(null, np); + + } + } + } catch (Exception e) { + Log.e("TcpComputerLink","Inner loop exception"); + e.printStackTrace(); + listenign = false; + break; + } + } + Log.e("TcpComputerLink","Exiting loop"); + } + }).run(); + + } catch (Exception e) { + Log.e("TcpComputerLink","Exception"); + listenign = false; + e.printStackTrace(); + } + + } +} diff --git a/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/UdpComputerLink.java b/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/UdpComputerLink.java index 2af5d722..8dca89ca 100644 --- a/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/UdpComputerLink.java +++ b/KdeConnect/src/main/java/org/kde/connect/ComputerLinks/UdpComputerLink.java @@ -3,66 +3,78 @@ package org.kde.connect.ComputerLinks; import android.os.AsyncTask; import android.util.Log; +import org.kde.connect.LinkProviders.AvahiLinkProvider; import org.kde.connect.NetworkPackage; +import org.kde.connect.PackageReceivers.BasePackageReceiver; +import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UdpComputerLink extends BaseComputerLink { + DatagramSocket socket = null; int UDP_PORT; InetAddress IP; final int BUFFER_SIZE = 5*1024; - public UdpComputerLink(InetAddress ip, int port) { + public UdpComputerLink(AvahiLinkProvider linkProvider, InetAddress ip, int port) throws IOException { + super(linkProvider); UDP_PORT = port; IP = ip; + } - Log.e("UdpComputerLink","" + ip + ":" + UDP_PORT); -/* - new AsyncTask() { + @Override + public boolean sendPackage(NetworkPackage np) { + if (socket == null) startReceivingPackages(); + Log.e("UdpComputerLink","sendPackage"); + final String messageStr = np.serialize(); + Log.e("UdpComputerLink", "aboutToSend"); + int msg_length = messageStr.length(); + byte[] message = messageStr.getBytes(); + DatagramPacket p = new DatagramPacket(message, msg_length, IP, UDP_PORT); + Log.e("UdpComputerLink", "aboutToSend " + IP + ":" + UDP_PORT); + try { + socket.send(p); + } catch (Exception e) { + Log.e("UdpComputerLink", "Exception!"); + } + Log.e("UdpComputerLink", "sent"); + return true; + } + @Override + public void addPackageReceiver(BasePackageReceiver pr) { + super.addPackageReceiver(pr); + if (socket == null) startReceivingPackages(); + } + + private void startReceivingPackages() { + try { + socket = new DatagramSocket(UDP_PORT); + }catch(Exception e) { + Log.e("UdpComputerLink","Exception"); + e.printStackTrace(); + } + Log.e("UdpComputerLink","" + IP + ":" + UDP_PORT); + new Thread(new Runnable() { @Override - protected Void doInBackground(Void... voids) { + public void run() { try { Log.e("UdpComputerLink","Waiting for udp datagrams"); byte[] buffer = new byte[BUFFER_SIZE]; - DatagramSocket socket = new DatagramSocket(UDP_PORT); while(true){ DatagramPacket packet = new DatagramPacket(buffer, buffer.length ); socket.receive(packet); String s = new String(packet.getData(), 0, packet.getLength()); - packageReceived(NetworkPackage.fromString(s)); + packageReceived(null,NetworkPackage.unserialize(s)); } - } catch (IOException e) { + } catch (java.io.IOException e) { + Log.e("UdpComputerLink","Exception"); e.printStackTrace(); } - return null; } - }.execute(); -*/ - } - - @Override - public void sendPackage(NetworkPackage np) { - Log.e("UdpComputerLink","sendPackage"); - final String messageStr = np.serialize(); - new AsyncTask(){ - @Override - protected Void doInBackground(Void... voids) { - try { - DatagramSocket s = new DatagramSocket(); - int msg_length = messageStr.length(); - byte[] message = messageStr.getBytes(); - DatagramPacket p = new DatagramPacket(message, msg_length,IP,UDP_PORT); - s.send(p); - Log.e("Sent", messageStr); - } catch(Exception e) { - e.printStackTrace(); - } - return null; - } - }.execute(); + }).run(); } } diff --git a/KdeConnect/src/main/java/org/kde/connect/Device.java b/KdeConnect/src/main/java/org/kde/connect/Device.java new file mode 100644 index 00000000..931e0d06 --- /dev/null +++ b/KdeConnect/src/main/java/org/kde/connect/Device.java @@ -0,0 +1,92 @@ +package org.kde.connect; + +import android.os.AsyncTask; +import android.util.Log; + +import org.kde.connect.ComputerLinks.BaseComputerLink; +import org.kde.connect.PackageReceivers.BasePackageReceiver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class Device { + + private ArrayList links = new ArrayList(); + private ArrayList receivers = new ArrayList(); + + private String deviceId; + private String name; + + + Device(String deviceId, String name, BaseComputerLink dl) { + this.deviceId = deviceId; + this.name = name; + addLink(dl); + } + + public String getName() { + return name; + } + + public String getDeviceId() { + return deviceId; + } + + public void addLink(BaseComputerLink link) { + Log.e("Device","addLink "+link.getLinkProvider().getName()+" -> "+getName()); + links.add(link); + Collections.sort(links, new Comparator() { + @Override + public int compare(BaseComputerLink o, BaseComputerLink o2) { + return o2.getLinkProvider().getPriority() - o.getLinkProvider().getPriority(); + } + }); + + link.addPackageReceiver(new BasePackageReceiver() { + @Override + public void onPackageReceived(Device d, NetworkPackage np) { + for (BasePackageReceiver receiver : receivers) { + receiver.onPackageReceived(Device.this, np); + } + } + }); + } + + + + public void removeLink(BaseComputerLink link) { + links.remove(link); + } + + + + //Send and receive interfaces + + public void addPackageReceiver(BasePackageReceiver receiver) { + receivers.add(receiver); + } + + public boolean sendPackage(final NetworkPackage np) { + Log.e("Device","sendPackage"); + + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + Log.e("sendPackage","Do in background"); + for(BaseComputerLink link : links) { + Log.e("sendPackage","Trying "+link.getLinkProvider().getName()); + if (link.sendPackage(np)) { + Log.e("sent using", link.getLinkProvider().getName()); + return null; + } + } + Log.e("sendPackage","Error: Package could not be sent"); + return null; + } + }.execute(); + Log.e("Device","/sendPackage"); + return true; //FIXME + } + +} diff --git a/KdeConnect/src/main/java/org/kde/connect/LinkProviders/AvahiLinkProvider.java b/KdeConnect/src/main/java/org/kde/connect/LinkProviders/AvahiLinkProvider.java index 38e806c7..600886fb 100644 --- a/KdeConnect/src/main/java/org/kde/connect/LinkProviders/AvahiLinkProvider.java +++ b/KdeConnect/src/main/java/org/kde/connect/LinkProviders/AvahiLinkProvider.java @@ -6,7 +6,9 @@ import android.net.nsd.NsdServiceInfo; import android.util.Log; import org.kde.connect.ComputerLinks.UdpComputerLink; +import org.kde.connect.Device; import org.kde.connect.NetworkPackage; +import org.kde.connect.PackageReceivers.BasePackageReceiver; import java.lang.Override; import java.util.ArrayList; @@ -21,6 +23,8 @@ public class AvahiLinkProvider implements BaseLinkProvider { Context ctx; + private NsdManager.DiscoveryListener oldListener = null; + public AvahiLinkProvider(Context context) { mNsdManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE); ctx = context; @@ -31,34 +35,50 @@ public class AvahiLinkProvider implements BaseLinkProvider { visibleComputers.clear(); + if (oldListener != null) mNsdManager.stopServiceDiscovery(oldListener); + Log.e("AvahiLinkProvider", "Discovering computers..."); final NsdManager.ResolveListener mResolveListener = new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { - Log.e("AvahiLinkProvider", "Resolve failed" + errorCode); + Log.e("AvahiLinkProvider", "Resolve failed: " + errorCode); } @Override - public void onServiceResolved(NsdServiceInfo serviceInfo) { - Log.e("AvahiLinkProvider", "Resolve Succeeded. " + serviceInfo); - - //Computer found + public void onServiceResolved(final NsdServiceInfo serviceInfo) { + Log.e("AvahiLinkProvider", "Resolve Succeeded: " + serviceInfo); //Handshake link - UdpComputerLink link = new UdpComputerLink(serviceInfo.getHost(),serviceInfo.getPort()); - NetworkPackage np = NetworkPackage.createIdentityPackage(ctx); - link.sendPackage(np); + try { + UdpComputerLink link = new UdpComputerLink(AvahiLinkProvider.this,serviceInfo.getHost(),serviceInfo.getPort()); + link.addPackageReceiver(new BasePackageReceiver() { + @Override + public void onPackageReceived(Device d, NetworkPackage np) { + Log.e("AvahiLinkProvider","Received reply"); + if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_IDENTITY)) { + String id = np.getString("deviceId"); + String name = np.getString("deviceName"); + //Real data link + try { + UdpComputerLink link2 = new UdpComputerLink(AvahiLinkProvider.this,serviceInfo.getHost(),10603); + visibleComputers.add(link2); + cr.onConnectionAccepted(id, name, link2); + } catch (Exception e) { - //TODO: Wait for computer confirmation and ensure this is the device we want (requiring user interaction) - //link.addPackageReceiver(); - - //Real data link - UdpComputerLink link2 = new UdpComputerLink(serviceInfo.getHost(),10600); - visibleComputers.add(link2); - cr.onConnectionAccepted(link2); + } + } else { + Log.e("AvahiLinkProvider","Received non-identity package"); + } + } + }); + Log.e("AvahiLinkProvider","Sending identity package"); + NetworkPackage np = NetworkPackage.createIdentityPackage(ctx); + link.sendPackage(np); + } catch (Exception e) { + } } }; @@ -85,8 +105,7 @@ public class AvahiLinkProvider implements BaseLinkProvider { @Override public void onServiceLost(NsdServiceInfo service) { - Log.e("AvahiLinkProvider", "service lost" + service); - visibleComputers.remove(service); + Log.e("AvahiLinkProvider", "Service lost: " + service); } @Override @@ -107,9 +126,21 @@ public class AvahiLinkProvider implements BaseLinkProvider { } }; + oldListener = mDiscoveryListener; mNsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener); } + @Override + public int getPriority() { + return 100; + } + + + @Override + public String getName() { + return "AvahiUdpLinkProvider"; + } + } diff --git a/KdeConnect/src/main/java/org/kde/connect/LinkProviders/AvahiTcpLinkProvider.java b/KdeConnect/src/main/java/org/kde/connect/LinkProviders/AvahiTcpLinkProvider.java new file mode 100644 index 00000000..8216f16a --- /dev/null +++ b/KdeConnect/src/main/java/org/kde/connect/LinkProviders/AvahiTcpLinkProvider.java @@ -0,0 +1,150 @@ +package org.kde.connect.LinkProviders; + +import android.content.Context; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.util.Log; + +import org.kde.connect.ComputerLinks.TcpComputerLink; +import org.kde.connect.Device; +import org.kde.connect.NetworkPackage; +import org.kde.connect.PackageReceivers.BasePackageReceiver; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class AvahiTcpLinkProvider implements BaseLinkProvider { + + String serviceType = "_kdeconnect._tcp"; + + NsdManager mNsdManager; + + HashMap visibleComputers = new HashMap(); + + Context ctx; + private NsdManager.DiscoveryListener oldListener = null; + + public AvahiTcpLinkProvider(Context context) { + mNsdManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE); + ctx = context; + } + + @Override + public void reachComputers(final ConnectionReceiver cr) { + + visibleComputers.clear(); + + if (oldListener != null) mNsdManager.stopServiceDiscovery(oldListener); + + Log.e("AvahiTcpLinkProvider", "Discovering computers..."); + + final NsdManager.ResolveListener mResolveListener = new NsdManager.ResolveListener() { + + @Override + public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { + Log.e("AvahiTcpLinkProvider", "Resolve failed" + errorCode); + } + + @Override + public void onServiceResolved(NsdServiceInfo serviceInfo) { + Log.e("AvahiTcpLinkProvider", "Resolve Succeeded. " + serviceInfo); + + try { + Log.e("AvahiTcpLinkProvider", "Creating link"); + final InetAddress host = serviceInfo.getHost(); + final int port = serviceInfo.getPort(); + final TcpComputerLink link = new TcpComputerLink(AvahiTcpLinkProvider.this,host,port); + Log.e("AvahiTcpLinkProvider", "Waiting identity package"); + link.addPackageReceiver(new BasePackageReceiver() { + @Override + public void onPackageReceived(Device d, NetworkPackage np) { + + Log.e("AvahiTcpLinkProvider", "Received package: " + np.getType()); + + if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_IDENTITY)) { + String id = np.getString("deviceId"); + String name = np.getString("deviceName"); + + link.setDeviceId(id); + link.sendPackage(NetworkPackage.createIdentityPackage(ctx)); + visibleComputers.put(host,link); + cr.onConnectionAccepted(id,name,link); + + } + + } + }); + link.startReceivingPackages(); + } catch (Exception e) { + Log.e("AvahiTcpLinkProvider","Exception"); + e.printStackTrace(); + } + + } + + }; + + NsdManager.DiscoveryListener mDiscoveryListener = new NsdManager.DiscoveryListener() { + + @Override + public void onDiscoveryStarted(String regType) { + Log.e("AvahiTcpLinkProvider", "Service discovery started"); + } + + @Override + public void onServiceFound(NsdServiceInfo service) { + Log.e("AvahiTcpLinkProvider", "Service discovery success" + service); + + if (!service.getServiceType().startsWith(serviceType)) { + Log.e("AvahiTcpLinkProvider", "Unknown Service Type: " + service.getServiceType()); + } else { + Log.e("AvahiTcpLinkProvider", "Computer found, resolving..."); + mNsdManager.resolveService(service, mResolveListener); + } + + } + + @Override + public void onServiceLost(NsdServiceInfo service) { + Log.e("AvahiTcpLinkProvider", "service lost" + service); + TcpComputerLink link = visibleComputers.remove(service.getHost()); + if (link != null) cr.onConnectionLost(link); + } + + @Override + public void onDiscoveryStopped(String serviceType) { + Log.e("AvahiTcpLinkProvider", "Discovery stopped: " + serviceType); + } + + @Override + public void onStartDiscoveryFailed(String serviceType, int errorCode) { + Log.e("AvahiTcpLinkProvider", "Discovery failed: Error code:" + errorCode); + mNsdManager.stopServiceDiscovery(this); + } + + @Override + public void onStopDiscoveryFailed(String serviceType, int errorCode) { + Log.e("AvahiTcpLinkProvider", "Discovery failed: Error code:" + errorCode); + mNsdManager.stopServiceDiscovery(this); + } + }; + + oldListener = mDiscoveryListener; + mNsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener); + + } + + @Override + public int getPriority() { + return 101; + } + + @Override + public String getName() { + return "AvahiTcpLinkProvider"; + } +} diff --git a/KdeConnect/src/main/java/org/kde/connect/LinkProviders/BaseLinkProvider.java b/KdeConnect/src/main/java/org/kde/connect/LinkProviders/BaseLinkProvider.java index 89cde52f..d27e8fb6 100644 --- a/KdeConnect/src/main/java/org/kde/connect/LinkProviders/BaseLinkProvider.java +++ b/KdeConnect/src/main/java/org/kde/connect/LinkProviders/BaseLinkProvider.java @@ -5,11 +5,13 @@ import org.kde.connect.ComputerLinks.BaseComputerLink; public interface BaseLinkProvider { public interface ConnectionReceiver { - public void onConnectionAccepted(BaseComputerLink link); + public void onConnectionAccepted(String deviceId, String name, BaseComputerLink link); + public void onConnectionLost(BaseComputerLink link); } //To override public void reachComputers(ConnectionReceiver cr); - + public int getPriority(); + public String getName(); } diff --git a/KdeConnect/src/main/java/org/kde/connect/MainActivity.java b/KdeConnect/src/main/java/org/kde/connect/MainActivity.java index 450c3d2d..65567c5b 100644 --- a/KdeConnect/src/main/java/org/kde/connect/MainActivity.java +++ b/KdeConnect/src/main/java/org/kde/connect/MainActivity.java @@ -11,6 +11,10 @@ import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import org.kde.kdeconnect.R; public class MainActivity extends Activity { @@ -23,18 +27,17 @@ public class MainActivity extends Activity { BackgroundService.RunCommand(MainActivity.this, new BackgroundService.InstanceCallback() { @Override public void onServiceStart(BackgroundService service) { - service.reachComputers(); } }); findViewById(R.id.button1).setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { - Log.i("MainActivity","Button2"); + Log.i("MainActivity","Button1"); BackgroundService.RunCommand(MainActivity.this, new BackgroundService.InstanceCallback() { @Override public void onServiceStart(BackgroundService service) { - service.reachComputers(); + service.restart(); } }); } @@ -43,7 +46,7 @@ public class MainActivity extends Activity { findViewById(R.id.button2).setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { - Log.i("MainActivity","Button3"); + Log.i("MainActivity","Button2"); BackgroundService.RunCommand(MainActivity.this, new BackgroundService.InstanceCallback() { @Override public void onServiceStart(BackgroundService service) { @@ -54,6 +57,28 @@ public class MainActivity extends Activity { } }); + final ListView list = (ListView)findViewById(R.id.listView1); + + + findViewById(R.id.button3).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + Log.i("MainActivity","Button3"); + BackgroundService.RunCommand(MainActivity.this, new BackgroundService.InstanceCallback() { + @Override + public void onServiceStart(final BackgroundService service) { + runOnUiThread(new Runnable() { + @Override + public void run() { + String[] listContent = service.getVisibleDevices().toArray(new String[0]); + list.setAdapter(new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, listContent)); + } + }); + } + }); + + } + }); } @Override diff --git a/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/BasePackageEmitter.java b/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/BasePackageEmitter.java index 88277152..4ed2d10d 100644 --- a/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/BasePackageEmitter.java +++ b/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/BasePackageEmitter.java @@ -1,31 +1,42 @@ package org.kde.connect.PackageEmitters; +import android.util.Log; + import org.kde.connect.ComputerLinks.BaseComputerLink; +import org.kde.connect.Device; import org.kde.connect.NetworkPackage; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; public class BasePackageEmitter { - private ArrayList mBaseComputerLinks = new ArrayList(); + private ArrayList mDevices = new ArrayList(); - public void addComputerLink(BaseComputerLink cl) { - mBaseComputerLinks.add(cl); + public void addDevice(Device d) { + mDevices.add(d); } - public void removeComputerLink(BaseComputerLink cl) { - mBaseComputerLinks.remove(cl); + + public void removeDevice(Device d) { + mDevices.remove(d); } + public void clearComputerLinks() { - mBaseComputerLinks.clear(); + mDevices.clear(); } - protected int countLinkedComputers() { - return mBaseComputerLinks.size(); + public int countLinkedDevices() { + return mDevices.size(); } - protected void sendPackage(NetworkPackage np) { - for(BaseComputerLink cl : mBaseComputerLinks) { - cl.sendPackage(np); + + protected boolean sendPackage(NetworkPackage np) { + if (mDevices.isEmpty()) return false; + for(Device d : mDevices) { + d.sendPackage(np); } + return true; } } diff --git a/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/PingPackageEmitter.java b/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/PingPackageEmitter.java index afe1b9ef..a059bfc4 100644 --- a/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/PingPackageEmitter.java +++ b/KdeConnect/src/main/java/org/kde/connect/PackageEmitters/PingPackageEmitter.java @@ -3,6 +3,7 @@ package org.kde.connect.PackageEmitters; import android.content.Context; import android.util.Log; +import org.kde.connect.Device; import org.kde.connect.NetworkPackage; @@ -11,8 +12,14 @@ public class PingPackageEmitter extends BasePackageEmitter { public PingPackageEmitter(Context ctx) { } + @Override + public void addDevice(Device d) { + super.addDevice(d); + Log.e("PinkPackageEmitter","addDevice: "+d.getName()); + } + public void sendPing() { - Log.e("PingPackageEmitter", "sendPing to "+countLinkedComputers()); + Log.e("PingPackageEmitter", "sendPing to "+countLinkedDevices()); NetworkPackage lastPackage = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_PING); sendPackage(lastPackage); diff --git a/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/BasePackageReceiver.java b/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/BasePackageReceiver.java index 16e04d54..f7b5f86a 100644 --- a/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/BasePackageReceiver.java +++ b/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/BasePackageReceiver.java @@ -1,9 +1,10 @@ package org.kde.connect.PackageReceivers; +import org.kde.connect.Device; import org.kde.connect.NetworkPackage; public interface BasePackageReceiver { - public void onPackageReceived(NetworkPackage np); + public void onPackageReceived(Device d, NetworkPackage np); } diff --git a/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/PingPackageReceiver.java b/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/PingPackageReceiver.java index ae6d63ef..6c9b1d80 100644 --- a/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/PingPackageReceiver.java +++ b/KdeConnect/src/main/java/org/kde/connect/PackageReceivers/PingPackageReceiver.java @@ -1,8 +1,14 @@ package org.kde.connect.PackageReceivers; +import android.R; +import android.app.Notification; +import android.app.NotificationManager; import android.content.Context; +import android.util.Log; import android.widget.Toast; +import org.kde.connect.BackgroundToast; +import org.kde.connect.Device; import org.kde.connect.NetworkPackage; public class PingPackageReceiver implements BasePackageReceiver { @@ -14,9 +20,23 @@ public class PingPackageReceiver implements BasePackageReceiver { } @Override - public void onPackageReceived(NetworkPackage np) { - if (np.getType() == "kdeconnect.ping") { - Toast.makeText(context, "Ping!", Toast.LENGTH_LONG).show(); + public void onPackageReceived(Device d, NetworkPackage np) { + Log.e("PingPackageReceiver", "onPackageReceived"); + if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_PING)) { + Log.e("PingPackageReceiver", "was a ping!"); + + Notification noti = new Notification.Builder(context) + .setContentTitle(d.getName()) + .setContentText("Ping!") + .setTicker("Ping!") + .setSmallIcon(R.drawable.ic_dialog_alert) + .setAutoCancel(true) + .setDefaults(Notification.DEFAULT_SOUND) + .build(); + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(0, noti); + } } } diff --git a/KdeConnect/src/main/java/org/kde/connect/ServiceLauncher.java b/KdeConnect/src/main/java/org/kde/connect/ServiceLauncher.java index ae37313c..90f5479a 100644 --- a/KdeConnect/src/main/java/org/kde/connect/ServiceLauncher.java +++ b/KdeConnect/src/main/java/org/kde/connect/ServiceLauncher.java @@ -26,7 +26,7 @@ public class ServiceLauncher extends BroadcastReceiver BackgroundService.RunCommand(context, new BackgroundService.InstanceCallback() { @Override public void onServiceStart(BackgroundService service) { - service.reachComputers(); + } }); } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { @@ -34,15 +34,16 @@ public class ServiceLauncher extends BroadcastReceiver BackgroundService.RunCommand(context, new BackgroundService.InstanceCallback() { @Override public void onServiceStart(BackgroundService service) { - service.reachComputers(); + } }); - } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { + } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION) + || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { Log.e("KdeConnect", "Connection state changed, trying to connect"); BackgroundService.RunCommand(context, new BackgroundService.InstanceCallback() { @Override public void onServiceStart(BackgroundService service) { - service.reachComputers(); + } }); } else { diff --git a/KdeConnect/src/main/res/layout/activity_main.xml b/KdeConnect/src/main/res/layout/activity_main.xml index 63642759..64b806b0 100644 --- a/KdeConnect/src/main/res/layout/activity_main.xml +++ b/KdeConnect/src/main/res/layout/activity_main.xml @@ -12,4 +12,11 @@