From bbebf46fddcfe37b03332988ce9ca863661815ef Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Thu, 20 Jan 2022 16:28:53 +0000 Subject: [PATCH] Try to provide hotspot and discover peers at the same time. --- .../briarproject/publicmesh/MainActivity.java | 34 +- .../briarproject/publicmesh/util/IoUtils.java | 22 + .../wifidirect/WifiDirectService.java | 6 - .../wifidirect/WifiDirectServiceImpl.java | 603 +----------------- app/src/main/res/layout/activity_main.xml | 14 +- 5 files changed, 36 insertions(+), 643 deletions(-) diff --git a/app/src/main/java/org/briarproject/publicmesh/MainActivity.java b/app/src/main/java/org/briarproject/publicmesh/MainActivity.java index 32256ed..38903fd 100644 --- a/app/src/main/java/org/briarproject/publicmesh/MainActivity.java +++ b/app/src/main/java/org/briarproject/publicmesh/MainActivity.java @@ -59,49 +59,23 @@ public class MainActivity extends AppCompatActivity { ((MeshApplication) getApplication()).getAppComponent().inject(this); setContentView(R.layout.activity_main); Button hotspotButton = findViewById(R.id.hotspotButton); - Button discoveryButton = findViewById(R.id.discoveryButton); LiveData<Status> hotspotStatus = wifiDirectService.getHotspotStatus(); - LiveData<Status> discoveryStatus = wifiDirectService.getDiscoveryStatus(); hotspotStatus.observe(this, status -> { if (status == STARTING) { hotspotButton.setText(R.string.start_hotspot); hotspotButton.setEnabled(false); - discoveryButton.setEnabled(false); } else if (status == STARTED) { hotspotButton.setText(R.string.stop_hotspot); hotspotButton.setEnabled(true); - discoveryButton.setEnabled(false); } else if (status == STOPPING) { hotspotButton.setText(R.string.stop_hotspot); hotspotButton.setEnabled(false); - discoveryButton.setEnabled(false); } else if (status == STOPPED) { hotspotButton.setText(R.string.start_hotspot); - hotspotButton.setEnabled(discoveryStatus.getValue() == STOPPED); - discoveryButton.setEnabled(discoveryStatus.getValue() == STOPPED); - } - }); - discoveryStatus.observe(this, status -> { - if (status == STARTING) { - discoveryButton.setText(R.string.start_discovery); - discoveryButton.setEnabled(false); - hotspotButton.setEnabled(false); - } else if (status == STARTED) { - discoveryButton.setText(R.string.stop_discovery); - discoveryButton.setEnabled(true); - hotspotButton.setEnabled(false); - } else if (status == STOPPING) { - discoveryButton.setText(R.string.stop_discovery); - discoveryButton.setEnabled(false); - hotspotButton.setEnabled(false); - } else if (status == STOPPED) { - discoveryButton.setText(R.string.start_discovery); - discoveryButton.setEnabled(hotspotStatus.getValue() == STOPPED); - hotspotButton.setEnabled(hotspotStatus.getValue() == STOPPED); + hotspotButton.setEnabled(true); } }); hotspotButton.setOnClickListener(v -> onHotspotButtonClicked()); - discoveryButton.setOnClickListener(v -> onDiscoveryButtonClicked()); } @Override @@ -173,10 +147,4 @@ public class MainActivity extends AppCompatActivity { if (status == STARTED) wifiDirectService.stopHotspot(); else if (status == STOPPED) wifiDirectService.startHotspot(); } - - private void onDiscoveryButtonClicked() { - Status status = wifiDirectService.getDiscoveryStatus().getValue(); - if (status == STARTED) wifiDirectService.stopDiscovery(); - else if (status == STOPPED) wifiDirectService.startDiscovery(); - } } \ No newline at end of file diff --git a/app/src/main/java/org/briarproject/publicmesh/util/IoUtils.java b/app/src/main/java/org/briarproject/publicmesh/util/IoUtils.java index 37c0619..169c4b6 100644 --- a/app/src/main/java/org/briarproject/publicmesh/util/IoUtils.java +++ b/app/src/main/java/org/briarproject/publicmesh/util/IoUtils.java @@ -5,18 +5,28 @@ import org.briarproject.publicmesh.nullsafety.NotNullByDefault; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; +import static java.util.Collections.emptyList; +import static java.util.Collections.list; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; import static org.briarproject.publicmesh.util.LogUtils.logException; @NotNullByDefault public class IoUtils { + private static final Logger LOG = getLogger(IoUtils.class.getName()); + public static void tryToClose(@Nullable Socket s, Logger logger, Level level) { try { @@ -63,4 +73,16 @@ public class IoUtils { ipBytes[3] = (byte) ((ip >> 24) & 0xFF); return ipBytes; } + + public static List<NetworkInterface> getNetworkInterfaces() { + try { + Enumeration<NetworkInterface> ifaces = + NetworkInterface.getNetworkInterfaces(); + // Despite what the docs say, the return value can be null + return ifaces == null ? emptyList() : list(ifaces); + } catch (SocketException e) { + logException(LOG, WARNING, e); + return emptyList(); + } + } } diff --git a/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectService.java b/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectService.java index 396bc1e..9b9319c 100644 --- a/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectService.java +++ b/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectService.java @@ -10,12 +10,6 @@ public interface WifiDirectService { LiveData<Status> getHotspotStatus(); - void startDiscovery(); - - void stopDiscovery(); - - LiveData<Status> getDiscoveryStatus(); - enum Status { STARTING, STARTED, diff --git a/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectServiceImpl.java b/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectServiceImpl.java index bd3ea5b..f22a33b 100644 --- a/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectServiceImpl.java +++ b/app/src/main/java/org/briarproject/publicmesh/wifidirect/WifiDirectServiceImpl.java @@ -6,57 +6,29 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.DhcpInfo; -import android.net.MacAddress; -import android.net.Network; -import android.net.NetworkRequest; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; -import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pManager; import android.net.wifi.p2p.WifiP2pManager.ActionListener; import android.net.wifi.p2p.WifiP2pManager.Channel; -import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener; -import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener; -import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener; import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener; -import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo; -import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest; import android.os.Handler; import org.briarproject.publicmesh.R; import org.briarproject.publicmesh.lifecycle.Service; import org.briarproject.publicmesh.nullsafety.NotNullByDefault; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; -import java.util.Map; -import java.util.Random; -import java.util.TreeMap; import java.util.logging.Logger; import javax.inject.Inject; -import javax.net.SocketFactory; import androidx.annotation.Nullable; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Context.WIFI_P2P_SERVICE; import static android.content.Context.WIFI_SERVICE; -import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.wifi.WifiManager.WIFI_MODE_FULL; import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF; import static android.net.wifi.p2p.WifiP2pManager.BUSY; @@ -66,13 +38,7 @@ import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION; import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION; import static android.os.Build.VERSION.SDK_INT; import static java.util.Objects.requireNonNull; -import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; -import static org.briarproject.publicmesh.util.IoUtils.getInputStream; -import static org.briarproject.publicmesh.util.IoUtils.getOutputStream; -import static org.briarproject.publicmesh.util.IoUtils.ipAddressIntToBytes; -import static org.briarproject.publicmesh.util.IoUtils.tryToClose; -import static org.briarproject.publicmesh.util.StringUtils.getRandomString; import static org.briarproject.publicmesh.wifidirect.WifiDirectService.Status.STARTED; import static org.briarproject.publicmesh.wifidirect.WifiDirectService.Status.STARTING; import static org.briarproject.publicmesh.wifidirect.WifiDirectService.Status.STOPPED; @@ -81,15 +47,7 @@ import static org.briarproject.publicmesh.wifidirect.WifiDirectService.Status.ST @NotNullByDefault class WifiDirectServiceImpl implements WifiDirectService, Service { - private static final String SERVICE_TYPE = "_mesh._tcp"; - private static final String KEY_NETWORK_NAME = "ssid"; - private static final String KEY_PASSPHRASE = "pass"; - private static final int PORT = 55555; - private static final int MAX_GROUP_INFO_ATTEMPTS = 5; - private static final int MAX_CONNECTION_INFO_ATTEMPTS = 5; - private static final int MAX_WIFI_CONNECTION_ATTEMPTS = 5; - private static final int MAX_SOCKET_CONNECTION_ATTEMPTS = 5; private static final Logger LOG = getLogger(WifiDirectServiceImpl.class.getName()); @@ -100,29 +58,13 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { private final WifiManager wifiManager; @Nullable private final WifiP2pManager wifiP2pManager; - private final ConnectivityManager connectivityManager; private final MutableLiveData<Status> hotspotStatus = new MutableLiveData<>(STOPPED); - private final MutableLiveData<Status> discoveryStatus = new MutableLiveData<>(STOPPED); private final WifiDirectBroadcastReceiver receiver = new WifiDirectBroadcastReceiver(); - private final String instanceName = getRandomString(6); @Nullable private WifiLock wifiLock; @Nullable private Channel channel; - private boolean connectionInProgress = false, connectedToPeer = false; - @Nullable - private WifiP2pDnsSdServiceInfo serviceInfo; - @Nullable - private WifiP2pDnsSdServiceRequest serviceRequest; - private int networkId = -1; - @Nullable - private ServerSocket serverSocket; - @Nullable - private NetworkCallback networkCallback; - private SocketFactory socketFactory = SocketFactory.getDefault(); - @Nullable - private SenderThread senderThread; @Inject WifiDirectServiceImpl(Application app) { @@ -131,8 +73,6 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { handler = new Handler(app.getMainLooper()); wifiManager = (WifiManager) app.getSystemService(WIFI_SERVICE); wifiP2pManager = (WifiP2pManager) app.getSystemService(WIFI_P2P_SERVICE); - connectivityManager = (ConnectivityManager) - requireNonNull(app.getSystemService(CONNECTIVITY_SERVICE)); } @Override @@ -141,10 +81,6 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { LOG.warning("Hotspot already started"); return; } - if (discoveryStatus.getValue() != STOPPED) { - LOG.warning("Service discovery in progress"); - return; - } if (wifiP2pManager == null) { LOG.info("Wifi Direct is not supported"); return; @@ -190,10 +126,6 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { LOG.warning("Hotspot is not running"); return; } - if (discoveryStatus.getValue() != STOPPED) { - LOG.warning("Service discovery in progress"); - return; - } hotspotStatus.postValue(STOPPING); requireNonNull(wifiP2pManager).removeGroup(requireNonNull(channel), new ActionListener() { @@ -236,9 +168,10 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { releaseHotspot(); } } else { + hotspotStatus.postValue(STARTED); LOG.info("SSID: " + group.getNetworkName()); LOG.info("Passphrase: " + group.getPassphrase()); - addService(group.getNetworkName(), group.getPassphrase()); + startDiscovery(); } }; try { @@ -249,46 +182,7 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { } } - private void addService(String networkName, String passphrase) { - Channel channel = this.channel; - if (channel == null) return; - try { - serverSocket = new ServerSocket(PORT); - LOG.info("Opened server socket " + serverSocket.getLocalSocketAddress()); - new ServerThread(serverSocket).start(); - } catch (IOException e) { - LOG.info("Failed to open server socket: " + e); - releaseHotspot(); - return; - } - Map<String, String> record = new TreeMap<>(); - record.put(KEY_NETWORK_NAME, networkName); - record.put(KEY_PASSPHRASE, passphrase); - serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(instanceName, SERVICE_TYPE, record); - ActionListener listener = new ActionListener() { - @Override - public void onSuccess() { - hotspotStatus.postValue(STARTED); - LOG.info("Added local service"); - } - - @Override - public void onFailure(int reason) { - LOG.info("Failed to add local service: " + reason); - releaseHotspot(); - } - }; - try { - requireNonNull(wifiP2pManager).addLocalService(channel, serviceInfo, listener); - } catch (SecurityException e) { - LOG.info("Failed to add local service: " + e); - releaseHotspot(); - } - } - private void releaseHotspot() { - closeServerSocket(); - removeService(); if (SDK_INT >= 27) requireNonNull(channel).close(); channel = null; releaseLock(); @@ -296,34 +190,6 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { LOG.info("Released hotspot"); } - private void closeServerSocket() { - if (serverSocket == null) return; - tryToClose(serverSocket, LOG, INFO); - serverSocket = null; - } - - private void removeService() { - if (serviceInfo == null) return; - ActionListener listener = new ActionListener() { - @Override - public void onSuccess() { - LOG.info("Removed local service"); - } - - @Override - public void onFailure(int reason) { - LOG.info("Failed to remove local service: " + reason); - } - }; - try { - requireNonNull(wifiP2pManager).removeLocalService(requireNonNull(channel), serviceInfo, - listener); - } catch (SecurityException e) { - LOG.info("Failed to remove local service: " + e); - } - serviceInfo = null; - } - private void releaseLock() { if (wifiLock != null) { wifiLock.release(); @@ -331,131 +197,34 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { } } - @Override - public void startDiscovery() { - if (discoveryStatus.getValue() != STOPPED) { - LOG.warning("Service discovery already started"); - return; - } - if (hotspotStatus.getValue() != STOPPED) { - LOG.warning("Hotspot in use"); - return; - } - if (wifiP2pManager == null) { - LOG.info("Wifi Direct is not supported"); - return; - } - channel = wifiP2pManager.initialize(app, app.getMainLooper(), null); - if (channel == null) { - LOG.info("Failed to initialize Wifi Direct"); - return; - } - discoveryStatus.postValue(STARTING); - acquireLock(); - DnsSdServiceResponseListener serviceListener = (instanceName, serviceType, device) -> { - LOG.info("Discovered service"); - LOG.info("Instance name: " + instanceName); - LOG.info("Service type: " + serviceType); - LOG.info("Device name: " + device.deviceName); - LOG.info("Device address: " + device.deviceAddress); - }; - DnsSdTxtRecordListener txtListener = (domain, record, device) -> { - LOG.info("Discovered TXT record"); - LOG.info("Domain: " + domain); - LOG.info("Record: " + record); - LOG.info("Device name: " + device.deviceName); - LOG.info("Device address: " + device.deviceAddress); - String networkName = record.get(KEY_NETWORK_NAME); - String passphrase = record.get(KEY_PASSPHRASE); - if (networkName != null && passphrase != null) { - connectToPeer(device, networkName, passphrase); - } - }; - try { - wifiP2pManager.setDnsSdResponseListeners(channel, serviceListener, txtListener); - LOG.info("Set DNS SD response listeners"); - addServiceRequest(); - } catch (SecurityException e) { - LOG.info("Failed to set DNS SD response listeners: " + e); - releaseDiscovery(); - } - } - - private void addServiceRequest() { - serviceRequest = WifiP2pDnsSdServiceRequest.newInstance(); - ActionListener listener = new ActionListener() { - @Override - public void onSuccess() { - LOG.info("Added service request"); - discoverServices(); - } - - @Override - public void onFailure(int reason) { - LOG.info("Failed to add service request: " + reason); - releaseDiscovery(); - } - }; - try { - requireNonNull(wifiP2pManager).addServiceRequest(requireNonNull(channel), - serviceRequest, listener); - } catch (SecurityException e) { - LOG.info("Failed to add service request: " + e); - releaseDiscovery(); - } - } - - private void discoverServices() { - Channel channel = this.channel; - if (channel == null) return; + private void startDiscovery() { ActionListener listener = new ActionListener() { @Override public void onSuccess() { - discoveryStatus.postValue(STARTED); - LOG.info("Started service discovery"); + LOG.info("Started peer discovery"); } @Override public void onFailure(int reason) { if (reason == BUSY) { - discoveryStatus.postValue(STARTED); - LOG.info("Status BUSY - service discovery already running?"); + LOG.info("Peer discovery already running?"); } else { - LOG.info("Failed to start service discovery: " + reason); - releaseDiscovery(); + LOG.info("Failed to start peer discovery: " + reason); + releaseHotspot(); } } }; try { - requireNonNull(wifiP2pManager).discoverServices(channel, listener); + requireNonNull(wifiP2pManager).discoverPeers(channel, listener); } catch (SecurityException e) { - LOG.info("Failed to start service discovery: " + e); - releaseDiscovery(); - } - } - - @Override - public void stopDiscovery() { - if (discoveryStatus.getValue() != STARTED) { - LOG.warning("Discovery is not running"); - return; - } - if (hotspotStatus.getValue() != STOPPED) { - LOG.warning("Hotspot is running"); - return; + LOG.info("Failed to start peer discovery: " + e); + releaseHotspot(); } - discoveryStatus.postValue(STOPPING); - releaseDiscovery(); - } - - @Override - public LiveData<Status> getDiscoveryStatus() { - return discoveryStatus; } private void requestPeers() { - if (discoveryStatus.getValue() != STARTED) return; + if (hotspotStatus.getValue() != STARTED) return; try { requireNonNull(wifiP2pManager).requestPeers(requireNonNull(channel), devices -> { if (devices == null || devices.getDeviceList() == null) { @@ -473,245 +242,6 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { } } - private void connectToPeer(WifiP2pDevice device, String networkName, String passphrase) { - Channel channel = this.channel; - if (channel == null || connectionInProgress || connectedToPeer) return; - // If we're using wifi (not WFD) on API 21+ we need the network's socket factory - if (SDK_INT >= 21 && SDK_INT < 29) { - NetworkRequest networkRequest = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_WIFI) - .removeCapability(NET_CAPABILITY_INTERNET) - .build(); - networkCallback = new NetworkCallback() { - @Override - public void onAvailable(Network network) { - LOG.info("Network is available, setting socket factory"); - socketFactory = network.getSocketFactory(); - } - }; - connectivityManager.registerNetworkCallback(networkRequest, networkCallback); - } - if (SDK_INT >= 29) { - LOG.info("Connecting to peer " + device.deviceName); - connectionInProgress = true; - WifiP2pConfig config = new WifiP2pConfig.Builder() - .setDeviceAddress(MacAddress.fromString(device.deviceAddress)) - .setNetworkName(networkName) - .setPassphrase(passphrase) - .build(); - ActionListener listener = new ActionListener() { - @Override - public void onSuccess() { - LOG.info("Connected to peer " + device.deviceName); - connectedToPeer = true; - connectionInProgress = false; - requestConnectionInfo(1); - } - - @Override - public void onFailure(int reason) { - LOG.info("Failed to connect to peer " + device.deviceName + ": " + reason); - connectionInProgress = false; - } - }; - try { - requireNonNull(wifiP2pManager).connect(channel, config, listener); - } catch (SecurityException e) { - LOG.info("Failed to connect to peer " + device.deviceName + ": " + e); - } - } else { - WifiConfiguration config = new WifiConfiguration(); - config.SSID = "\"" + networkName + "\""; - config.preSharedKey = "\"" + passphrase + "\""; - try { - networkId = requireNonNull(wifiManager).addNetwork(config); - if (networkId == -1) { - LOG.info("Failed to add wifi network"); - } else { - LOG.info("Added wifi network"); - connectToNetwork(networkName, networkId, 1); - } - } catch (SecurityException e) { - LOG.info("Failed to add wifi network: " + e); - } - } - } - - private void requestConnectionInfo(int attempt) { - Channel channel = this.channel; - if (channel == null) return; - ConnectionInfoListener listener = info -> { - if (info.groupOwnerAddress == null) { - // On some devices we need to wait for the connection info to become available - if (attempt < MAX_CONNECTION_INFO_ATTEMPTS) { - handler.postDelayed(() -> requestConnectionInfo(attempt + 1), 1000); - } else { - LOG.info("Failed to get group owner's address"); - releaseDiscovery(); - } - } else { - LOG.info("Server address " + info.groupOwnerAddress); - senderThread = new SenderThread(info.groupOwnerAddress); - senderThread.start(); - } - }; - try { - requireNonNull(wifiP2pManager).requestConnectionInfo(channel, listener); - LOG.info("Requested connection info"); - } catch (SecurityException e) { - LOG.info("Failed to request connection info: " + e); - releaseDiscovery(); - } - } - - private void connectToNetwork(String networkName, int networkId, int attempt) { - String ssid = "\"" + networkName + "\""; - try { - WifiInfo info = requireNonNull(wifiManager).getConnectionInfo(); - if (info == null) { - LOG.info("Not connected to a wifi network"); - } else if (!ssid.equals(info.getSSID())) { - LOG.info("Connected to unwanted wifi network " + info.getSSID()); - // If we want to allow the device to remain connected to another network, - // we should return here and there's no need to call disconnect() below - } else { - DhcpInfo dhcpInfo = wifiManager.getDhcpInfo(); - if (dhcpInfo == null) { - LOG.info("No DHCP info"); - // Fall through - } else { - LOG.info("Successfully connected to wifi network " + networkName); - byte[] ipBytes = ipAddressIntToBytes(dhcpInfo.gateway); - try { - InetAddress serverAddress = InetAddress.getByAddress(ipBytes); - LOG.info("Server address " + serverAddress); - senderThread = new SenderThread(serverAddress); - senderThread.start(); - return; - } catch (UnknownHostException e) { - throw new AssertionError(e); - } - } - } - if (attempt > MAX_WIFI_CONNECTION_ATTEMPTS) return; - LOG.info("Connecting to " + networkName + ", attempt " + attempt); - if (wifiManager.disconnect()) LOG.info("Disconnected from wifi network"); - else LOG.info("Failed to disconnect from wifi network"); - if (wifiManager.enableNetwork(networkId, true)) LOG.info("Enabled wifi network"); - else LOG.info("Failed to enable wifi network"); - if (wifiManager.reconnect()) LOG.info("Reconnected to wifi network"); - else LOG.info("Failed to reconnect to wifi network"); - if (wifiManager.reassociate()) LOG.info("Reassociated to wifi network"); - else LOG.info("Failed to reassociate to wifi network"); - handler.postDelayed(() -> connectToNetwork(networkName, networkId, attempt + 1), 5000); - } catch (SecurityException e) { - LOG.info("Failed to connect to wifi network: " + e); - } - } - - private void releaseDiscovery() { - cancelConnection(); - removeGroup(); - removeServiceRequest(); - if (SDK_INT >= 27) requireNonNull(channel).close(); - channel = null; - removeNetwork(); - unregisterNetworkCallback(); - interruptSenderThread(); - releaseLock(); - discoveryStatus.postValue(STOPPED); - LOG.info("Released service discovery"); - } - - private void cancelConnection() { - if (!connectionInProgress) return; - ActionListener listener = new ActionListener() { - @Override - public void onSuccess() { - LOG.info("Cancelled connection"); - } - - @Override - public void onFailure(int reason) { - LOG.info("Failed to cancel connection: " + reason); - } - }; - try { - requireNonNull(wifiP2pManager).cancelConnect(requireNonNull(channel), listener); - } catch (SecurityException e) { - LOG.info("Failed to cancel connection: " + e); - } - connectionInProgress = false; - } - - private void removeGroup() { - if (!connectedToPeer) return; - ActionListener listener = new ActionListener() { - @Override - public void onSuccess() { - LOG.info("Removed group"); - } - - @Override - public void onFailure(int reason) { - LOG.info("Failed to remove group: " + reason); - } - }; - try { - requireNonNull(wifiP2pManager).removeGroup(requireNonNull(channel), listener); - } catch (SecurityException e) { - LOG.info("Failed to remove group: " + e); - } - connectedToPeer = false; - } - - private void removeServiceRequest() { - if (serviceRequest == null) return; - ActionListener listener = new ActionListener() { - @Override - public void onSuccess() { - LOG.info("Removed service request"); - } - - @Override - public void onFailure(int reason) { - LOG.info("Failed to remove service request: " + reason); - } - }; - try { - requireNonNull(wifiP2pManager).removeServiceRequest(requireNonNull(channel), - serviceRequest, listener); - } catch (SecurityException e) { - LOG.info("Failed to remove service request: " + e); - } - serviceRequest = null; - } - - private void removeNetwork() { - if (networkId == -1) return; - try { - if (requireNonNull(wifiManager).removeNetwork(networkId)) LOG.info("Removed network"); - else LOG.info("Failed to remove network"); - } catch (SecurityException e) { - LOG.info("Failed to remove network: " + e); - } - networkId = -1; - } - - private void unregisterNetworkCallback() { - if (SDK_INT < 21 || networkCallback == null) return; - requireNonNull(connectivityManager).unregisterNetworkCallback(networkCallback); - LOG.info("Unregistered network callback"); - networkCallback = null; - } - - private void interruptSenderThread() { - if (senderThread == null) return; - senderThread.interrupt(); - LOG.info("Interrupted sender thread"); - senderThread = null; - } - @Override public void start() { IntentFilter filter = new IntentFilter(); @@ -726,7 +256,6 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { public void stop() { app.unregisterReceiver(receiver); if (hotspotStatus.getValue() == STARTED) stopHotspot(); - if (discoveryStatus.getValue() == STARTED) stopDiscovery(); } private class WifiDirectBroadcastReceiver extends BroadcastReceiver { @@ -738,114 +267,4 @@ class WifiDirectServiceImpl implements WifiDirectService, Service { if (WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) requestPeers(); } } - - private static class ServerThread extends Thread { - - private final ServerSocket serverSocket; - - private ServerThread(ServerSocket serverSocket) { - this.serverSocket = serverSocket; - } - - @Override - public void run() { - try { - // We'll break out of the loop when the server socket is closed - //noinspection InfiniteLoopStatement - while (true) { - Socket s = serverSocket.accept(); - LOG.info("Incoming connection from " + s.getRemoteSocketAddress()); - new ReceiverThread(s).start(); - } - } catch (IOException e) { - LOG.info("Server thread exiting: " + e); - } - } - } - - private static class ReceiverThread extends Thread { - - private final Socket socket; - - private ReceiverThread(Socket socket) { - this.socket = socket; - } - - @Override - public void run() { - try { - InputStream in = getInputStream(socket); - OutputStream out = getOutputStream(socket); - byte[] buf = new byte[4096]; - while (true) { - int read = in.read(buf); - if (read == -1) { - LOG.info("Receiver thread exiting: EOF"); - return; - } - LOG.info("Received " + read + " bytes"); - out.write(buf, 0, read); - LOG.info("Sent " + read + " bytes"); - } - } catch (IOException e) { - LOG.info("Receiver thread exiting: " + e); - tryToClose(socket, LOG, INFO); - } - } - } - - private class SenderThread extends Thread { - - private final InetAddress serverAddress; - - private SenderThread(InetAddress serverAddress) { - this.serverAddress = serverAddress; - } - - @Override - public void run() { - Socket socket = null; - for (int i = 0; i < MAX_SOCKET_CONNECTION_ATTEMPTS; i++) { - try { - LOG.info("Connecting to " + serverAddress); - socket = socketFactory.createSocket(serverAddress, PORT); - LOG.info("Connected to " + serverAddress); - break; - } catch (IOException e) { - LOG.info("Failed to connect to " + serverAddress + ": " + e); - } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - LOG.info("Sender thread interrupted"); - return; - } - } - if (socket == null) return; - byte[] buf = new byte[4096]; - Random random = new Random(); - try { - InputStream in = getInputStream(socket); - OutputStream out = getOutputStream(socket); - // We'll break out of the loop when the sender thread is interrupted - while (true) { - int bytesToSend = 1 + random.nextInt(99); - out.write(buf, 0, bytesToSend); - LOG.info("Sent " + bytesToSend + " bytes"); - int read = in.read(buf); - if (read == -1) { - LOG.info("Sender thread exiting: EOF"); - tryToClose(socket, LOG, INFO); - return; - } - LOG.info("Received " + read + " bytes"); - //noinspection BusyWait - Thread.sleep(1000); - } - } catch (IOException | InterruptedException e) { - LOG.info("Sender thread exiting: " + e); - tryToClose(socket, LOG, INFO); - } - } - } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 24bf0c5..88d5a52 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,20 +11,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/start_hotspot" - app:layout_constraintVertical_chainStyle="packed" - app:layout_constraintBottom_toTopOf="@id/discoveryButton" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - <Button - android:id="@+id/discoveryButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/start_discovery" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" - app:layout_constraintTop_toBottomOf="@id/hotspotButton" /> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file -- GitLab