monitor Wifi changes with BroadcastReceiver/Service

The local repo will need to both have current wifi settings in order to
send the correct IP address, SSID, etc.  Also, this could be used to handle
interrupted downloads and updates, but that is not included in this commit.

refs #3204 https://dev.guardianproject.info/issues/3204
This commit is contained in:
Hans-Christoph Steiner 2014-05-02 17:35:12 -04:00
parent db0b106656
commit 2c2d8c868c
5 changed files with 154 additions and 11 deletions

View File

@ -33,6 +33,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@ -303,8 +304,14 @@
<data android:scheme="package" /> <data android:scheme="package" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".WifiStateChangeReceiver" >
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".UpdateService" /> <service android:name=".UpdateService" />
<service android:name=".net.WifiStateChangeService" />
</application> </application>
</manifest> </manifest>

View File

@ -23,6 +23,8 @@ import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
@ -30,7 +32,11 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build; import android.os.Build;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@ -46,19 +52,36 @@ import de.duenndns.ssl.MemorizingTrustManager;
import org.fdroid.fdroid.compat.PRNGFixes; import org.fdroid.fdroid.compat.PRNGFixes;
import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.InstalledAppCacheUpdater; import org.fdroid.fdroid.data.InstalledAppCacheUpdater;
import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.net.WifiStateChangeService;
import org.thoughtcrime.ssl.pinning.PinningTrustManager; import org.thoughtcrime.ssl.pinning.PinningTrustManager;
import org.thoughtcrime.ssl.pinning.SystemKeyStore; import org.thoughtcrime.ssl.pinning.SystemKeyStore;
import javax.net.ssl.*;
import java.io.File; import java.io.File;
import java.lang.Thread;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Set;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class FDroidApp extends Application { public class FDroidApp extends Application {
// for the local repo on this device, all static since there is only one
public static int ipAddress = 0;
public static int port = 8888;
public static String ipAddressString = null;
public static String ssid = "";
public static String bssid = "";
public static Repo repo = new Repo();
static Set<String> selectedApps = new HashSet<String>();
BluetoothAdapter bluetoothAdapter = null; BluetoothAdapter bluetoothAdapter = null;
private static enum Theme { private static enum Theme {
@ -196,6 +219,13 @@ public class FDroidApp extends Application {
} catch (KeyStoreException e) { } catch (KeyStoreException e) {
Log.e("FDroid", "Unable to set up trust manager chain. KeyStoreException"); Log.e("FDroid", "Unable to set up trust manager chain. KeyStoreException");
} }
// initialized the local repo information
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
int wifiState = wifiManager.getWifiState();
if (wifiState == WifiManager.WIFI_STATE_ENABLING
|| wifiState == WifiManager.WIFI_STATE_ENABLED)
startService(new Intent(this, WifiStateChangeService.class));
} }
@TargetApi(18) @TargetApi(18)

View File

@ -197,15 +197,12 @@ public final class Utils {
return Uri.parse("http://wifi-not-enabled"); return Uri.parse("http://wifi-not-enabled");
Uri uri = Uri.parse(repo.address.replaceFirst("http", "fdroidrepo")); Uri uri = Uri.parse(repo.address.replaceFirst("http", "fdroidrepo"));
Uri.Builder b = uri.buildUpon(); Uri.Builder b = uri.buildUpon();
b.appendQueryParameter("fingerprint", repo.fingerprint); if (!TextUtils.isEmpty(repo.fingerprint))
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); b.appendQueryParameter("fingerprint", repo.fingerprint);
WifiInfo wifiInfo = wifiManager.getConnectionInfo(); if (!TextUtils.isEmpty(FDroidApp.bssid)) {
String ssid = wifiInfo.getSSID().replaceAll("^\"(.*)\"$", "$1"); b.appendQueryParameter("bssid", Uri.encode(FDroidApp.bssid));
String bssid = wifiInfo.getBSSID(); if (!TextUtils.isEmpty(FDroidApp.ssid))
if (!TextUtils.isEmpty(bssid)) { b.appendQueryParameter("ssid", Uri.encode(FDroidApp.ssid));
b.appendQueryParameter("bssid", Uri.encode(bssid));
if (!TextUtils.isEmpty(ssid))
b.appendQueryParameter("ssid", Uri.encode(ssid));
} }
return b.build(); return b.build();
} }

View File

@ -0,0 +1,21 @@
package org.fdroid.fdroid;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import org.fdroid.fdroid.net.WifiStateChangeService;
public class WifiStateChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
NetworkInfo ni = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (ni.isConnected()) {
context.startService(new Intent(context, WifiStateChangeService.class));
}
}
}

View File

@ -0,0 +1,88 @@
package org.fdroid.fdroid.net;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.fdroid.fdroid.FDroidApp;
import java.util.Locale;
public class WifiStateChangeService extends Service {
public static final String BROADCAST = "org.fdroid.fdroid.action.WIFI_CHANGE";
private Context context;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = this;
new WaitForWifiAsyncTask().execute();
return START_NOT_STICKY;
}
public class WaitForWifiAsyncTask extends AsyncTask<Void, Void, Void> {
private static final String TAG = "WaitForWifiAsyncTask";
private WifiManager wifiManager;
@Override
protected Void doInBackground(Void... params) {
wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
try {
while (!wifiManager.isWifiEnabled()) {
Log.i(TAG, "waiting for the wifi to be enabled...");
Thread.sleep(3000);
}
FDroidApp.ipAddress = wifiManager.getConnectionInfo().getIpAddress();
while (FDroidApp.ipAddress == 0) {
Log.i(TAG, "waiting for an IP address...");
Thread.sleep(3000);
FDroidApp.ipAddress = wifiManager.getConnectionInfo().getIpAddress();
}
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
FDroidApp.ipAddress = wifiInfo.getIpAddress();
FDroidApp.ipAddressString = String.format(Locale.ENGLISH, "%d.%d.%d.%d",
(FDroidApp.ipAddress & 0xff),
(FDroidApp.ipAddress >> 8 & 0xff),
(FDroidApp.ipAddress >> 16 & 0xff),
(FDroidApp.ipAddress >> 24 & 0xff));
FDroidApp.ssid = wifiInfo.getSSID().replaceAll("^\"(.*)\"$", "$1");
FDroidApp.bssid = wifiInfo.getBSSID();
String scheme;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean("use_https", false))
scheme = "https";
else
scheme = "http";
FDroidApp.repo.address = String.format(Locale.ENGLISH, "%s://%s:%d/fdroid/repo",
scheme, FDroidApp.ipAddressString, FDroidApp.port);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
Intent intent = new Intent(BROADCAST);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
WifiStateChangeService.this.stopSelf();
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}