Search code examples
javaandroidmultithreadingbroadcastreceiver

Notify thread from receiver


This is my main thread:

Thread t = new Thread(){

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i = 0; i < passes.length; i++){
            progPass.setProgress(i);
            WifiConfiguration wc = new WifiConfiguration();
            wc.SSID = "\"" + dbw.getSsid() + "\"";
            wc.preSharedKey  = "\"" + passes[i] + "\"";
            wc.status = WifiConfiguration.Status.ENABLED;   
            wc = configureCapabs(wc, dbw.getCapability());
            int res = wifi.addNetwork(wc);
            //Toast.makeText(this, "add Network returned " + res , Toast.LENGTH_SHORT).show();
            boolean b = wifi.enableNetwork(res, true);        
            //Toast.makeText(this, "enableNetwork returned " + b , Toast.LENGTH_SHORT).show();
            if(!b) continue;
            try {
                synchronized(this){
                    this.wait();
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            boolean fin = wifi.getConnectionInfo() != null;
            if(fin) break;
        }
        progPass.dismiss();
        this.interrupt();
    }

};

It checks if wifi uses one of more common passwords. When the on the wait line it waits for notification from broadcast receiver, here is its code:

public class ConnectivityActionReceiver extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
        NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
        if(networkInfo.isConnected()) {
            // Wifi is connected
            Toast.makeText(context, "Wifi is connected: " + String.valueOf(networkInfo), Toast.LENGTH_SHORT).show();
            synchronized(this){
                notifyAll();
            }
        }
    } else if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
        NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
        if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && ! networkInfo.isConnected()) {
            // Wifi is disconnected
            Toast.makeText(context, "Wifi is disconnected: " + String.valueOf(networkInfo), Toast.LENGTH_SHORT).show();
        }
    } else if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)){
        int esr = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
        if(esr != 0){
            Toast.makeText(context, Integer.toString(esr), Toast.LENGTH_LONG).show();
            synchronized(this){
                notifyAll();
            }
        }

    }
}

Here it is registered Manifest:

 <receiver
        android:name="ConnectivityActionReceiver"
        android:enabled="true"
        android:label="ConnectivityActionReceiver" >
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            <action android:name="android.net.wifi.STATE_CHANGE" />
            <action android:name="android.net.wifi.supplicant.STATE_CHANGE" />
        </intent-filter>
    </receiver>

It has an instance in the same class as the thread:

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    IntentFilter filter = new IntentFilter();
    this.registerReceiver(car, filter);
}

The toast that should appear in onReceive method shows up, meaning that messages are received, but the notification doesn't reach the thread, which means it's stuck in waiting.


Solution

  • You're using two different objects for synchronization! One is the thread object, one is the ConnectivityActionReceiver. When you're using this:

     synchronized(this){
          this.wait();
     }
    

    you're locking on the current instance, hence you are locking on different instances in your case.

    The solution is to call wait/notify on a common, globally visible object:

    final Object signal = new Object();
    
    // in the waiting thread
    synchronized(signal) {
        signal.wait();
    }
    
    // in the signaling thread
    synchronized(signal) {
        signal.notifyAll();
    }