/* This file is part of the Android Clementine Remote.
* Copyright (C) 2013, Andreas Muttscheller <asfa194@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.qspool.clementineremote.backend.mdns;
import android.annotation.TargetApi;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import java.io.IOException;
import java.net.Inet4Address;
import java.util.LinkedList;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import de.qspool.clementineremote.App;
import de.qspool.clementineremote.backend.elements.ServiceFound;
import de.qspool.clementineremote.utils.Utilities;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class ClementineMDnsDiscovery {
private JmDNS mJmDNS;
private MulticastLock mMulticastLock;
private Thread mThread;
private final String mDnsType = "_clementine._tcp.local.";
private ServiceListener mListener;
private LinkedList<ServiceInfo> mServices;
private Handler mConnectActivityHandler;
public ClementineMDnsDiscovery(Handler handler) {
mConnectActivityHandler = handler;
mServices = new LinkedList<>();
}
/**
* Discover services on the network
*/
public void discoverServices() {
mThread = new Thread(new Runnable() {
@Override
public void run() {
WifiManager wifi = (WifiManager)
App.getApp().getApplicationContext()
.getSystemService(android.content.Context.WIFI_SERVICE);
mMulticastLock = wifi.createMulticastLock("Clementine Lock");
mMulticastLock.setReferenceCounted(true);
mMulticastLock.acquire();
jmDnsListener();
}
});
mThread.start();
}
/**
* Stop network discovery
*/
public void stopServiceDiscovery() {
mThread = new Thread(new Runnable() {
@Override
public void run() {
try {
if (mListener != null) {
mJmDNS.removeServiceListener(mDnsType, mListener);
mJmDNS.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (mMulticastLock != null && mMulticastLock.isHeld()) {
mMulticastLock.release();
}
}
});
mThread.start();
}
/**
* Get the services on the network
*
* @return A LinkedList of ServiceInfo with the services.
*/
public LinkedList<ServiceInfo> getServices() {
return mServices;
}
/**
* Get the Hosts on the network
*
* @return A LinkedList of Hosts found
*/
public LinkedList<String> getHosts() {
LinkedList<String> hosts = new LinkedList<String>();
for (ServiceInfo info : mServices) {
hosts.add(info.getName());
}
return hosts;
}
private void jmDnsListener() {
try {
Inet4Address ip = Utilities.getIp4Address();
if (ip == null) {
return;
}
mJmDNS = JmDNS.create(ip);
mJmDNS.addServiceListener(mDnsType, mListener = new ServiceListener() {
@Override
public void serviceAdded(ServiceEvent serviceEvent) {
mJmDNS.requestServiceInfo(serviceEvent.getType(), serviceEvent.getName(), 250);
}
@Override
public void serviceRemoved(ServiceEvent serviceEvent) {
ServiceInfo info = serviceEvent.getInfo();
mServices.remove(info);
// Send a message to the connect activity
if (mConnectActivityHandler != null) {
Message msg = Message.obtain();
msg.obj = new ServiceFound();
mConnectActivityHandler.sendMessage(msg);
}
}
@Override
public void serviceResolved(ServiceEvent serviceEvent) {
ServiceInfo info = serviceEvent.getInfo();
Inet4Address inet4[] = info.getInet4Addresses();
if (inet4.length > 0) {
mServices.add(info);
// Send a message to the connect activity
if (mConnectActivityHandler != null) {
Message msg = Message.obtain();
msg.obj = new ServiceFound();
mConnectActivityHandler.sendMessage(msg);
}
}
}
});
} catch (Exception e) {
mJmDNS = null;
}
}
}