rework WifiStateChangeService to support hotspots (aka WiFi AP on device)

When a device is setup as a WiFi Access Point aka "hotspot", the standard
API for getting the WiFi settings returns nothing.  We have to use a
separate API to get the IP address of the WiFi AP.  As far as I could tell,
there is no public API for getting the SSID/BSSID of the WiFi AP, so for
now that is left blank.  That means the wifi screen in swap is confusing
because it will say it is not attached when the device is a hotspot

@mvdan's https://github.com/mvdan/libaccesspoint should help there

#193 https://gitlab.com/fdroid/fdroidclient/issues/193
This commit is contained in:
Hans-Christoph Steiner 2015-05-09 13:39:03 -04:00
parent edb3564e29
commit 96b7c35a2a

View File

@ -3,6 +3,7 @@ package org.fdroid.fdroid.net;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
@ -17,7 +18,12 @@ import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.LocalRepoKeyStore;
import org.fdroid.fdroid.localrepo.LocalRepoManager;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.cert.Certificate;
import java.util.Enumeration;
import java.util.Locale;
public class WifiStateChangeService extends Service {
@ -27,36 +33,29 @@ public class WifiStateChangeService extends Service {
private WifiManager wifiManager;
private static WaitForWifiAsyncTask asyncTask;
private int wifiState;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
FDroidApp.initWifiSettings();
NetworkInfo ni = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
if (ni == null) {
// this app just started up, NetworkInfo is only passed via WifiStateChangeReceiver
int wifiState = wifiManager.getWifiState();
if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
startAsyncTask();
}
} else if (ni.isConnected()) {
Log.i(TAG, "ni.isConnected()");
startAsyncTask();
} else {
Log.i("WifiStateChangeReceiver", "ni != null && !ni.isConnected()");
FDroidApp.initWifiSettings();
}
return START_NOT_STICKY;
}
private void startAsyncTask() {
Log.i(TAG, "startAsyncTask");
wifiState = wifiManager.getWifiState();
if (ni == null || ni.isConnected()) {
/* started on app start or from WifiStateChangeReceiver,
NetworkInfo is only passed via WifiStateChangeReceiver */
Log.i(TAG, "ni == " + ni + " wifiState == " + printWifiState(wifiState));
if (wifiState == WifiManager.WIFI_STATE_ENABLED
|| wifiState == WifiManager.WIFI_STATE_UNKNOWN) { // might be hotspot
if (asyncTask != null) {
Log.i(TAG, "asyncTask.cancel");
asyncTask.cancel(true);
}
asyncTask = new WaitForWifiAsyncTask();
asyncTask.execute();
}
}
return START_NOT_STICKY;
}
public class WaitForWifiAsyncTask extends AsyncTask<Void, Void, Void> {
private static final String TAG = "WaitForWifiAsyncTask";
@ -64,40 +63,37 @@ public class WifiStateChangeService extends Service {
@Override
protected Void doInBackground(Void... params) {
try {
while (!wifiManager.isWifiEnabled()) {
FDroidApp.initWifiSettings();
if (isCancelled())
WifiInfo wifiInfo = null;
wifiState = wifiManager.getWifiState();
while (FDroidApp.ipAddressString == null) {
if (isCancelled()) // can be canceled by a change via WifiStateChangeReceiver
return null;
if (BuildConfig.DEBUG) {
Log.d(TAG, "waiting for the wifi to be enabled...");
}
if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
wifiInfo = wifiManager.getConnectionInfo();
FDroidApp.ipAddressString = formatIpAddress(wifiInfo.getIpAddress());
} else
FDroidApp.ipAddressString = getIpAddressFromNetworkInterface();
// TODO turning off a hotspot leaves wifiState as UNKNOWN with no IP, and this goes until next wifi change
Thread.sleep(1000);
}
int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
while (ipAddress == 0) {
if (isCancelled())
return null;
if (BuildConfig.DEBUG) {
Log.d(TAG, "waiting for an IP address...");
}
Thread.sleep(1000);
ipAddress = wifiManager.getConnectionInfo().getIpAddress();
}
if (isCancelled())
if (isCancelled()) // can be canceled by a change via WifiStateChangeReceiver
return null;
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
ipAddress = wifiInfo.getIpAddress();
FDroidApp.ipAddressString = String.format(Locale.ENGLISH, "%d.%d.%d.%d",
(ipAddress & 0xff),
(ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff),
(ipAddress >> 24 & 0xff));
final String ssid = wifiInfo.getSSID();
if (wifiInfo != null) {
String ssid = wifiInfo.getSSID();
if (ssid != null) {
FDroidApp.ssid = ssid.replaceAll("^\"(.*)\"$", "$1");
}
FDroidApp.bssid = wifiInfo.getBSSID();
String bssid = wifiInfo.getBSSID();
if (bssid != null) {
FDroidApp.bssid = bssid;
}
}
String scheme;
if (Preferences.get().isLocalRepoHttpsEnabled())
@ -108,14 +104,14 @@ public class WifiStateChangeService extends Service {
FDroidApp.repo.address = String.format(Locale.ENGLISH, "%s://%s:%d/fdroid/repo",
scheme, FDroidApp.ipAddressString, FDroidApp.port);
if (isCancelled())
if (isCancelled()) // can be canceled by a change via WifiStateChangeReceiver
return null;
Context context = WifiStateChangeService.this.getApplicationContext();
LocalRepoManager lrm = LocalRepoManager.get(context);
lrm.writeIndexPage(Utils.getSharingUri(FDroidApp.repo).toString());
if (isCancelled())
if (isCancelled()) // can be canceled by a change via WifiStateChangeReceiver
return null;
// the fingerprint for the local repo's signing key
@ -156,4 +152,54 @@ public class WifiStateChangeService extends Service {
return null;
}
public String getIpAddressFromNetworkInterface() {
try {
for (Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) {
NetworkInterface netIf = networkInterfaces.nextElement();
for (Enumeration<InetAddress> inetAddresses = netIf.getInetAddresses(); inetAddresses.hasMoreElements(); ) {
InetAddress inetAddress = inetAddresses.nextElement();
if (inetAddress.isLoopbackAddress() || inetAddress instanceof Inet6Address) {
continue;
} else if (netIf.getDisplayName().contains("wlan0")
|| netIf.getDisplayName().contains("eth0")
|| netIf.getDisplayName().contains("ap0")) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException ex) {
ex.printStackTrace();
}
return null;
}
private String formatIpAddress(int ipAddress) {
if (ipAddress == 0) {
return null;
} else {
return String.format(Locale.ENGLISH, "%d.%d.%d.%d",
(ipAddress & 0xff),
(ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff),
(ipAddress >> 24 & 0xff));
}
}
private String printWifiState(int wifiState) {
switch (wifiState) {
case WifiManager.WIFI_STATE_DISABLED:
return "WIFI_STATE_DISABLED";
case WifiManager.WIFI_STATE_DISABLING:
return "WIFI_STATE_DISABLING";
case WifiManager.WIFI_STATE_ENABLING:
return "WIFI_STATE_ENABLING";
case WifiManager.WIFI_STATE_ENABLED:
return "WIFI_STATE_ENABLED";
case WifiManager.WIFI_STATE_UNKNOWN:
return "WIFI_STATE_UNKNOWN";
}
return null;
}
}