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.
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();
}