package eu.hgross.blaubot.android.wifi;
import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;
import eu.hgross.blaubot.core.BlaubotUUIDSet;
import eu.hgross.blaubot.core.IBlaubotAdapter;
import eu.hgross.blaubot.core.IBlaubotConnection;
import eu.hgross.blaubot.core.IBlaubotDevice;
import eu.hgross.blaubot.core.acceptor.ConnectionMetaDataDTO;
import eu.hgross.blaubot.core.acceptor.IBlaubotConnectionAcceptor;
import eu.hgross.blaubot.core.acceptor.IBlaubotIncomingConnectionListener;
import eu.hgross.blaubot.core.acceptor.IBlaubotListeningStateListener;
import eu.hgross.blaubot.core.acceptor.discovery.IBlaubotBeaconStore;
import eu.hgross.blaubot.ethernet.BlaubotEthernetAcceptor;
import eu.hgross.blaubot.util.Log;
/**
* An acceptor that creates an access point and then utilizes the EthernetAcceptor to accept the
* actual connections over socket connections.
*/
public class BlaubotWifiAcceptor implements IBlaubotConnectionAcceptor {
private static final String LOG_TAG = "BlaubotWifiAcceptor";
private final BlaubotWifiAdapter adapter;
private final IBlaubotDevice ownDevice;
private final BlaubotUUIDSet uuidSet;
private final ConnectivityManager connectivityManager;
private final WifiManager wifiManager;
/**
* The port to be used to accept connections
*/
private final int acceptorPort;
private IBlaubotBeaconStore beaconStore;
private IBlaubotIncomingConnectionListener acceptorListener;
private IBlaubotListeningStateListener listeningStateListener;
/**
* Lock for the start/stop listening methods.
*/
private final Object startStopMonitor = new Object();
private BlaubotEthernetAcceptor currentEthernetAcceptor;
public BlaubotWifiAcceptor(BlaubotWifiAdapter blaubotWifiAdapter, IBlaubotDevice ownDevice, BlaubotUUIDSet uuidSet, WifiManager wifiManager, ConnectivityManager connectivityManager, int acceptorPort) {
this.adapter = blaubotWifiAdapter;
this.ownDevice = ownDevice;
this.uuidSet = uuidSet;
this.wifiManager = wifiManager;
this.connectivityManager = connectivityManager;
this.acceptorPort = acceptorPort;
}
@Override
public void setBeaconStore(IBlaubotBeaconStore beaconStore) {
this.beaconStore = beaconStore;
}
@Override
public IBlaubotAdapter getAdapter() {
return adapter;
}
@Override
public void startListening() {
Log.d(LOG_TAG, "Starting to listen");
final CountDownLatch startLatch = new CountDownLatch(1);
synchronized (startStopMonitor) {
wifiManager.setWifiEnabled(false);
final WifiApUtil apUtil = WifiApUtil.createInstance(wifiManager);
final WifiConfiguration wifiApConfiguration = apUtil.getWifiApConfiguration();
apUtil.setWifiApEnabled(wifiApConfiguration, true);
final WifiInfo connectionInfo = wifiManager.getConnectionInfo();
final InetAddress ownIp = intToInetAddress(connectionInfo.getIpAddress());
Log.e(LOG_TAG, "myIp:" + ownIp);
final BlaubotEthernetAcceptor blaubotEthernetAcceptor = new BlaubotEthernetAcceptor(adapter, ownDevice, ownIp, acceptorPort);
blaubotEthernetAcceptor.setBeaconStore(beaconStore);
blaubotEthernetAcceptor.setAcceptorListener(new IBlaubotIncomingConnectionListener() {
@Override
public void onConnectionEstablished(IBlaubotConnection connection) {
acceptorListener.onConnectionEstablished(connection);
}
});
blaubotEthernetAcceptor.setListeningStateListener(new IBlaubotListeningStateListener() {
@Override
public void onListeningStarted(IBlaubotConnectionAcceptor connectionAcceptor) {
startLatch.countDown();
}
@Override
public void onListeningStopped(IBlaubotConnectionAcceptor connectionAcceptor) {
}
});
blaubotEthernetAcceptor.startListening();
this.currentEthernetAcceptor = blaubotEthernetAcceptor;
}
try {
startLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
listeningStateListener.onListeningStarted(this);
Log.d(LOG_TAG, "Started listening");
}
@Override
public void stopListening() {
Log.d(LOG_TAG, "Stopping to listen");
final CountDownLatch stopLatch = new CountDownLatch(1);
synchronized (startStopMonitor) {
WifiApUtil apUtil = WifiApUtil.createInstance(wifiManager);
BlaubotEthernetAcceptor acceptor = this.currentEthernetAcceptor;
if(acceptor != null) {
this.currentEthernetAcceptor.setListeningStateListener(new IBlaubotListeningStateListener() {
@Override
public void onListeningStarted(IBlaubotConnectionAcceptor connectionAcceptor) {
}
@Override
public void onListeningStopped(IBlaubotConnectionAcceptor connectionAcceptor) {
stopLatch.countDown();
}
});
this.currentEthernetAcceptor.stopListening();
} else {
stopLatch.countDown();
}
// Disable AP mode
if(apUtil.isWifiApEnabled()) {
apUtil.setWifiApEnabled(apUtil.getWifiApConfiguration(), false);
}
}
try {
stopLatch.await();
this.currentEthernetAcceptor = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
listeningStateListener.onListeningStopped(this);
Log.d(LOG_TAG, "Stopped listening");
}
@Override
public boolean isStarted() {
return false;
}
@Override
public void setListeningStateListener(IBlaubotListeningStateListener stateListener) {
this.listeningStateListener = stateListener;
}
@Override
public void setAcceptorListener(IBlaubotIncomingConnectionListener acceptorListener) {
this.acceptorListener = acceptorListener;
}
@Override
public ConnectionMetaDataDTO getConnectionMetaData() {
final WifiApUtil apUtil = WifiApUtil.createInstance(wifiManager);
final WifiConfiguration wifiApConfiguration = apUtil.getWifiApConfiguration();
final String ssid = wifiApConfiguration.SSID;
final String psk = wifiApConfiguration.preSharedKey;
final String ipAddress = intToInetAddress(wifiManager.getConnectionInfo().getIpAddress()).getHostAddress();
final String macAddress = wifiManager.getConnectionInfo().getMacAddress();
final ConnectionMetaDataDTO metaDataDTO = new WifiConnectionMetaDataDTO(ssid, psk, ipAddress, macAddress, acceptorPort);
return metaDataDTO;
}
/**
* Convert a IPv4 address from an integer to an InetAddress.
* @param hostAddress an int corresponding to the IPv4 address in network byte order
*/
private static InetAddress intToInetAddress(int hostAddress) {
byte[] addressBytes = { (byte)(0xff & hostAddress),
(byte)(0xff & (hostAddress >> 8)),
(byte)(0xff & (hostAddress >> 16)),
(byte)(0xff & (hostAddress >> 24)) };
try {
return InetAddress.getByAddress(addressBytes);
} catch (UnknownHostException e) {
throw new AssertionError();
}
}
}