import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-public class NetworkManager extends BroadcastReceiver
+import java.util.LinkedList;
+
+public class NetworkManager extends BroadcastReceiver implements Runnable
{
private final Context mContext;
- private boolean mRegistered;
+ private volatile boolean mRegistered;
+ private Thread mEventNotifier;
+ private LinkedList<Boolean> mEvents = new LinkedList<>();
public NetworkManager(Context context)
{
public void Register()
{
+ mEvents.clear();
+ mRegistered = true;
+ mEventNotifier = new Thread(this);
+ mEventNotifier.start();
mContext.registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
public void Unregister()
{
mContext.unregisterReceiver(this);
+ mRegistered = false;
+ synchronized (this)
+ {
+ notifyAll();
+ }
+ try
+ {
+ mEventNotifier.join();
+ mEventNotifier = null;
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
}
public boolean isConnected()
@Override
public void onReceive(Context context, Intent intent)
{
- networkChanged(!isConnected());
+ synchronized (this)
+ {
+ mEvents.addLast(isConnected());
+ notifyAll();
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ while (mRegistered)
+ {
+ boolean connected;
+
+ synchronized (this)
+ {
+ try
+ {
+ while (mRegistered && mEvents.isEmpty())
+ {
+ wait();
+ }
+ }
+ catch (InterruptedException ex)
+ {
+ break;
+ }
+ if (!mRegistered)
+ {
+ break;
+ }
+ connected = mEvents.removeFirst();
+ }
+ /* call the native parts without holding the lock */
+ networkChanged(!connected);
+ }
}
/**
METHOD(network_manager_t, remove_connectivity_cb, void,
private_network_manager_t *this, connectivity_cb_t cb)
{
+ bool unregister = FALSE;
+
this->mutex->lock(this->mutex);
if (this->connectivity_cb.cb == cb)
{
this->connectivity_cb.cb = NULL;
- unregister_network_manager(this);
+ unregister = TRUE;
}
this->mutex->unlock(this->mutex);
+ if (unregister)
+ { /* this call blocks until a possible networkChanged call returned so
+ * we can't hold the mutex */
+ unregister_network_manager(this);
+ }
}
METHOD(network_manager_t, is_connected, bool,