Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offline #2

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
18 changes: 15 additions & 3 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.microg.nlp.backend.openwlanmap">

package="org.microg.nlp.backend.openwlanmap"
android:versionCode="2"
android:versionName="0.0.2"
>

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-sdk android:minSdkVersion="19" />
<application
Expand All @@ -19,7 +23,15 @@
<intent-filter>
<action android:name="org.microg.nlp.LOCATION_BACKEND" />
</intent-filter>
<meta-data
android:name="org.microg.nlp.BACKEND_SETTINGS_ACTIVITY"
android:value="org.microg.nlp.backend.openwlanmap.Settings" />
</service>

<activity android:name="org.microg.nlp.backend.openwlanmap.Settings"
android:label="OpenWlanMap Backend">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application>
</manifest>
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ OpenWlanMapNlpBackend
=====================
[UnifiedNlp](https://github.com/microg/android_packages_apps_UnifiedNlp) backend that uses [OpenWlanMap](http://www.openwlanmap.org/) to resolve user location.

Location calculation is done online and therefor requires internet connection.
Location calculation is done either online or offline. This can be switched in the settings.
Online calculation of course requires internet connection.
Offline calculation won't use any data, but look up the wifi access points in a database on your sd-card only.
To generate the database a shell script (gen_openwifimap_db.sh) is included.

To contribute to the OpenWlanMap database you can use the available Android app or upload your "wardriving" data manually [here](https://openwlanmap.org/upload.php?lang=). Don't forget to enable the "Publish own data" in the Android apps settings!

Building
--------
Expand All @@ -16,6 +21,13 @@ Used libraries
- [libwlocate](http://sourceforge.net/projects/libwlocate/) (included)


Changes
-------

0.0.2 - Felix Knecht added offline support

0.0.1 - Initial version by @mar-v-in with online support

License
-------
libwlocate is GPLv3, so is OpenWlanMapNlpBackend.
Expand Down
77 changes: 77 additions & 0 deletions gen_openwifimap_db.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#! /bin/bash
#
# Quick and dirty script to build and install a new
# wifi APs location database on a phone for microg/nogapps
# OpenWlanMapNlpBackend.
#

MAX_LAT="90"
MIN_LAT="-90"
MAX_LON="180"
MIN_LON="-180"

function usage {
echo "Calling Sequence:"
echo "${0} [options]"
echo " Options:"
echo " -nDD -(North) Maximum latitude"
echo " -sDD -(South) Minimum latitude"
echo " -eDD -(East) Maximum longitude"
echo " -nDD -(West) Minimum latitude"
exit
}

#Process the arguments
while getopts n:s:e:w: opt
do
case "$opt" in
n) MAX_LAT=$OPTARG;;
s) MIN_LAT=$OPTARG;;
e) MAX_LON=$OPTARG;;
w) MIN_LON=$OPTARG;;
\?) usage;;
esac
done

#
# Get latest wifi AP locations from OpenWLANMap.org
#

echo 'Getting wifi AP locations from OpenWLANMap.org'
if [ -e db.tar.bz2 ] ; then
rm db.tar.bz2
fi
if [ -e db.csv ] ; then
mv -f db.csv db.csv.bak
fi
wget "http://openwlanmap.org/db.tar.bz2"
tar --strip-components=1 -xjf db.tar.bz2 db/db.csv

echo 'Building database file'
if [ -e openwifimap.db ] ; then
mv -f openwifimap.db openwifimap.db.bak
fi

### TODO: Filter all entries with lat or long = 0
### Those are the _nomap entries

sqlite3 openwifimap.db <<!
CREATE TABLE APs(bssid STRING, latitude REAL, longitude REAL);
.mode csv
.separator "\t"
.import db.csv APs
DELETE FROM APs WHERE latitude>${MAX_LAT};
DELETE FROM APs WHERE latitude<${MIN_LAT};
DELETE FROM APs WHERE longitude>${MAX_LON};
DELETE FROM APs WHERE longitude<${MIN_LON};
CREATE INDEX _idx1 ON APs (bssid);
VACUUM;
.quit
!

#
# Push the new database to the phone.
#
echo 'Pushing database to phone'
adb push openwifimap.db /sdcard/.nogapps/openwifimap.db.x
adb shell mv /sdcard/.nogapps/openwifimap.db.x /sdcard/.nogapps/openwifimap.db.new
8 changes: 8 additions & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">OpenWlanMapNlpBackend</string>
<string name="title_network_category">Network</string>
<string name="title_networkAllowed_preference">Allow network activity</string>
<string name="title_local_category">Local</string>
<string name="title_databaseLocation_preference">Database location</string>
<string name="title_assumedAccuracy_preference">Assumed accuracy for database in meters</string>
<string name="title_debug_category">Debug</string>
<string name="title_debugEnabled_preference">Enable debug log (contains your location)</string>
<string name="prefs_error_accuracy_notfloat">The supplied value for assumed accuracy is not a float</string>
</resources>
26 changes: 26 additions & 0 deletions res/xml/settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

<PreferenceCategory android:title="@string/title_network_category" >
<CheckBoxPreference
android:key="networkAllowed"
android:title="@string/title_networkAllowed_preference" />
</PreferenceCategory>

<PreferenceCategory android:title="@string/title_local_category"
android:key="category_local">
<EditTextPreference
android:key="databaseLocation"
android:title="@string/title_databaseLocation_preference" />
<EditTextPreference
android:defaultValue="50"
android:numeric="integer"
android:key="assumedAccuracy"
android:title="@string/title_assumedAccuracy_preference" />
</PreferenceCategory>

<PreferenceCategory android:title="@string/title_debug_category" >
<CheckBoxPreference
android:key="debugEnabled"
android:title="@string/title_debugEnabled_preference" />
</PreferenceCategory>
</PreferenceScreen>
124 changes: 115 additions & 9 deletions src/org/microg/nlp/backend/openwlanmap/BackendService.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,108 @@
package org.microg.nlp.backend.openwlanmap;

import java.util.ArrayList;
import java.util.List;

import org.microg.nlp.api.LocationBackendService;
import org.microg.nlp.api.LocationHelper;
import org.microg.nlp.backend.openwlanmap.local.WifiLocationFile;
import org.microg.nlp.backend.openwlanmap.local.WifiReceiver;
import org.microg.nlp.backend.openwlanmap.local.WifiReceiver.WifiReceivedCallback;

import android.content.Context;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Location;
import android.net.wifi.WifiManager;
import android.preference.PreferenceManager;
import android.util.Log;

import com.vwp.libwlocate.WLocate;
import org.microg.nlp.api.LocationBackendService;
import org.microg.nlp.api.LocationHelper;

public class BackendService extends LocationBackendService {
private static final String TAG = BackendService.class.getName();
private WLocate wLocate;
private WifiLocationFile wifiLocationFile;
private WifiReceiver wifiReceiver;
private boolean networkAllowed;

@Override
protected void onOpen() {
if (wLocate == null) {
wLocate = new MyWLocate(this);
} else {
wLocate.doResume();
}
Log.d(TAG, "onOpen");

SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Configuration.fillFromPrefs(sharedPrefs);
sharedPrefs.registerOnSharedPreferenceChangeListener(Configuration.listener);

setOperatingMode();
}

@Override
protected void onClose() {
if (Configuration.debugEnabled) Log.d(TAG, "onClose");

SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
sharedPrefs.unregisterOnSharedPreferenceChangeListener(Configuration.listener);

cleanupOperatingMode();

}

private void setOperatingMode() {
this.networkAllowed = Configuration.networkAllowed;
if (this.networkAllowed) {
if (wLocate == null) {
wLocate = new MyWLocate(this);
} else {
wLocate.doResume();
}
} else {
openDatabase();
if (wifiReceiver == null) {
wifiReceiver = new WifiReceiver(this, new WifiDBResolver());
}
registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
}

private void cleanupOperatingMode() {
if (wLocate != null) {
wLocate.doPause();
}
}
if (wifiReceiver != null) {
unregisterReceiver(wifiReceiver);
}
}

@Override
protected Location update() {
if (Configuration.debugEnabled) Log.d(TAG, "update");

if (this.networkAllowed != Configuration.networkAllowed) {
if (Configuration.debugEnabled) Log.d(TAG, "Network allowed changed");
cleanupOperatingMode();
setOperatingMode();
}
if (wLocate != null) {
if (Configuration.debugEnabled) Log.d(TAG, "Requesting location from net");
wLocate.wloc_request_position(WLocate.FLAG_NO_GPS_ACCESS);
return null;
}

if (wifiReceiver != null) {
if (Configuration.debugEnabled) Log.d(TAG, "Requesting location from db");
wifiReceiver.startScan();
}

return null;
}

private void openDatabase() {
if (wifiLocationFile == null) {
wifiLocationFile = new WifiLocationFile();
}
}

private class MyWLocate extends WLocate {

public MyWLocate(Context ctx) throws IllegalArgumentException {
Expand All @@ -43,7 +111,7 @@ public MyWLocate(Context ctx) throws IllegalArgumentException {

@Override
protected void wloc_return_position(int ret, double lat, double lon, float radius, short ccode, float cog) {
Log.d(TAG, String.format("wloc_return_position ret=%d lat=%f lon=%f radius=%f ccode=%d cog=%f", ret, lat, lon, radius, ccode, cog));
if (Configuration.debugEnabled) Log.d(TAG, String.format("wloc_return_position ret=%d lat=%f lon=%f radius=%f ccode=%d cog=%f", ret, lat, lon, radius, ccode, cog));
if (ret == WLOC_OK) {
Location location = LocationHelper.create("libwlocate", lat, lon, radius);
if (cog != -1) {
Expand All @@ -53,4 +121,42 @@ protected void wloc_return_position(int ret, double lat, double lon, float radiu
}
}
}

private class WifiDBResolver implements WifiReceivedCallback {

@Override
public void process(List<String> foundBssids) {

if (foundBssids == null || foundBssids.isEmpty()) {
return;
}
if (wifiLocationFile != null) {

List<Location> locations = new ArrayList<Location>(foundBssids.size());

for (String bssid : foundBssids) {
Location result = wifiLocationFile.query(bssid);
if (result != null) {
locations.add(result);
}
}

if (locations.isEmpty()) {
return;
}

//TODO fix LocationHelper:average to not calculate with null values
//TODO sort out wifis obviously in the wrong spot
Location avgLoc = LocationHelper.average("owm", locations);

if (avgLoc == null) {
Log.e(TAG, "Averaging locations did not work.");
return;
}

if (Configuration.debugEnabled) Log.d(TAG, "Reporting location: " + avgLoc.toString());
report(avgLoc);
}
}
}
}
Loading