On Android, JmDNS being called repeatedly with network ON and OFF - android

I am having a problem with using the JmDNS library for an Android app.
Since Bonjour does not send periodic keep-alive messages, I am closing and opening a new JmDNS instance every 30 seconds, so that I can have the serviceAdded and serviceResolved functions called.
But in between these instance creations, if I switch off and on the Wifi, although the creation of the JmDNS instance succeeds, my serviceAdded and serviceResolved functions are not called.
My main doubts are:
1) Is it ok to re-create these instance again and again and therefore effect a kind-of polling? Or is there a better way?
2) If the network is switched off and on, is there something I need to do each time I create the JmDNS instance?
Here's a snippet of my code:
private void _startJmDnsService() throws IOException {
if (mJmdns != null) {
if (mJmDnsServiceListener != null) {
mJmdns.removeServiceListener(mBonjourServiceType, mJmDnsServiceListener);
mJmDnsServiceListener = null;
}
mJmdns.close();
mJmdns = null;
}
Log.d(TAG, "starting JmDNS");
mJmdns = JmDNS.create(getInet4Address());
mJmDnsServiceListener = new ServiceListener() {
public void serviceResolved(ServiceEvent ev) {
ServiceInfo serviceInfo = ev.getInfo();
Log.w(TAG, "serviceResolved for device " + serviceInfo.getName());
}
public void serviceRemoved(ServiceEvent ev) {
ServiceInfo serviceInfo = ev.getInfo();
Log.w(TAG, "serviceRemoved for device " + serviceInfo.getName());
CDevice.removeDevice(deviceId);
}
public void serviceAdded(ServiceEvent event) {
// Required to force serviceResolved to be called again
// (after the first search)
ServiceInfo serviceInfo = event.getInfo();
Log.w(TAG, "serviceAdded for device " + serviceInfo.getName());
mJmdns.requestServiceInfo(event.getType(), event.getName(), 1);
}
};
mJmdns.addServiceListener(mBonjourServiceType, mJmDnsServiceListener);
Log.w(TAG, "mJmdns Service Listener added!");
}

For anyone that might have a similar problem. There was nothing in the JmDNS library that had a problem. In my code, I was closing the multicast socket between instance calls, which was creating a problem.

Related

Programmatically pairing with a BLE device on Android 4.4+

Does anyone have a complete working example of how to programmatically pair with a BLE (not Bluetooth Classic) device that uses passkey entry (i.e. a 6-digit PIN) or Numeric Comparison on Android 4.4 or later? By 'programmatically' I mean I tell Android the PIN - the user isn't prompted.
There are many similar questions about this on SO but they are either a) about Bluetooth Classic, b) old (before setPin() and createBond() were public), or c) unanswered.
My understanding is as follows.
You connect to the device and discover its services.
You try to read a 'protected' characteristic.
The device returns an authentication error.
Android somehow initiates pairing and you tell it the PIN.
You can now read the characteristic.
I have created a device using mBed running on the nRF51-DK and given it a single characteristic.
I set up the security parameters like so:
ble.securityManager().init(
true, // Enable bonding (though I don't really need this)
true, // Require MitM protection. I assume you don't get a PIN prompt without this, though I'm not 100% sure.
SecurityManager::IO_CAPS_DISPLAY_ONLY, // This makes it us the Passkey Entry (PIN) pairing method.
"123456"); // Static PIN
And then in the characteristic I used
requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
Now when I try to read it with the Nordic Master Control Panel, I get a pairing request notification like this:
And I can put this PIN in, and then MCP says I'm bonded, and can read the characteristic.
However, in my app I would like to avoid having the user enter the PIN, since I know it already. Does anyone have a complete recent example of how to do this?
Edit: By the way this is the most relevant question I found on SO, but the answer there doesn't seem to work.
I almost have it working. It pairs programmatically but I can't get rid of the "Pairing request" notification. Some answers to this question claim to be able to hide it just after it is shown using the hidden method cancelPairingUserInput() but that doesn't seem to work for me.
Edit: Success!
I eventually resorted to reading the source code of BluetoothPairingRequest and the code that sends the pairing request broadcast and realised I should be intercepting the ACTION_PAIRING_REQUEST. Fortunately it is an ordered intent broadcast so you can intercept it before the system does.
Here's the procedure.
Register to receive BluetoothDevice.ACTION_PAIRING_REQUEST changed broadcast intents. Use a high priority!
Connect to the device.
Discover services.
If you have disconnected by now, it's probably because the bond information is incorrect (e.g. the peripheral purged it). In that case, delete the bond information using a hidden method (seriously Google), and reconnect.
Try to read a characteristic that requires encryption MitM protection.
In the ACTION_PAIRING_REQUEST broadcast receiver, check that the pairing type is BluetoothDevice.PAIRING_VARIANT_PIN and if so, call setPin() and abortBroadcast(). Otherwise you can just let the system handle it, or show an error or whatever.
Here is the code.
/* This implements the BLE connection logic. Things to watch out for:
1. If the bond information is wrong (e.g. it has been deleted on the peripheral) then
discoverServices() will cause a disconnect. You need to delete the bonding information and reconnect.
2. If the user ignores the PIN request, you get the undocumented GATT_AUTH_FAILED code.
*/
public class ConnectActivityLogic extends Fragment
{
// The connection to the device, if we are connected.
private BluetoothGatt mGatt;
// This is used to allow GUI fragments to subscribe to state change notifications.
public static class StateObservable extends Observable
{
private void notifyChanged() {
setChanged();
notifyObservers();
}
};
// When the logic state changes, State.notifyObservers(this) is called.
public final StateObservable State = new StateObservable();
public ConnectActivityLogic()
{
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Tell the framework to try to keep this fragment around
// during a configuration change.
setRetainInstance(true);
// Actually set it in response to ACTION_PAIRING_REQUEST.
final IntentFilter pairingRequestFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingRequestFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
getActivity().getApplicationContext().registerReceiver(mPairingRequestRecevier, pairingRequestFilter);
// Update the UI.
State.notifyChanged();
// Note that we don't actually need to request permission - all apps get BLUETOOTH and BLUETOOTH_ADMIN permissions.
// LOCATION_COARSE is only used for scanning which I don't need (MAC is hard-coded).
// Connect to the device.
connectGatt();
}
#Override
public void onDestroy()
{
super.onDestroy();
// Disconnect from the device if we're still connected.
disconnectGatt();
// Unregister the broadcast receiver.
getActivity().getApplicationContext().unregisterReceiver(mPairingRequestRecevier);
}
// The state used by the UI to show connection progress.
public ConnectionState getConnectionState()
{
return mState;
}
// Internal state machine.
public enum ConnectionState
{
IDLE,
CONNECT_GATT,
DISCOVER_SERVICES,
READ_CHARACTERISTIC,
FAILED,
SUCCEEDED,
}
private ConnectionState mState = ConnectionState.IDLE;
// When this fragment is created it is given the MAC address and PIN to connect to.
public byte[] macAddress()
{
return getArguments().getByteArray("mac");
}
public int pinCode()
{
return getArguments().getInt("pin", -1);
}
// Start the connection process.
private void connectGatt()
{
// Disconnect if we are already connected.
disconnectGatt();
// Update state.
mState = ConnectionState.CONNECT_GATT;
State.notifyChanged();
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress());
// Connect!
mGatt = device.connectGatt(getActivity(), false, mBleCallback);
}
private void disconnectGatt()
{
if (mGatt != null)
{
mGatt.disconnect();
mGatt.close();
mGatt = null;
}
}
// See https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/stack/include/gatt_api.h
private static final int GATT_ERROR = 0x85;
private static final int GATT_AUTH_FAIL = 0x89;
private android.bluetooth.BluetoothGattCallback mBleCallback = new BluetoothGattCallback()
{
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
{
super.onConnectionStateChange(gatt, status, newState);
switch (newState)
{
case BluetoothProfile.STATE_CONNECTED:
// Connected to the device. Try to discover services.
if (gatt.discoverServices())
{
// Update state.
mState = ConnectionState.DISCOVER_SERVICES;
State.notifyChanged();
}
else
{
// Couldn't discover services for some reason. Fail.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
// If we try to discover services while bonded it seems to disconnect.
// We need to debond and rebond...
switch (mState)
{
case IDLE:
// Do nothing in this case.
break;
case CONNECT_GATT:
// This can happen if the bond information is incorrect. Delete it and reconnect.
deleteBondInformation(gatt.getDevice());
connectGatt();
break;
case DISCOVER_SERVICES:
// This can also happen if the bond information is incorrect. Delete it and reconnect.
deleteBondInformation(gatt.getDevice());
connectGatt();
break;
case READ_CHARACTERISTIC:
// Disconnected while reading the characteristic. Probably just a link failure.
gatt.close();
mState = ConnectionState.FAILED;
State.notifyChanged();
break;
case FAILED:
case SUCCEEDED:
// Normal disconnection.
break;
}
break;
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status)
{
super.onServicesDiscovered(gatt, status);
// Services have been discovered. Now I try to read a characteristic that requires MitM protection.
// This triggers pairing and bonding.
BluetoothGattService nameService = gatt.getService(UUIDs.NAME_SERVICE);
if (nameService == null)
{
// Service not found.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
BluetoothGattCharacteristic characteristic = nameService.getCharacteristic(UUIDs.NAME_CHARACTERISTIC);
if (characteristic == null)
{
// Characteristic not found.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
// Read the characteristic.
gatt.readCharacteristic(characteristic);
mState = ConnectionState.READ_CHARACTERISTIC;
State.notifyChanged();
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
{
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS)
{
// Characteristic read. Check it is the right one.
if (!UUIDs.NAME_CHARACTERISTIC.equals(characteristic.getUuid()))
{
// Read the wrong characteristic. This shouldn't happen.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
// Get the name (the characteristic I am reading just contains the device name).
byte[] value = characteristic.getValue();
if (value == null)
{
// Hmm...
}
disconnectGatt();
mState = ConnectionState.SUCCEEDED;
State.notifyChanged();
// Success! Save it to the database or whatever...
}
else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION)
{
// This is where the tricky part comes
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE)
{
// Bonding required.
// The broadcast receiver should be called.
}
else
{
// ?
}
}
else if (status == GATT_AUTH_FAIL)
{
// This can happen because the user ignored the pairing request notification for too long.
// Or presumably if they put the wrong PIN in.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
else if (status == GATT_ERROR)
{
// I thought this happened if the bond information was wrong, but now I'm not sure.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
else
{
// That's weird.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
}
};
private final BroadcastReceiver mPairingRequestRecevier = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction()))
{
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if (type == BluetoothDevice.PAIRING_VARIANT_PIN)
{
device.setPin(Util.IntToPasskey(pinCode()));
abortBroadcast();
}
else
{
L.w("Unexpected pairing type: " + type);
}
}
}
};
public static void deleteBondInformation(BluetoothDevice device)
{
try
{
// FFS Google, just unhide the method.
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
}
catch (Exception e)
{
L.e(e.getMessage());
}
}
}
I also faced the same problem and after all the research, I figured out the below solution to pair to a BLE without any manual intervention.
(Tested and working!!!)
I am basically looking for a particular Bluetooth device (I know MAC address) and pair with it once found. The first thing to do is to create pair request using a broadcast receiver and handle the request as below.
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(broadCastReceiver,intentFilter);
You need to write the broadcastReceiver and handle it as below.
String BLE_PIN = "1234"
private BroadcastReceiver broadCastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action))
{
BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
bluetoothDevice.setPin(BLE_PIN.getBytes());
Log.e(TAG,"Auto-entering pin: " + BLE_PIN);
bluetoothDevice.createBond();
Log.e(TAG,"pin entered and request sent...");
}
}
};
Voila! You should be able to pair to Bluetooth device without ANY MANUAL INTERVENTION.
Hope this helps :-) Please make it right answer if it works for you.

Can I write a system property listener in android?

Having set a system property in android using the setprop command (through adb) is there a way to listen to this change in my own service?
I tried with SystemProperties.addChangeCallback and was not notified. Was there something that I missed?
You can create a method in your service which should fetch any Systemproperty and that method should call Looper.loop(); so that that loop will poll for SystemProperty time to time
This implementation may not be optimized way of doing this but it is used in Android 4.4.2, you can see here http://androidxref.com/4.4.2_r2/xref/frameworks/base/services/java/com/android/server/SystemServer.java
you can see at above link:
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
boolean disableTelephony = SystemProperties.getBoolean("config.disable_telephony", false);
boolean disableLocation = SystemProperties.getBoolean("config.disable_location", false);
boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
These boolean variables are being checked in initAndLoop() method with the help of Looper.loop(); here you can notify your other components on any change in even a single SystemProperty.
Another way is to create static callback and get call for any change in any of SystemProperty, see the master branch's code for SystemService here: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/SystemService.java
you can see in above link what following code is doing:
private static Object sPropertyLock = new Object();
static {
SystemProperties.addChangeCallback(new Runnable() {
#Override
public void run() {
synchronized (sPropertyLock) {
sPropertyLock.notifyAll();
}
}
});
}
/**
* Wait until given service has entered specific state.
*/
public static void waitForState(String service, State state, long timeoutMillis)
throws TimeoutException {
final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis;
while (true) {
synchronized (sPropertyLock) {
final State currentState = getState(service);
if (state.equals(currentState)) {
return;
}
if (SystemClock.elapsedRealtime() >= endMillis) {
throw new TimeoutException("Service " + service + " currently " + currentState
+ "; waited " + timeoutMillis + "ms for " + state);
}
try {
sPropertyLock.wait(timeoutMillis);
} catch (InterruptedException e) {
}
}
}
}
/**
* Wait until any of given services enters {#link State#STOPPED}.
*/
public static void waitForAnyStopped(String... services) {
while (true) {
synchronized (sPropertyLock) {
for (String service : services) {
if (State.STOPPED.equals(getState(service))) {
return;
}
}
try {
sPropertyLock.wait();
} catch (InterruptedException e) {
}
}
}
}
This information originates from Shridutt Kothari. Check this google post about listening to single SystemProperty changes
Too long for comments, so adding as an answer:
The setprop tool does not appear to fire change callbacks. In my read of the OS source, it simply sets a property value in a hashmap (see: https://cs.android.com/android/platform/superproject/+/master:system/libbase/properties.cpp;bpv=1;bpt=1;l=133?q=setprop).
For the callback to happen, someone needs to call do_report_sysprop_change (https://cs.android.com/android/platform/superproject/+/master:system/core/libutils/misc.cpp;bpv=1;bpt=1;l=102?q=syspropchange&ss=android%2Fplatform%2Fsuperproject&gsn=do_report_sysprop_change&gs=kythe%3A%2F%2Fandroid.googlesource.com%2Fplatform%2Fsuperproject%3Flang%3Dc%252B%252B%3Fpath%3Dsystem%2Fcore%2Flibutils%2Fmisc.cpp%23tC5_BHx-Z-jKUw_rRXWlL0wtVyVh15Oh60E0YnrdfSg&gs=kythe%3A%2F%2Fandroid.googlesource.com%2Fplatform%2Fsuperproject%3Flang%3Dc%252B%252B%3Fpath%3Dsystem%2Fcore%2Flibutils%2Fmisc.cpp%234FfZ9jgPIUEg7IKCGYGLCaQ4-cj6enFs8AeI7SIRLBs) and this is not done via setprop. I do see it invoked in a variety of places in the OS since invocation of the set prop callback is a method in the IBase interface implemented by a variety of services in Android.

Repeating JmDNS device search

I want to scan for Bonjour devices (_http._tcp.local.) every 5 seconds and get a arraylist with the found devices (the names, so strings). I need to do it in a service (and in a background thread).
Now I'm making every 5 seconds a new instance of JmDNS (JmDNS.create()) and that leaks memory ;).
I think there must be a better way to do it, but I don't know it... Who can help me?
try {
final JmDNS jm;
ArrayList<String> foundDevices = new ArrayList<String>();
jm = JmDNS.create();
jm.addServiceListener("_http._tcp.local.", listener = new ServiceListener() {
#Override
public void serviceAdded(ServiceEvent event) {
jm.requestServiceInfo(event.getType(), event.getName(), 1);
}
#Override
public void serviceRemoved(ServiceEvent event) {
}
#Override
public void serviceResolved(ServiceEvent event) {
JSONObject obj = null;
ServiceInfo info = event.getInfo();
//Log.e("TCLogging", "RAW: " + info);
String Name = info.getName();
foundDevices.add(Name);
} catch (Exception e) {
Log.e("TCLogging", "Error");
}
}
});
ServiceInfo serviceInfo = ServiceInfo.create("_http._tcp.", "TC_" + android.os.Build.MODEL, 0, "AndroidApp");
jm.registerService(serviceInfo);
} catch (Exception e) {
Log.e("TCLogging", e.toString());
}
You could just call JmDNS.list(String type) every N seconds, which would return the ServiceInfo for the services it found. This first call will take time (you can control that via an overload of list(String type, long timeout)), default seems to be 6secs.
Something I didn't know about JmDNS was that you get notified when a device is discovered or disappears in the network. I wanted to scan every N seconds to see what devices are in the network. But it's much easier (and less resource intensive) to just wait until you get notified of any device changes.
The accepted answer did work for me to achieve the scan every N seconds, but it's not the most ideal way to do it!

bindService() returns false but unbindService() needs to be called?

My app uses a service provided by another (of my) apps. I am using a bound service wit a Messenger to access and communicate with it (and as it is a different app, it is also a remote service).
When I call bindService with a proper intent, and the call returns false (as expected when the APK providing the service is not around), I assumed from the documentation and the example code, that I do not need to unbind the ServiceConnection. However, when doing so on my Galaxy Nexus (Jelly Bean) device, I get the well-known ServiceConnectionLeaked message when finishing the Activity.
I have salvaged that this by doing
if (!ctxt.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)) {
try {
ctxt.unbindService(serviceConnection);
} catch (Throwable t) {}
// Clean up
return;
}
// Store serviceConnection for future use
I am curious: Did I just miss something in the documentation and is it supposed to work this way? I added the try ... catch to make sure that even if this behavior is indeed different on other devices or Android versions my app is not (negatively) affected by it.
General speaking, a ServiceConnection is always allocated and registered by the framework, regardless of whether bindService() call return true or false. See bindService() implementation in android.app.ContextImpl:
public boolean bindService(Intent service, ServiceConnection conn, int flags, int userHandle) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
// A new ServiceDispatcher will be created and registered along with
// ServiceConnection in LoadedApk.mService for your application context.
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
try {
... ...
return res != 0;
} catch (RemoteException e) {
return false;
}
}
You should always unbind the service when you are done with it, as suggested by the official dev guide, as a good programming manner:
To disconnect from the service, call unbindService().
When your client is destroyed, it will unbind from the service, but you should always unbind when you're done interacting with the service or when your activity pauses so that the service can shutdown while its not being used. (Appropriate times to bind and unbind is discussed more below.)
The ServiceConnectionLeaked is raised when framework start performing a final cleanup (for instance, when your app is quit) and found there are unregistered ServiceConnection, and the framework will then try to unbind it for you. See removeContextRegistrations() implementation in android.app.LoadedApk:
public void removeContextRegistrations(Context context,
String who, String what) {
final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
... ...
//Slog.i(TAG, "Receiver registrations: " + mReceivers);
HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
mServices.remove(context);
if (smap != null) {
Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator();
while (it.hasNext()) {
LoadedApk.ServiceDispatcher sd = it.next();
ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
what + " " + who + " has leaked ServiceConnection "
+ sd.getServiceConnection() + " that was originally bound here");
leak.setStackTrace(sd.getLocation().getStackTrace());
Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
if (reportRegistrationLeaks) {
StrictMode.onServiceConnectionLeaked(leak);
}
try {
ActivityManagerNative.getDefault().unbindService(
sd.getIServiceConnection());
} catch (RemoteException e) {
// system crashed, nothing we can do
}
sd.doForget();
}
}
mUnboundServices.remove(context);
//Slog.i(TAG, "Service registrations: " + mServices);
}

Implementing JmDNS on Android/Multithreading

I am trying to get JmDNS to work in my android program. I am able to get it to discover the devices I want, but I do not fully understand how to get the information from JmDNS to the object that started the JmDNS task. Here is my code.
protected void browse() {
try {
jmdns = (JmDNSImpl) JmDNS.create();
jmdns.addServiceListener(type, listener = new ServiceListener() {
public void serviceResolved(ServiceEvent ev) {
}
public void serviceRemoved(ServiceEvent ev) {
}
public void serviceAdded(ServiceEvent event) {
DNSEntry addressEntry = jmdns.getCache().getDNSEntry(name, DNSRecordType.TYPE_A, DNSRecordClass.CLASS_ANY);
if (addressEntry instanceof DNSRecord) {
ServiceInfo cachedAddressInfo = ((DNSRecord) addressEntry).getServiceInfo(true);
if (cachedAddressInfo != null) {
for (Inet4Address address : cachedAddressInfo.getInet4Addresses()) {
//I need to get the address that is here back out of this listener to the main thread
}
}
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
The problem I am running into is that I have a service manager object that has a instance of a browser object that has the browse method in it. I am unable to get the service manager object access to the address variable. Because JmDNS spawns its own thread when it is created to run its tasks I have tried to use a handler and runnable to send messages with the variable in it but I cant seem to get it right. Can anyone help?
I think you want to just use the ServiceEvent event object passed into the service added method. It has all the info you need.
See this example from our open source application
http://code.google.com/p/tunesremote-plus/source/browse/trunk/src/org/tunesremote/LibraryActivity.java

Categories

Resources