diff --git a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java --- a/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java +++ b/src/org/kde/kdeconnect/Backends/LanBackend/LanLinkProvider.java @@ -20,12 +20,15 @@ package org.kde.kdeconnect.Backends.LanBackend; +import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; import android.preference.PreferenceManager; import android.util.Base64; import android.util.Log; +import android.net.nsd.NsdServiceInfo; +import android.net.nsd.NsdManager; import org.kde.kdeconnect.Backends.BaseLinkProvider; import org.kde.kdeconnect.BackgroundService; @@ -77,6 +80,10 @@ private DatagramSocket udpServer; private DatagramSocket udpServerOldPort; + private NsdManager mNsdManager; + private NsdManager.RegistrationListener mRegistrationListener; + private boolean mServiceRegistered = false; + boolean listening = false; // To prevent infinte loop between Android < IceCream because both device can only broadcast identity package but cannot connect via TCP @@ -363,6 +370,7 @@ private void broadcastUdpPacket() { + // TODO check this already in onNetworkChange? if (NetworkHelper.isOnMobileNetwork(context)) { Log.w("LanLinkProvider", "On 3G network, not sending broadcast."); return; @@ -437,17 +445,111 @@ } broadcastUdpPacket(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // mDNS support was first introduced with API level 16 (jelly bean), + // but setting attributes came with 21 (lollipop). + initializeRegistrationListener(); + + initializeNsdManager(); + } + } + } + + @TargetApi(21) + public void initializeNsdManager() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return; } + mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE); + try { + mNsdManager.unregisterService(mRegistrationListener); + } catch (java.lang.IllegalArgumentException e) { + // not yet registered, but it's fine. + } + NsdServiceInfo serviceInfo = new NsdServiceInfo(); + + // The name is subject to change based on conflicts + // with other services advertised on the same network. + NetworkPacket myIdentity = NetworkPacket.createIdentityPacket(context); + String did = myIdentity.getString("deviceID"); + String name = myIdentity.getString("deviceName"); + InetAddress addr = this.tcpServer.getInetAddress(); + int port = this.tcpServer.getLocalPort(); + + // These cause the requirement for api level 21. + serviceInfo.setAttribute("name", myIdentity.getString("deviceName")); + serviceInfo.setAttribute("id", myIdentity.getString("deviceId")); + serviceInfo.setAttribute("type", myIdentity.getString("deviceType")); + serviceInfo.setAttribute("version", myIdentity.getString("protocolVersion")); + + // TODO the capabilities as such are too long to fit into the TXT records + // Log.w("KDE/Lan", myIdentity.getString("incomingCapabilities")); + // Log.w("KDE/Lan", myIdentity.getString("outgoingCapabilities")); + // serviceInfo.setAttribute("incomingCapabilities", myIdentity.getString("incomingCapabilities")); + // serviceInfo.setAttribute("outgoingCapabilities", myIdentity.getString("outgoingCapabilities")); + + serviceInfo.setServiceName("KDE Connect on " + myIdentity.getString("deviceName")); + serviceInfo.setServiceType("_kdeconnect._tcp"); + serviceInfo.setHost(addr); + serviceInfo.setPort(port); + + //Log.d("KDE/Lan", "service: " + serviceInfo.toString()); + + + mNsdManager.registerService( + serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); + } + + @TargetApi(16) + public void initializeRegistrationListener() { + mRegistrationListener = new NsdManager.RegistrationListener() { + + @Override + public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) { + // Save the service name. Android may have changed it in order to + // resolve a conflict, so update the name you initially requested + // with the name Android actually used. + Log.w("KDE/LanLinkProvider", "mDNS: Registered " + NsdServiceInfo.getServiceName()); + } + + @Override + public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + // Registration failed! Put debugging code here to determine why. + Log.w("KDE/LanLinkProvider", "mDNS: Registration failed"); + } + + @Override + public void onServiceUnregistered(NsdServiceInfo arg0) { + // Service has been unregistered. This only happens when you call + // NsdManager.unregisterService() and pass in this listener. + Log.w("KDE/LanLinkProvider", "mDNS: Service unregistered: " + arg0); + } + + @Override + public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + // Unregistration failed. Put debugging code here to determine why. + Log.w("KDE/LanLinkProvider", "mDNS: Unregister of " + serviceInfo + " failed with: " + errorCode); + } + }; } + @Override public void onNetworkChange() { broadcastUdpPacket(); + if (NetworkHelper.isOnMobileNetwork(context)) { + Log.w("LanLinkProvider", "On 3G network, disabling mDNS advertisements."); + mNsdManager.unregisterService(mRegistrationListener); + + } else { + this.initializeNsdManager(); + } } @Override public void onStop() { - //Log.i("KDE/LanLinkProvider", "onStop"); + Log.i("KDE/LanLinkProvider", "onStop"); listening = false; try { tcpServer.close(); @@ -464,6 +566,11 @@ } catch (Exception e){ e.printStackTrace(); } + try { + mNsdManager.unregisterService(mRegistrationListener); + } catch(Exception e) { + e.printStackTrace(); + } } @Override