├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── app
├── app-release.apk
├── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── org
│ │ └── fitchfamily
│ │ └── android
│ │ └── wifi_backend
│ │ ├── Configuration.java
│ │ ├── Constants.java
│ │ ├── SpiceService.java
│ │ ├── backend
│ │ ├── BackendService.java
│ │ └── gpsMonitor.java
│ │ ├── data
│ │ ├── ExportSpiceRequest.java
│ │ ├── ImportSpiceRequest.java
│ │ └── ResetSpiceRequest.java
│ │ ├── database
│ │ ├── AccessPoint.java
│ │ ├── Database.java
│ │ └── SamplerDatabase.java
│ │ ├── ui
│ │ ├── AdvancedSettingsFragment.java
│ │ ├── BaseDialogFragment.java
│ │ ├── EditTextPreference.java
│ │ ├── MainActivity.java
│ │ ├── MainSettingsFragment.java
│ │ ├── data
│ │ │ ├── CursorAdapter.java
│ │ │ ├── CursorLoader.java
│ │ │ ├── WifiDetailActivity.java
│ │ │ ├── WifiDetailFragment.java
│ │ │ ├── WifiListActivity.java
│ │ │ ├── WifiListAdapter.java
│ │ │ ├── reset
│ │ │ │ ├── ResetDatabaseDialogFragment.java
│ │ │ │ └── ResetProgressDialog.java
│ │ │ └── transfer
│ │ │ │ ├── ExportProgressDialog.java
│ │ │ │ ├── ImportProgressDialog.java
│ │ │ │ └── OperationProgressDialog.java
│ │ └── statistic
│ │ │ ├── DatabaseStatistic.java
│ │ │ └── DatabaseStatisticLoader.java
│ │ ├── util
│ │ ├── AgeValue.java
│ │ ├── CountingInputStream.java
│ │ ├── LocationUtil.java
│ │ ├── SimpleLocation.java
│ │ └── distanceCache.java
│ │ └── wifi
│ │ ├── WifiAccessPoint.java
│ │ ├── WifiBlacklist.java
│ │ ├── WifiCompat.java
│ │ └── WifiReceiver.java
│ ├── res
│ ├── drawable-hdpi-v11
│ │ └── ic_stat_no_location.png
│ ├── drawable-hdpi
│ │ └── ic_stat_no_location.png
│ ├── drawable-mdpi-v11
│ │ └── ic_stat_no_location.png
│ ├── drawable-mdpi
│ │ └── ic_stat_no_location.png
│ ├── drawable-xhdpi-v11
│ │ └── ic_stat_no_location.png
│ ├── drawable-xhdpi
│ │ └── ic_stat_no_location.png
│ ├── drawable-xxhdpi-v11
│ │ └── ic_stat_no_location.png
│ ├── drawable-xxhdpi
│ │ └── ic_stat_no_location.png
│ ├── drawable-xxxhdpi-v11
│ │ └── ic_stat_no_location.png
│ ├── drawable-xxxhdpi
│ │ └── ic_stat_no_location.png
│ ├── layout-w900dp
│ │ └── activity_wifi_list.xml
│ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_wifi_detail.xml
│ │ ├── activity_wifi_list.xml
│ │ ├── toolbar.xml
│ │ ├── wifi_detail.xml
│ │ └── wifi_list_content.xml
│ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ ├── values-de
│ │ └── strings.xml
│ ├── values-fr
│ │ └── strings.xml
│ ├── values-pl
│ │ └── strings.xml
│ ├── values-sr
│ │ └── strings.xml
│ ├── values-uk
│ │ └── strings.xml
│ ├── values-v19
│ │ └── constants.xml
│ ├── values
│ │ ├── constants.xml
│ │ ├── defaults.xml
│ │ ├── dimens.xml
│ │ ├── libraries.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── xml
│ │ ├── advanced.xml
│ │ └── main.xml
│ └── web_hi_res_512.png
├── build.gradle
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── changelogs
│ └── 42.txt
│ ├── full_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── Screenshot1.png
│ │ └── Screenshot2.png
│ ├── short_description.txt
│ └── title.txt
├── get_it_on_f-droid.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | tags
2 | .DS_Store
3 | local.properties
4 | gen/
5 | .idea/
6 | out/
7 | *.iml
8 | build/
9 | *.apk
10 | .gradle/
11 | user.gradle
12 | local.properties
13 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en)
5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6 |
7 | ## [Unreleased]
8 | ### Added
9 | - Not applicable
10 |
11 | ### Changed
12 | - Not applicable
13 |
14 | ### Removed
15 | - Not applicable
16 |
17 | ## [1.1.13] - 2018-06-17
18 | ### Added
19 | - Add Ukrainian translation
20 |
21 | ### Changed
22 | - Update build environment
23 |
24 | ## [1.1.12] - 2018-06-08
25 | ### Added
26 | - Ability to filter or search for specific AP or group of APs by SSID or BSSIS.
27 |
28 | ### Changed
29 | - Correct typographic error in German translation. Thanks to @N3dal
30 |
31 | ## [1.1.11] - 2018-03-13
32 | ### Added
33 | - Reset database control added. Thanks to @l-jonas
34 |
35 | ## [1.1.10] 2017-09-21
36 | ### Added
37 | - Polish translation. Thanks to @verdulo
38 |
39 | ## [1.1.9] 2017-09-19
40 | ### Changed
41 | - Correct XML errors in French translation.
42 |
43 | ## [1.1.8] 2017-09-12
44 | ### Changed
45 | - Build changed to compile dependency rather than import jar file.
46 |
47 | ## [1.1.7] - 2017-09-08
48 | ### Added
49 | - Add French translation. Thanks to @Massedil
50 |
51 | ### Changed
52 | - Move change log into separate file.
53 | - Update build tools and gradle
54 |
55 | ## [1.1.6] - 2016-08-10
56 | ### Added
57 | - Now supports backup/export of new/changed data in addition to full backup/export.
58 |
59 | ### Changed
60 | - New database schema (probably want to backup/export existing data before upgrading just in case).
61 | - Various other internal changes and fixes to work toward goal of supporting other types of RF sources for position estimation.
62 |
63 | ## [1.1.5] - 2016-07-30
64 | ### Changed
65 | - Add permission to write to external storage so export data will work.
66 |
67 | ## [1.1.4] - 2016-06-23
68 | ### Changed
69 | - Fix calculation cache to miss less often.
70 |
71 | ## [1.1.3] - 2016-06-23
72 | ### Changed
73 | - Improve performance on often used distance calculations
74 |
75 | ## [1.1.2] - 2016-06-22
76 | ### Changed
77 | - Refactor some files and logic. Should be no user discernible change in operation.
78 |
79 | ## [1.1.1] - 2016-05-13
80 | ### Changed
81 | - Fix divide by zero on minimum signal strength.
82 |
83 | ## [1.1.0] - 2016-05-05
84 | ### Changed
85 | - Change import/export format to comma separated value (CSV) format.
86 |
87 | ## [1.0.2] - 2016-03-23
88 | ### Changed
89 | - Update for revised UnifiedNlp with aging of reports.
90 |
91 | ## [1.0.0] - 2016-01-06
92 | ### Added
93 | - Thanks to @pejakm, update Serbian translation
94 |
95 | ## [0.9.9] - 2016-01-16
96 | ### Added
97 | - Thanks to @UnknownUntilNow, new UI, refactored code, import and export of WiFi AP location information, support for Marshmallow
98 |
99 | ## [0.17.0] 2015-08-21
100 | ### Changed
101 | - |21Aug2015|Increase location uncertainty if no position found.
102 |
103 | ## [0.6.1]
104 | ### Changed
105 | - Fix up Android Studio/Gradle build environment
106 |
107 | ## [0.6.0]
108 | ### Added
109 | - Configurable settings for data collection and use.
110 |
111 | ### Changed
112 | - Some improvements in performance
113 |
114 | ## [0.1.0]
115 | ### Added
116 | - Initial version
117 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | NOTICE
2 | ======
3 | The author of this backend is now primarily focused on the [Déjá Vu backend](https://github.com/n76/DejaVu). Bug fixes and pull requests will be accepted for this backend but it will not be as well supported as Déjá Vu going forward.
4 |
5 | Local WiFi Backend
6 | ==================
7 | [UnifiedNlp](https://github.com/microg/android_packages_apps_UnifiedNlp) backend that uses locally acquired WiFi AP data to resolve user location.
8 |
9 | This backend consists of two parts sharing a common database. One part passively monitors the GPS. If the GPS has acquired and has a good position accuracy, then the WiFi APs detected by the phone are stored.
10 |
11 | The other part is the actual location provider which uses the database to estimate location when the GPS is not available. The use of stored WiFi AP can decrease the GPS time to first fix and allows apps to get an immediate approximate location.
12 |
13 | This backend uses no network data. All data acquired by the phone stays on the phone and no queries are made to a centralized WiFi AP location provider.
14 |
15 | [](https://f-droid.org/repository/browse/?fdid=org.fitchfamily.android.wifi_backend)
16 |
17 | Requirement for building
18 | ========================
19 |
20 | 1. Building requires Android SDK with API 19 or higher.
21 |
22 | Requirements on phone
23 | =====================
24 | 1. This is a plug-in for [µg UnifiedNlp](http://forum.xda-developers.com/android/apps-games/app-g-unifiednlp-floss-wi-fi-cell-tower-t2991544) which can be [installed from f-droid](https://f-droid.org/repository/browse/?fdfilter=unified&fdpage=1&page_id=0). The [µg GmsCore](http://forum.xda-developers.com/android/apps-games/app-microg-gmscore-floss-play-services-t3217616) can also use this backend.
25 |
26 | How to build and install
27 | ========================
28 |
29 | Using Android Studio, select Build->"Generate Signed APK..."
30 |
31 | Setup on phone
32 | ==============
33 | In the NLP Controller app (interface for µg UnifiedNlp) select the "WiFi Location Service". If using GmsCore, then the little gear at microG Settings->UnifiedNlp Settings->Configure location backends->WiFi Location Service is used.
34 |
35 | Advanced Settings
36 | --------
37 | - Required Accuracy: Sets the maximum error that a GPS location report can have for the sampler to trigger the collection of WiFi Access Point (AP) data. For example, if set to 10m then all GPS locations with accuracy worse (greater) than 10m will be ignored.
38 | - Sample Distance: Sets the minimum distance change in a GPS location for the Android OS to give the sampler a new location. For example if set to 20m, then only GPS positions more than 20m apart will be used.
39 | - Sample Interval: Sets the minimum time between GPS location reports from the Android OS. Smaller values may improve AP range detection but will cause higher processing loads.
40 | - GPS Valid Time: How long a position report from the GPS is considered good. WiFi APs detected during this time will use the most recent valid GPS location when updating the database.
41 | - Minimum AP Range: Sets the minimum range (accuracy) value back end will report for an AP. This value should be set to the usual coverage radius of a WiFi AP. For current model APs this is about 100m.
42 | - Moved Threshold: If a new GPS location sample for an AP is too far from our old estimate we assume the AP has been moved. This value sets the distance that will trigger the moved AP logic.
43 | - Move Guard: Once an AP has been detected as moved we block its location from being used until we are sure it is stable. Stable is defined as having received a number of GPS location updates for the AP that are plausible. This value sets the number of samples required to clear the "moved" indication.
44 |
45 | Collecting WiFi AP Data
46 | -----------------------
47 | To conserve power the collection process does not actually turn on the GPS. If some other app turns on the app, for example a map or navigation app, then the backend will monitor the location and collect WiFi data.
48 |
49 | What is stored in the database
50 | ------------------------------
51 | For each WiFi AP the [bssid](https://en.wikipedia.org/wiki/Service_set_(802.11_network)#Basic_service_set_identification_.28BSSID.29) and, if set, the [ssid](https://en.wikipedia.org/wiki/Service_set_(802.11_network)#Service_set_identification_.28SSID.29) are stored along with up to three sets of latitude/longitude samples. There is also a "moved" indicator set if it appears the AP may have moved.
52 |
53 | The ssid is stored for display only and is irrelevant to actual function of this software.
54 |
55 | The algorithm attempts to determine the outer edge of the coverage area a WiFi AP by saving the three samples that give the largest reasonable circle within which the AP is detected. The [logic behind this was to reduce identifiable "bread crumb" trails](http://retiredtechie.fitchfamily.org/2014/12/13/bread-crumbs/) for data collected by stumblers and may not be ideal.
56 |
57 | Export and Import of WiFi (WLAN) Access Point (AP) data
58 | -------------------------------------------------------
59 | - On export each sample for each AP is written as a separate record with up to three records per AP. Excluded from this are points for any AP which has been detected as moved or moving.
60 | - On import each record is treated the same as a data point from the internal background sampling server. That is the data is merged into the database with each position compared against the ones already in the database to see if using it would provide a better AP position estimate.
61 | - It is possible to share export files: Position sample data from a file someone else exported will be merged on import and you will end up with a database containing the "best" set of location sample points from all imports as well as those collected locally.
62 | - The location lookup process requires a minimum of three samples for a AP before it will use that AP. So imports that have a single best position will be entered in the database but will not be used for position estimation until at least two more position samples are available. If you are importing from another project you may wish to pre-process their data to create three points around the best guess location and then import the three estimated points rather than the center location.
63 | - This backend does not support the import or export of data to anyplace other than local storage on the phone. If you wish to back up the data or share it, you will need to do that through other means.
64 |
65 | Clearing the database
66 | ---------------------
67 | To clear or reset database, touch the "Reset Database" in the backend setting.
68 |
69 | Libraries Used
70 | --------------
71 | - A full list of libraries used is listed in the "External Libraries" area of this app's settings.
72 |
73 | Other IP used
74 | =============
75 | Icon created with the [Android Asset Studio](https://romannurik.github.io/AndroidAssetStudio/icons-launcher.html#foreground.type=clipart&foreground.space.trim=1&foreground.space.pad=0.15&foreground.clipart=res%2Fclipart%2Ficons%2Fdevice_signal_wifi_3_bar.svg&foreColor=fff%2C0&crop=0&backgroundShape=circle&backColor=4caf50%2C100&effects=none) (Creative Commons Attribution 3.0 Unported License).
76 |
77 | Notification icon created with the [Android Asset Studio](https://romannurik.github.io/AndroidAssetStudio/icons-notification.html#source.type=clipart&source.space.trim=1&source.space.pad=0&source.clipart=res%2Fclipart%2Ficons%2Fcommunication_location_off.svg&name=ic_stat_no_location) (Creative Commons Attribution 3.0 Unported License).
78 |
79 | Changes
80 | =======
81 | [History is now a separate file](CHANGELOG.md)
82 |
83 | License
84 | =======
85 |
86 | Copyright (C) 2014, 2015, 2016 Tod Fitch
87 |
88 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
89 |
90 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
91 |
92 | You should have received a copy of the GNU General Public License along with this program. If not, see .
93 |
--------------------------------------------------------------------------------
/app/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/app-release.apk
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | }
5 |
6 | dependencies {
7 | // replace with the current version of the Android plugin
8 | classpath 'com.android.tools.build:gradle:2.3.3'
9 | // replace with the current version of the android-apt plugin
10 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
11 | }
12 | }
13 |
14 | apply plugin: 'com.android.application'
15 | apply plugin: 'android-apt'
16 |
17 | android {
18 | compileSdkVersion 23
19 | buildToolsVersion '25.0.2'
20 |
21 | defaultConfig {
22 | applicationId "org.fitchfamily.android.wifi_backend"
23 | minSdkVersion 17
24 | targetSdkVersion 23
25 | }
26 |
27 | buildTypes {
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
31 | }
32 | }
33 |
34 | packagingOptions {
35 | exclude 'META-INF/LICENSE.txt'
36 | exclude 'META-INF/NOTICE.txt'
37 | }
38 | }
39 |
40 | def AAVersion = '3.3.2'
41 |
42 | dependencies {
43 | compile "com.android.support:support-v4:23.4.0"
44 | provided 'com.google.auto.value:auto-value:1.5.2'
45 | apt "org.androidannotations:androidannotations:$AAVersion"
46 | compile "org.androidannotations:androidannotations-api:$AAVersion"
47 | compile('com.mikepenz:materialdrawer:4.6.3@aar') {
48 | transitive = true
49 | }
50 | compile('com.mikepenz:aboutlibraries:5.3.7@aar') {
51 | transitive = true
52 | }
53 | compile 'org.microg:unifiednlp-api:1.5.3'
54 | compile 'com.google.guava:guava:19.0'
55 | compile 'com.mikepenz:google-material-typeface:2.1.0.1.original@aar'
56 | compile "com.android.support:support-v4:23.4.0"
57 | compile "com.android.support:recyclerview-v7:23.4.0"
58 | compile 'com.google.code.gson:gson:2.8.0'
59 | compile 'com.octo.android.robospice:robospice:1.4.14'
60 | compile 'com.github.machinarius:preferencefragment:0.1.1'
61 | compile 'com.opencsv:opencsv:3.7'
62 | }
63 |
64 | apt {
65 | arguments {
66 | androidManifestFile variant.outputs[0]?.processResources?.manifestFile
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
24 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
43 |
46 |
47 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/Configuration.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.Manifest;
22 | import android.content.Context;
23 | import android.content.SharedPreferences;
24 | import android.content.pm.PackageManager;
25 | import android.content.res.Resources;
26 | import android.preference.PreferenceManager;
27 | import android.support.v4.content.ContextCompat;
28 |
29 | public class Configuration {
30 | // Identifiers for extra fields in Location records
31 | public static final String EXTRA_MAC_ADDRESS = "MAC_ADDRESS";
32 | public static final String EXTRA_SIGNAL_LEVEL = "SIGNAL_LEVEL";
33 |
34 | public static final String PREF_MIN_GPS_TIME = "gps_min_time_preference";
35 | public static final String PREF_MIN_GPS_ACCURACY = "gps_accuracy_preference";
36 | public static final String PREF_MIN_GPS_DISTANCE = "gps_min_distance_preference";
37 |
38 | public static final String PREF_AP_ACCURACY = "ap_min_range_preference";
39 | public static final String PREF_MOVE_GUARD = "ap_moved_guard_preference";
40 | public static final String PREF_MOVE_RANGE = "ap_moved_range_preference";
41 |
42 | public static final String PREF_GPS_VALID_TIME = "gps_valid_time";
43 |
44 | private static final Object lock = new Object();
45 | private static Configuration instance;
46 |
47 | public static Configuration with(Context context) {
48 | if(context == null) {
49 | throw new NullPointerException();
50 | }
51 |
52 | if(instance == null) {
53 | synchronized (lock) {
54 | if (instance == null) {
55 | instance = new Configuration(context.getApplicationContext());
56 | }
57 | }
58 | }
59 |
60 | return instance;
61 | }
62 |
63 | private SharedPreferences preferences;
64 | private Resources resources;
65 | private Context context;
66 |
67 | public static final int LIST_OPTION_ALL = 0;
68 | public static final int LIST_OPTION_CHANGED = 1;
69 | private static int listOptionValue = LIST_OPTION_ALL;
70 |
71 | public static final int EXPORT_OPTION_ALL = 0;
72 | public static final int EXPORT_OPTION_CHANGED = 1;
73 | private static int exportOptionValue = LIST_OPTION_ALL;
74 |
75 | private Configuration(Context context) {
76 | preferences = PreferenceManager.getDefaultSharedPreferences(context);
77 | resources = context.getResources();
78 | this.context = context;
79 | }
80 |
81 | // How accurate should our GPS position be to bother recording WiFi signals?
82 | public float minimumGpsAccuracyInMeters() {
83 | return parseFloat(PREF_MIN_GPS_ACCURACY, R.string.gps_accuracy_default);
84 | }
85 |
86 | public long minimumGpsTimeInMilliseconds() {
87 | return parseLong(PREF_MIN_GPS_TIME, R.string.gps_min_time_default) * 1000;
88 | }
89 |
90 | public float minimumGpsDistanceInMeters() {
91 | return parseFloat(PREF_MIN_GPS_DISTANCE, R.string.gps_min_distance_default);
92 | }
93 |
94 | // If new report is too far away from our current estimate then
95 | // we assume the AP has moved. apMovedThreshold sets the value for that
96 | // check.
97 | //
98 | // We set a guard against using the moved AP until we get a number
99 | // of samples confirming that it has a stable location. We get a new
100 | // GPS sample every gpsMinTime and we decrease the move guard count
101 | // by one for each good sample for the specific AP. Set this value
102 | // so big enough so that if we are near a parked WiFi AP equipped bus
103 | // it is likely to move before we count down to zero.
104 |
105 | public float accessPointMoveThresholdInMeters() {
106 | return parseFloat(PREF_MOVE_RANGE, R.string.ap_moved_range_default);
107 | }
108 |
109 | public int accessPointMoveGuardSampleCount() {
110 | return parseInt(PREF_MOVE_GUARD, R.string.ap_moved_guard_default);
111 | }
112 |
113 | // For reporting our results to the network backend we will
114 | // guess about the minimum accuracy for an individual AP
115 | public float accessPointAssumedAccuracy() {
116 | return parseFloat(PREF_AP_ACCURACY, R.string.ap_min_range_default);
117 | }
118 |
119 | public long validGpsTimeInMilliseconds() {
120 | return parseLong(PREF_GPS_VALID_TIME, R.string.gps_valid_time_default) * 1000;
121 | }
122 |
123 | public Configuration register(SharedPreferences.OnSharedPreferenceChangeListener listener) {
124 | preferences.registerOnSharedPreferenceChangeListener(listener);
125 |
126 | return this;
127 | }
128 |
129 | public Configuration unregister(SharedPreferences.OnSharedPreferenceChangeListener listener) {
130 | preferences.unregisterOnSharedPreferenceChangeListener(listener);
131 |
132 | return this;
133 | }
134 |
135 | public boolean hasLocationAccess() {
136 | return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
137 | }
138 |
139 | public static int listOption() {
140 | return listOptionValue;
141 | }
142 |
143 | public static void listOption(int newVal ) {
144 | listOptionValue = newVal;
145 | }
146 |
147 | public static int exportOption() { return exportOptionValue; }
148 | public static void exportOption(int newVal) { exportOptionValue = newVal; }
149 |
150 | private float parseFloat(String preferenceKey, int defaultResource) {
151 | String defaultValue = resources.getString(defaultResource);
152 |
153 | try {
154 | return Float.parseFloat(preferences.getString(preferenceKey, defaultValue));
155 | } catch (NumberFormatException ex) {
156 | return Float.parseFloat(defaultValue);
157 | }
158 | }
159 |
160 | private long parseLong(String preferenceKey, int defaultResource) {
161 | String defaultValue = resources.getString(defaultResource);
162 |
163 | try {
164 | return Long.parseLong(preferences.getString(preferenceKey, defaultValue));
165 | } catch (NumberFormatException ex) {
166 | return Long.parseLong(defaultValue);
167 | }
168 | }
169 |
170 | private int parseInt(String preferenceKey, int defaultResource) {
171 | String defaultValue = resources.getString(defaultResource);
172 |
173 | try {
174 | return Integer.parseInt(preferences.getString(preferenceKey, defaultValue));
175 | } catch (NumberFormatException ex) {
176 | return Integer.parseInt(defaultValue);
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/Constants.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | public abstract class Constants {
22 | private Constants() {
23 |
24 | }
25 |
26 | public static final String WEBSITE = "https://github.com/n76/wifi_backend/blob/master/README.md";
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/SpiceService.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend;
2 |
3 | import android.content.Context;
4 |
5 | import com.octo.android.robospice.UncachedSpiceService;
6 | import com.octo.android.robospice.networkstate.NetworkStateChecker;
7 |
8 | public class SpiceService extends UncachedSpiceService {
9 | @Override
10 | protected NetworkStateChecker getNetworkStateChecker() {
11 | return new NetworkStateChecker() {
12 | @Override
13 | public boolean isNetworkAvailable(Context context) {
14 | return true;
15 | }
16 |
17 | @Override
18 | public void checkPermissions(Context context) {
19 |
20 | }
21 | };
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/backend/gpsMonitor.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.backend;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.app.Service;
22 | import android.content.Intent;
23 | import android.content.SharedPreferences;
24 | import android.location.LocationListener;
25 | import android.location.LocationManager;
26 | import android.net.wifi.WifiManager;
27 | import android.os.Binder;
28 | import android.os.Bundle;
29 | import android.os.IBinder;
30 | import android.support.annotation.NonNull;
31 | import android.text.TextUtils;
32 | import android.util.Log;
33 |
34 | import org.androidannotations.annotations.AfterInject;
35 | import org.androidannotations.annotations.EService;
36 | import org.androidannotations.annotations.SystemService;
37 | import org.fitchfamily.android.wifi_backend.BuildConfig;
38 | import org.fitchfamily.android.wifi_backend.Configuration;
39 |
40 | import java.util.concurrent.ExecutorService;
41 | import java.util.concurrent.Executors;
42 |
43 | @EService
44 | public class gpsMonitor extends Service implements LocationListener,
45 | SharedPreferences.OnSharedPreferenceChangeListener {
46 |
47 | private final static String TAG = "WiFiBackendGpsMon";
48 | private static final boolean DEBUG = BuildConfig.DEBUG;
49 |
50 | private final ExecutorService executor = Executors.newSingleThreadExecutor();
51 |
52 | @SystemService
53 | protected LocationManager locationManager;
54 |
55 | @SystemService
56 | protected WifiManager wifi;
57 |
58 | private long sampleTime;
59 | private float sampleDistance;
60 |
61 | @Override
62 | public IBinder onBind(Intent intent) {
63 | return new Binder();
64 | }
65 |
66 | @AfterInject
67 | protected void init() {
68 | if (DEBUG) {
69 | Log.i(TAG, "service started");
70 | }
71 |
72 | sampleTime = Configuration.with(this).minimumGpsTimeInMilliseconds();
73 | sampleDistance = Configuration.with(this).minimumGpsDistanceInMeters();
74 |
75 | try {
76 | locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
77 | sampleTime,
78 | sampleDistance,
79 | gpsMonitor.this);
80 | } catch (SecurityException ex) {
81 | if(DEBUG) {
82 | Log.w(TAG, "init()", ex);
83 | }
84 | }
85 |
86 | Configuration.with(this).register(this);
87 | }
88 |
89 | @Override
90 | public void onDestroy() {
91 | super.onDestroy();
92 |
93 | Configuration.with(this).unregister(this);
94 |
95 | try {
96 | locationManager.removeUpdates(gpsMonitor.this);
97 | } catch (SecurityException ex) {
98 | // ignore
99 | }
100 |
101 | if (DEBUG) {
102 | Log.i(TAG, "service destroyed");
103 | }
104 | }
105 |
106 | @Override
107 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
108 | if(TextUtils.equals(key, Configuration.PREF_MIN_GPS_TIME) ||
109 | TextUtils.equals(key, Configuration.PREF_MIN_GPS_DISTANCE)) {
110 |
111 | updateSamplingConf(
112 | Configuration.with(gpsMonitor.this).minimumGpsTimeInMilliseconds(),
113 | Configuration.with(gpsMonitor.this).minimumGpsDistanceInMeters()
114 | );
115 | }
116 | }
117 |
118 | private void updateSamplingConf(final long sampleTime, final float sampleDistance) {
119 | if (DEBUG) {
120 | Log.i(TAG, "updateSamplingConf(" + sampleTime + ", " + sampleDistance + ")");
121 | }
122 |
123 | // We are in a call back so we can't change the sampling configuration
124 | // in the caller's thread context. Send a message to the processing thread
125 | // for it to deal with the issue.
126 | executor.submit(new Runnable() {
127 | @Override
128 | public void run() {
129 | if ((gpsMonitor.this.sampleTime != sampleTime) ||
130 | (gpsMonitor.this.sampleDistance != sampleDistance)) {
131 |
132 | gpsMonitor.this.sampleTime = sampleTime;
133 | gpsMonitor.this.sampleDistance = sampleDistance;
134 |
135 | if (DEBUG) {
136 | Log.i(TAG, "Changing GPS sampling configuration: " +
137 | gpsMonitor.this.sampleTime + " ms, " + gpsMonitor.this.sampleDistance + " meters");
138 | }
139 |
140 | try {
141 | locationManager.removeUpdates(gpsMonitor.this);
142 | locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
143 | gpsMonitor.this.sampleTime,
144 | gpsMonitor.this.sampleDistance,
145 | gpsMonitor.this);
146 | } catch (SecurityException ex) {
147 | if(DEBUG) {
148 | Log.w(TAG, "updateSamplingConf()", ex);
149 | }
150 | }
151 | }
152 | }
153 | });
154 | }
155 |
156 | @Override
157 | public int onStartCommand(Intent intent, int flags, int startId) {
158 | return Service.START_STICKY;
159 | }
160 |
161 | @Override
162 | public void onLocationChanged(final android.location.Location location) {
163 |
164 | if (location.getProvider().equals("gps")) {
165 | if (location.getAccuracy() <= Configuration.with(this).minimumGpsAccuracyInMeters()) {
166 | BackendService.instanceGpsLocationUpdated(location);
167 | } else {
168 | if (DEBUG) {
169 | Log.i(TAG, "Ignoring inaccurate GPS location ("+location.getAccuracy()+" meters).");
170 | }
171 | }
172 | } else {
173 | if (DEBUG) {
174 | Log.i(TAG, "Ignoring position from \""+location.getProvider()+"\"");
175 | }
176 | }
177 | }
178 |
179 | @Override
180 | public void onProviderDisabled(String arg0) {
181 | if (DEBUG) {
182 | Log.i(TAG, "Provider Disabled.");
183 | }
184 | }
185 |
186 | @Override
187 | public void onProviderEnabled(String arg0) {
188 | if (DEBUG) {
189 | Log.i(TAG, "Provider Enabled.");
190 | }
191 | }
192 |
193 | @Override
194 | public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
195 | if (DEBUG) {
196 | Log.i(TAG, "Status Changed.");
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/data/ExportSpiceRequest.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Context;
22 | import android.database.Cursor;
23 | import android.net.Uri;
24 | import android.text.TextUtils;
25 |
26 | import com.octo.android.robospice.request.SpiceRequest;
27 | import com.opencsv.CSVWriter;
28 |
29 | import org.fitchfamily.android.wifi_backend.BuildConfig;
30 | import org.fitchfamily.android.wifi_backend.Configuration;
31 | import org.fitchfamily.android.wifi_backend.database.AccessPoint;
32 | import org.fitchfamily.android.wifi_backend.database.Database;
33 | import org.fitchfamily.android.wifi_backend.database.SamplerDatabase;
34 | import org.fitchfamily.android.wifi_backend.util.SimpleLocation;
35 |
36 | import java.io.IOException;
37 | import java.io.OutputStream;
38 | import java.io.OutputStreamWriter;
39 |
40 | public class ExportSpiceRequest extends SpiceRequest {
41 | public static final String TAG = "WiFiBackendExport";
42 | private static final boolean DEBUG = BuildConfig.DEBUG;
43 |
44 | public static final int MAX_PROGRESS = 1000;
45 |
46 | private final Context context;
47 | private final Uri uri;
48 |
49 | public abstract static class Result {
50 |
51 | }
52 |
53 | public ExportSpiceRequest(Context context, Uri uri) {
54 | super(Result.class);
55 | this.context = context.getApplicationContext();
56 | this.uri = uri;
57 | }
58 |
59 | @Override
60 | public Result loadDataFromNetwork() throws Exception {
61 | OutputStream outputStream = context.getContentResolver().openOutputStream(uri);
62 |
63 | if(outputStream == null) {
64 | throw new IOException();
65 | }
66 |
67 | try {
68 | CSVWriter writer = new CSVWriter(new OutputStreamWriter(outputStream, "UTF-8"));
69 | writer.writeNext(new String[]{"bssid","lat","lon","ssid"});
70 | String selection;
71 | boolean exportAll = true;
72 | switch (Configuration.exportOption()) {
73 | case Configuration.EXPORT_OPTION_CHANGED:
74 | selection = Database.COL_CHANGED + "<> 0";
75 | break;
76 |
77 | default:
78 | selection = null;
79 | exportAll = true;
80 | }
81 |
82 | Cursor cursor = SamplerDatabase.getInstance(context).getReadableDatabase().query(
83 | Database.TABLE_SAMPLES,
84 | new String[]{Database.COL_RFID},
85 | selection,
86 | null, null, null, null
87 | );
88 |
89 | try {
90 | if (cursor != null && cursor.moveToFirst()) {
91 | do {
92 | AccessPoint accessPoint = SamplerDatabase.getInstance(context).query(cursor.getString(0));
93 |
94 | if(accessPoint != null) {
95 | writeCSV(writer,
96 | accessPoint,
97 | exportAll
98 | );
99 | }
100 |
101 | publishProgress(cursor.getPosition() * MAX_PROGRESS / cursor.getCount());
102 | } while (cursor.moveToNext());
103 | }
104 |
105 | } finally {
106 | if (cursor != null) {
107 | cursor.close();
108 | }
109 | }
110 | writer.close();
111 | } finally {
112 | outputStream.close();
113 | }
114 | SamplerDatabase.getInstance(context).exportComplete();
115 | return null;
116 | }
117 |
118 | private void writeCSV(CSVWriter out, AccessPoint value, boolean exportAll) throws IOException {
119 |
120 | if(value.moveGuard() != 0) { // Don't export suspect (moved/moving) APs
121 | return;
122 | }
123 |
124 | final String rfId = value.rfId();
125 | String ssid = "";
126 |
127 | if(!TextUtils.isEmpty(value.ssid())) {
128 | ssid = value.ssid();
129 | }
130 |
131 | for(SimpleLocation sample : value.samples()) {
132 | if (exportAll || sample.changed()) {
133 | out.writeNext(new String[]{rfId,
134 | Double.toString(sample.latitude()),
135 | Double.toString(sample.longitude()),
136 | ssid});
137 | }
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/data/ImportSpiceRequest.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Context;
22 | import android.database.Cursor;
23 | import android.net.Uri;
24 | import android.provider.OpenableColumns;
25 | import android.util.Log;
26 |
27 | import com.octo.android.robospice.request.SpiceRequest;
28 | import com.opencsv.CSVReader;
29 |
30 | import org.fitchfamily.android.wifi_backend.BuildConfig;
31 | import org.fitchfamily.android.wifi_backend.data.util.CountingInputStream;
32 | import org.fitchfamily.android.wifi_backend.database.Database;
33 | import org.fitchfamily.android.wifi_backend.database.SamplerDatabase;
34 | import org.fitchfamily.android.wifi_backend.util.SimpleLocation;
35 |
36 | import java.io.IOException;
37 | import java.io.InputStream;
38 | import java.io.InputStreamReader;
39 |
40 | public class ImportSpiceRequest extends SpiceRequest {
41 | public static final String TAG = "WiFiBackendImport";
42 | private static final boolean DEBUG = BuildConfig.DEBUG;
43 | public static final int MAX_PROGRESS = 1000;
44 |
45 | private final Context context;
46 | private final Uri uri;
47 |
48 | public abstract static class Result {
49 |
50 | }
51 |
52 | public ImportSpiceRequest(Context context, Uri uri) {
53 | super(Result.class);
54 | this.context = context.getApplicationContext();
55 | this.uri = uri;
56 | }
57 |
58 | @Override
59 | public Result loadDataFromNetwork() throws Exception {
60 | long entryTime = System.currentTimeMillis();
61 | int recCount = 0;
62 |
63 | final long size = getFileSize(uri, context);
64 |
65 | InputStream inputStream = context.getContentResolver().openInputStream(uri);
66 |
67 | if(inputStream == null) {
68 | throw new IOException();
69 | }
70 |
71 | CountingInputStream countingInputStream = new CountingInputStream(inputStream);
72 | SamplerDatabase database = SamplerDatabase.getInstance(context);
73 |
74 | try {
75 | CSVReader reader = new CSVReader(new InputStreamReader(countingInputStream, "UTF-8"));
76 | final String[] headerLine = reader.readNext();
77 | if (headerLine == null) {
78 | throw new IOException();
79 | }
80 |
81 | int bssidIndex = -1;
82 | int latIndex = -1;
83 | int lonIndex = -1;
84 | int ssidIndex = -1;
85 | int idx = 0;
86 | for (String s : headerLine) {
87 | if (s.equals("bssid"))
88 | bssidIndex = idx;
89 | else if (s.equals("lat"))
90 | latIndex = idx;
91 | else if (s.equals("lon"))
92 | lonIndex = idx;
93 | else if (s.equals("ssid"))
94 | ssidIndex = idx;
95 | idx++;
96 | }
97 | Log.i(TAG, "bssidIndex=" + bssidIndex +
98 | ", latIndex=" + latIndex +
99 | ", lonIndex=" + lonIndex +
100 | ", ssidIndex=" + ssidIndex);
101 | if ((bssidIndex < 0) || (latIndex < 0) || (lonIndex < 0)) {
102 | throw new IOException();
103 | }
104 | String[] nextLine;
105 |
106 | database.beginTransaction();
107 | while ((nextLine = reader.readNext()) != null) {
108 | String rfId = nextLine[bssidIndex];
109 | String latString = nextLine[latIndex];
110 | String lonString = nextLine[lonIndex];
111 | String ssid = "";
112 | if (ssidIndex >= 0)
113 | ssid = nextLine[ssidIndex];
114 |
115 | database.addSample(Database.TYPE_WIFI, ssid, rfId, SimpleLocation.fromLatLon(latString,lonString,false));
116 | recCount++;
117 | if ((recCount % 100) == 0) {
118 | // Log.i(TAG, "recCount="+recCount+", committing transaction.");
119 | database.commitTransaction();
120 | database.beginTransaction();
121 | }
122 |
123 | if (size != 0) {
124 | publishProgress(countingInputStream.getBytesRead() * MAX_PROGRESS / size);
125 | }
126 | }
127 | } catch (Exception e) {
128 | Log.i(TAG, e.toString());
129 | e.printStackTrace();
130 | } finally {
131 | inputStream.close();
132 | database.commitTransaction();
133 | }
134 | Log.i(TAG, "Total Records processed: " + recCount);
135 | Log.i(TAG, "Import data elapsed time: " + (System.currentTimeMillis() - entryTime) + " ms");
136 |
137 | return null;
138 | }
139 |
140 | private static int getFileSize(Uri uri, Context context) {
141 | Cursor cursor = context.getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null);
142 |
143 | try {
144 | if(cursor != null && cursor.moveToFirst() && !cursor.isNull(0)) {
145 | return cursor.getInt(0);
146 | }
147 | } finally {
148 | if(cursor != null) {
149 | cursor.close();
150 | }
151 | }
152 |
153 | return 0;
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/data/ResetSpiceRequest.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Context;
22 |
23 | import com.octo.android.robospice.request.SpiceRequest;
24 |
25 | import org.fitchfamily.android.wifi_backend.database.SamplerDatabase;
26 |
27 | public class ResetSpiceRequest extends SpiceRequest {
28 | public static final String TAG = "WiFiBackendReset";
29 |
30 | private final Context context;
31 |
32 | public abstract static class Result {
33 | // nothing
34 | }
35 |
36 | public ResetSpiceRequest(Context context) {
37 | super(Result.class);
38 | this.context = context.getApplicationContext();
39 | }
40 |
41 | @Override
42 | public Result loadDataFromNetwork() throws Exception {
43 | SamplerDatabase.getInstance(context).dropAll();
44 |
45 | return null;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/database/AccessPoint.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.database;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.support.annotation.Nullable;
22 | import android.util.Log;
23 |
24 | import com.google.auto.value.AutoValue;
25 | import com.google.common.collect.ImmutableList;
26 |
27 | import org.fitchfamily.android.wifi_backend.BuildConfig;
28 | import org.fitchfamily.android.wifi_backend.util.SimpleLocation;
29 |
30 | import java.util.ArrayList;
31 | import java.util.List;
32 |
33 | @AutoValue
34 | public abstract class AccessPoint {
35 | private static final int MIN_SAMPLES = 3;
36 | private static final String TAG = "WiFiBackendAP";
37 | private static final boolean DEBUG = BuildConfig.DEBUG;
38 |
39 | AccessPoint() {
40 |
41 | }
42 |
43 | public static String bssid(String bssid) {
44 | return bssid.replace(":", "");
45 | }
46 |
47 | public static String readableBssid(String bssid) {
48 | return bssid(bssid).replaceAll(".(?!$).(?!$)", "$0:");
49 | }
50 |
51 | public static Builder builder() {
52 | return new AutoValue_AccessPoint.Builder();
53 | }
54 |
55 | public abstract String rfId();
56 | @Nullable
57 | public abstract String ssid();
58 | public abstract ImmutableList samples();
59 | public abstract int moveGuard();
60 | public abstract int rfType();
61 |
62 | public SimpleLocation sample(int index) {
63 | if(index < samples().size()) {
64 | return samples().get(index);
65 | } else {
66 | return null;
67 | }
68 | }
69 |
70 | /**
71 | * Use this function to get the estimate location
72 | * @return the estimate location or null if no samples are available
73 | */
74 | public SimpleLocation estimateLocation() {
75 | if(samples().size() == 0) {
76 | return null;
77 | }
78 |
79 | // get center of points
80 |
81 | double latitude = 0.0;
82 | double longitude = 0.0;
83 |
84 | for(SimpleLocation sample : samples()) {
85 | latitude += sample.latitude();
86 | longitude += sample.longitude();
87 | }
88 |
89 | latitude /= (double) samples().size();
90 | longitude /= (double) samples().size();
91 |
92 | SimpleLocation center = SimpleLocation.builder()
93 | .latitude(latitude)
94 | .longitude(longitude)
95 | .radius(-1.0f)
96 | .changed(false)
97 | .build();
98 |
99 | // get biggest distance
100 |
101 | float radius = 0.0f;
102 |
103 | for(SimpleLocation sample : samples()) {
104 | radius = Math.max(radius, center.distanceTo(sample));
105 | }
106 |
107 |
108 | return SimpleLocation.builder()
109 | .latitude(latitude)
110 | .longitude(longitude)
111 | .radius(radius)
112 | .changed(false)
113 | .build();
114 | }
115 |
116 | public abstract Builder buildUpon();
117 |
118 | private static float perimeter(List samples) {
119 | float result = 0.0f;
120 |
121 | for (SimpleLocation sample1 : samples) {
122 | for (SimpleLocation sample2 : samples) {
123 | result += sample1.distanceTo(sample2);
124 | }
125 | }
126 |
127 | return result;
128 | }
129 |
130 | public float perimeter() {
131 | return perimeter(samples());
132 | }
133 |
134 | @AutoValue.Builder
135 | public abstract static class Builder {
136 | public abstract Builder rfId(String rfId);
137 | public abstract Builder ssid(String ssid);
138 | public abstract Builder samples(List samples);
139 | public abstract Builder moveGuard(int moveGuard);
140 | public abstract Builder rfType(int rfType);
141 | public abstract AccessPoint build();
142 |
143 | protected abstract String rfId();
144 | protected abstract int moveGuard();
145 | protected abstract ImmutableList samples();
146 | protected abstract int rfType();
147 |
148 | protected int samplesCount() {
149 | try {
150 | return samples().size();
151 | } catch (Exception ex) {
152 | return 0;
153 | }
154 | }
155 |
156 | public Builder moved(int movedGuardCount) {
157 | return moveGuard(movedGuardCount);
158 | }
159 |
160 | public Builder decMoved() {
161 | return moveGuard(Math.max(0, moveGuard()));
162 | }
163 |
164 | public Builder addSample(SimpleLocation location) {
165 | return addSample(location, MIN_SAMPLES);
166 | }
167 |
168 | public Builder addSample(SimpleLocation location, int maxSamples) {
169 | maxSamples = Math.max(maxSamples, MIN_SAMPLES);
170 |
171 | if(samplesCount() < maxSamples) {
172 | List samples = new ArrayList<>();
173 |
174 | if(samplesCount() != 0) {
175 | samples.addAll(samples());
176 | }
177 |
178 | samples.add(location);
179 | if (DEBUG) {
180 | Log.i(TAG, "Simple add to " + rfId() + ", add " + location + ", result="+samples);
181 | }
182 |
183 | return samples(samples);
184 | } else {
185 | // We will take the new sample an see if we can make a triangle with
186 | // a larger perimeter by replacing one of our current samples with
187 | // the new one.
188 |
189 | List bestSamples = samples();
190 | float bestPerimeter = perimeter(bestSamples);
191 |
192 | for (int i = 0; i < samples().size(); i++) {
193 | List samples = new ArrayList(samples());
194 | samples.set(i, location);
195 |
196 | float guessPerimeter = perimeter(samples);
197 |
198 | if (guessPerimeter > bestPerimeter) {
199 | bestSamples = samples;
200 | bestPerimeter = guessPerimeter;
201 |
202 | if (DEBUG) {
203 | Log.i(TAG, "Better perimeter point found on " + rfId() + ", i=" + i);
204 | }
205 | }
206 | }
207 |
208 | return samples(bestSamples);
209 | }
210 | }
211 |
212 | public Builder clearSamples() {
213 | return samples(new ArrayList());
214 | }
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/database/SamplerDatabase.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.database;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Context;
22 | import android.util.Log;
23 |
24 | import org.fitchfamily.android.wifi_backend.BuildConfig;
25 | import org.fitchfamily.android.wifi_backend.Configuration;
26 | import org.fitchfamily.android.wifi_backend.util.SimpleLocation;
27 |
28 | import java.io.File;
29 |
30 | /*
31 | * We estimate the AP location by keeping three samples that form a triangle.
32 | * Our best guess for the AP location is then the average of the lat/lon values
33 | * for each triangle vertice.
34 | *
35 | * We select the samples that form the triangle by trying to maximize the
36 | * perimeter distance.
37 | *
38 | * Field naming conventions are:
39 | * rfid - ID for RF source. For WiFi this is
40 | * the MAC address of the AP
41 | * type - Type of RF source:
42 | * 0 - WiFi AP
43 | * 1 - Mobile/Cell Tower
44 | * latitude - Latitude estimate for the RF source
45 | * longitude - Longitude estimate for the RF source
46 | * move_guard - Count down of times to ignore moved wifi AP
47 | * radius - Estimated coverage radius of RF source
48 | * lat1 - Latitude measure for sample 1
49 | * lon1 - Longitude measure for sample 1
50 | * lat2 - Latitude measure for sample 2
51 | * lon2 - Longitude measure for sample 2
52 | * lat3 - Latitude measure for sample 3
53 | * lon3 - Longitude measure for sample 3
54 | */
55 | public class SamplerDatabase extends Database {
56 | private final static String TAG = "WiFiBackendSamplerDB";
57 | private static final boolean DEBUG = BuildConfig.DEBUG;
58 |
59 | private static SamplerDatabase mInstance;
60 | private final Context context;
61 |
62 | private SamplerDatabase(Context context) {
63 | super(context);
64 |
65 | this.context = context;
66 |
67 | if (DEBUG) {
68 | Log.i(TAG, "samplerDatabase.samplerDatabase()");
69 | }
70 | }
71 |
72 | public synchronized static SamplerDatabase getInstance(Context context) {
73 | if (mInstance == null) {
74 | final File oldFile = new File(context.getFilesDir(), "wifi.db");
75 | final File newFile = context.getDatabasePath("wifi.db");
76 |
77 | if(oldFile.exists()) {
78 | newFile.delete();
79 | oldFile.renameTo(newFile);
80 | }
81 |
82 | mInstance = new SamplerDatabase(context);
83 | }
84 |
85 | return mInstance;
86 | }
87 |
88 | public void addSample(int rfType, String ssid, String rfId, SimpleLocation sampleLocation) {
89 | final long entryTime = System.currentTimeMillis();
90 |
91 | if (DEBUG) {
92 | Log.i(TAG,"ID="+rfId+": Adding location="+sampleLocation.toString());
93 | }
94 | AccessPoint accessPoint = query(rfId);
95 |
96 | if (accessPoint != null) {
97 | // We attempt to estimate the position of the AP by making as
98 | // large a triangle around it as possible.
99 | // At this point we have the specified amount of points already
100 | // in the database describing a triangle.
101 |
102 | float diff = accessPoint.estimateLocation().distanceTo(sampleLocation);
103 |
104 | if (diff >= Configuration.with(context).accessPointMoveThresholdInMeters()) {
105 | accessPoint = accessPoint.buildUpon()
106 | .ssid(ssid)
107 | .clearSamples()
108 | .addSample(sampleLocation)
109 | .moved(Configuration.with(context).accessPointMoveGuardSampleCount())
110 | .build();
111 |
112 | if (DEBUG) {
113 | Log.i(TAG, "Sample is " + diff + " from AP, assume AP " + accessPoint.rfId() + " has moved.");
114 | }
115 | } else {
116 | accessPoint = accessPoint.buildUpon()
117 | .ssid(ssid)
118 | .decMoved()
119 | .addSample(sampleLocation)
120 | .build();
121 | }
122 |
123 | if (DEBUG) {
124 | Log.i(TAG, "Sample: " + accessPoint.toString());
125 | }
126 |
127 | update(accessPoint);
128 | } else {
129 | insert(
130 | AccessPoint.builder()
131 | .ssid(ssid)
132 | .rfId(AccessPoint.bssid(rfId))
133 | .moveGuard(0)
134 | .addSample(sampleLocation)
135 | .rfType(rfType)
136 | .build()
137 | );
138 | }
139 |
140 | if (DEBUG) {
141 | Log.i(TAG,"addSample time: "+ (System.currentTimeMillis() - entryTime) + " ms");
142 | }
143 | }
144 |
145 | public SamplerDatabase dropAccessPoint(String rfId) {
146 | dropAP(rfId);
147 |
148 | return this;
149 | }
150 |
151 | public SamplerDatabase dropAll() {
152 | dropAllAPs();
153 |
154 | return this;
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/AdvancedSettingsFragment.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | import com.github.machinarius.preferencefragment.PreferenceFragment;
21 |
22 | import org.androidannotations.annotations.EFragment;
23 | import org.androidannotations.annotations.PreferenceScreen;
24 | import org.fitchfamily.android.wifi_backend.R;
25 |
26 | @EFragment
27 | @PreferenceScreen(R.xml.advanced)
28 | public class AdvancedSettingsFragment extends PreferenceFragment {
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/BaseDialogFragment.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.support.v4.app.DialogFragment;
22 |
23 | import com.octo.android.robospice.SpiceManager;
24 |
25 | import org.fitchfamily.android.wifi_backend.SpiceService;
26 |
27 | public abstract class BaseDialogFragment extends DialogFragment {
28 | private SpiceManager spiceManager = new SpiceManager(SpiceService.class);
29 |
30 | @Override
31 | public void onStart() {
32 | super.onStart();
33 | spiceManager.start(getActivity());
34 | }
35 |
36 | @Override
37 | public void onStop() {
38 | super.onStop();
39 | spiceManager.shouldStop();
40 | }
41 |
42 | public SpiceManager getSpiceManager() {
43 | return spiceManager;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/EditTextPreference.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Context;
22 | import android.util.AttributeSet;
23 |
24 | public class EditTextPreference extends android.preference.EditTextPreference {
25 | public EditTextPreference(Context context) {
26 | super(context);
27 | }
28 |
29 | public EditTextPreference(Context context, AttributeSet attributeSet) {
30 | super(context, attributeSet);
31 | }
32 |
33 | @Override
34 | public void setText(String text) {
35 | super.setText(text);
36 | notifyChanged();
37 | }
38 |
39 | @Override
40 | public CharSequence getSummary() {
41 | final CharSequence summary = super.getSummary();
42 |
43 | if (summary == null) {
44 | return null;
45 | } else {
46 | return String.format(summary.toString(), getText());
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Intent;
22 | import android.net.Uri;
23 | import android.os.Bundle;
24 | import android.support.v4.app.Fragment;
25 | import android.support.v7.app.AppCompatActivity;
26 | import android.support.v7.widget.Toolbar;
27 | import android.view.View;
28 |
29 | import com.mikepenz.aboutlibraries.Libs;
30 | import com.mikepenz.aboutlibraries.LibsBuilder;
31 | import com.mikepenz.google_material_typeface_library.GoogleMaterial;
32 | import com.mikepenz.materialdrawer.Drawer;
33 | import com.mikepenz.materialdrawer.DrawerBuilder;
34 | import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
35 | import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
36 |
37 | import org.androidannotations.annotations.AfterViews;
38 | import org.androidannotations.annotations.EActivity;
39 | import org.androidannotations.annotations.Extra;
40 | import org.androidannotations.annotations.InstanceState;
41 | import org.androidannotations.annotations.ViewById;
42 | import org.fitchfamily.android.wifi_backend.Constants;
43 | import org.fitchfamily.android.wifi_backend.R;
44 |
45 | @EActivity(R.layout.activity_main)
46 | public class MainActivity extends AppCompatActivity {
47 | private static final int SETTINGS = 1;
48 | private static final int ADVANCED = 2;
49 | private static final int LIBRARIES = 3;
50 | private static final int WEBSITE = 4;
51 |
52 | @Extra
53 | protected Action action;
54 |
55 | @ViewById
56 | protected Toolbar toolbar;
57 |
58 | @InstanceState
59 | protected Bundle drawerState;
60 |
61 | private Drawer drawer;
62 |
63 | @AfterViews
64 | protected void init() {
65 | toolbar.setTitle(R.string.app_title);
66 |
67 | drawer = new DrawerBuilder()
68 | .withActivity(this)
69 | .withToolbar(toolbar)
70 | .withFireOnInitialOnClick(drawerState == null)
71 | .withSavedInstance(drawerState)
72 | .addDrawerItems(
73 | new PrimaryDrawerItem()
74 | .withName(R.string.drawer_settings)
75 | .withIcon(GoogleMaterial.Icon.gmd_settings)
76 | .withIdentifier(SETTINGS),
77 |
78 | new PrimaryDrawerItem()
79 | .withName(R.string.drawer_advanced)
80 | .withIcon(GoogleMaterial.Icon.gmd_settings_applications)
81 | .withIdentifier(ADVANCED)
82 | )
83 | .addStickyDrawerItems(
84 | new PrimaryDrawerItem()
85 | .withName(R.string.drawer_libraries)
86 | .withIcon(GoogleMaterial.Icon.gmd_info_outline)
87 | .withSelectable(false)
88 | .withIdentifier(LIBRARIES),
89 |
90 | new PrimaryDrawerItem()
91 | .withName(R.string.drawer_website)
92 | .withIcon(GoogleMaterial.Icon.gmd_info)
93 | .withSelectable(false)
94 | .withIdentifier(WEBSITE)
95 | )
96 | .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
97 | @Override
98 | public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
99 | if (drawerItem != null) {
100 | final int id = drawerItem.getIdentifier();
101 |
102 | if(id == SETTINGS) {
103 | setFragment(new MainSettingsFragment_());
104 | } else if (id == ADVANCED) {
105 | setFragment(new AdvancedSettingsFragment_());
106 | } else if (id == LIBRARIES) {
107 | new LibsBuilder()
108 | .withFields(R.string.class.getFields())
109 | .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
110 | .start(MainActivity.this);
111 | } else if (id == WEBSITE) {
112 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.WEBSITE)));
113 | }
114 | }
115 |
116 | return false;
117 | }
118 | })
119 | .build();
120 |
121 | updateTitle();
122 |
123 | if(action == Action.request_permission) {
124 | drawer.setSelection(SETTINGS);
125 | }
126 | }
127 |
128 | @Override
129 | public void onSaveInstanceState(Bundle outState) {
130 | drawer.saveInstanceState(drawerState = new Bundle());
131 | super.onSaveInstanceState(outState);
132 | }
133 |
134 | private void setFragment(Fragment fragment) {
135 | getSupportFragmentManager().beginTransaction()
136 | .replace(R.id.container, fragment)
137 | .commit();
138 |
139 | updateTitle();
140 | }
141 |
142 | private void updateTitle() {
143 | IDrawerItem item = drawer == null ? null : drawer.getDrawerItem(drawer.getCurrentSelection());
144 |
145 | if (item != null && item instanceof PrimaryDrawerItem) {
146 | toolbar.setSubtitle(((PrimaryDrawerItem) item).getName().getText(this));
147 | } else {
148 | toolbar.setSubtitle(null);
149 | }
150 | }
151 |
152 | @Override
153 | public void onBackPressed() {
154 | if(drawer != null && drawer.isDrawerOpen()) {
155 | drawer.closeDrawer();
156 | } else {
157 | super.onBackPressed();
158 | }
159 | }
160 |
161 | public enum Action {
162 | request_permission
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/CursorAdapter.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.database.Cursor;
22 | import android.support.annotation.NonNull;
23 | import android.support.v7.widget.RecyclerView;
24 |
25 | public abstract class CursorAdapter extends RecyclerView.Adapter {
26 | private Cursor cursor;
27 |
28 | protected void onCursorChanged(@NonNull Cursor cursor) {
29 | }
30 |
31 | @Override
32 | public int getItemCount() {
33 | return cursor == null ? 0 : cursor.getCount();
34 | }
35 |
36 | public void swap(Cursor cursor) {
37 | this.cursor = cursor;
38 |
39 | if(cursor != null) {
40 | onCursorChanged(cursor);
41 | }
42 |
43 | notifyDataSetChanged();
44 | }
45 |
46 | @Override
47 | public void onBindViewHolder(VH holder, int position) {
48 | bind(holder, getItem(position));
49 | }
50 |
51 | public abstract void bind(VH holder, Cursor cursor);
52 |
53 | public Cursor getItem(int position) {
54 | cursor.moveToPosition(position);
55 | return cursor;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/CursorLoader.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.BroadcastReceiver;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.content.IntentFilter;
25 | import android.database.Cursor;
26 | import android.support.v4.content.AsyncTaskLoader;
27 | import android.support.v4.content.LocalBroadcastManager;
28 |
29 | import org.fitchfamily.android.wifi_backend.database.SamplerDatabase;
30 |
31 | public class CursorLoader extends AsyncTaskLoader {
32 | private String table;
33 | private String[] columns;
34 | private String selection;
35 | private String[] selectionArgs;
36 | private String sortOrder;
37 | private Cursor cursor;
38 | private BroadcastReceiver changeReceiver;
39 |
40 | public CursorLoader(Context context) {
41 | super(context);
42 | }
43 |
44 | @Override
45 | public Cursor loadInBackground() {
46 | return SamplerDatabase.getInstance(getContext()).getReadableDatabase().query(table, columns, selection, selectionArgs, null, null, sortOrder);
47 | }
48 |
49 | @Override
50 | protected void onStartLoading() {
51 | super.onStartLoading();
52 |
53 | if(changeReceiver == null) {
54 | changeReceiver = new BroadcastReceiver() {
55 | @Override
56 | public void onReceive(Context context, Intent intent) {
57 | onContentChanged();
58 | }
59 | };
60 |
61 | LocalBroadcastManager.getInstance(getContext()).registerReceiver(changeReceiver, new IntentFilter(SamplerDatabase.ACTION_DATA_CHANGED));
62 | }
63 |
64 | if (cursor != null) {
65 | // deliver old data (if available)
66 | deliverResult(cursor);
67 | }
68 |
69 | forceLoad();
70 | }
71 |
72 | @Override
73 | protected void onStopLoading() {
74 | super.deliverResult(null);
75 | super.onStopLoading();
76 | cancelLoad();
77 | }
78 |
79 | @Override
80 | protected void onReset() {
81 | super.onReset();
82 |
83 | LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(changeReceiver);
84 | changeReceiver = null;
85 |
86 | // stop loader
87 | onStopLoading();
88 |
89 | if (cursor != null && !cursor.isClosed()) {
90 | cursor.close();
91 | }
92 |
93 | cursor = null;
94 | }
95 |
96 | @Override
97 | public void deliverResult(Cursor cursor) {
98 | if (isReset()) {
99 | if (cursor != null) {
100 | cursor.close();
101 | }
102 | } else {
103 | Cursor oldCursor = this.cursor;
104 | this.cursor = cursor;
105 |
106 | if (isStarted()) {
107 | super.deliverResult(cursor);
108 | }
109 |
110 | if (oldCursor != null && !oldCursor.isClosed()) {
111 | oldCursor.close();
112 | }
113 | }
114 | }
115 |
116 | @Override
117 | public void onCanceled(Cursor cursor) {
118 | super.onCanceled(cursor);
119 |
120 | if (cursor != null && !cursor.isClosed()) {
121 | cursor.close();
122 | }
123 | }
124 |
125 | public String table() {
126 | return table;
127 | }
128 |
129 | public CursorLoader table(String table) {
130 | this.table = table;
131 | return this;
132 | }
133 |
134 | public String[] columns() {
135 | return columns;
136 | }
137 |
138 | public CursorLoader columns(String[] columns) {
139 | this.columns = columns;
140 | return this;
141 | }
142 |
143 | public String selection() {
144 | return selection;
145 | }
146 |
147 | public CursorLoader selection(String selection) {
148 | this.selection = selection;
149 | return this;
150 | }
151 |
152 | public String[] selectionArgs() {
153 | return selectionArgs;
154 | }
155 |
156 | public CursorLoader selectionArgs(String[] selectionArgs) {
157 | this.selectionArgs = selectionArgs;
158 | return this;
159 | }
160 |
161 | public String sortOrder() {
162 | return sortOrder;
163 | }
164 |
165 | public CursorLoader sortOrder(String sortOrder) {
166 | this.sortOrder = sortOrder;
167 | return this;
168 | }
169 |
170 | public CursorLoader load() {
171 | forceLoad();
172 | return this;
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/WifiDetailActivity.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Intent;
22 | import android.database.Cursor;
23 | import android.os.Bundle;
24 | import android.support.v4.app.LoaderManager;
25 | import android.support.v4.content.Loader;
26 | import android.support.v7.app.ActionBar;
27 | import android.support.v7.app.AppCompatActivity;
28 | import android.support.v7.widget.Toolbar;
29 | import android.view.MenuItem;
30 |
31 | import org.androidannotations.annotations.AfterViews;
32 | import org.androidannotations.annotations.EActivity;
33 | import org.androidannotations.annotations.Extra;
34 | import org.androidannotations.annotations.InstanceState;
35 | import org.androidannotations.annotations.ViewById;
36 | import org.fitchfamily.android.wifi_backend.R;
37 | import org.fitchfamily.android.wifi_backend.database.AccessPoint;
38 | import org.fitchfamily.android.wifi_backend.database.Database;
39 |
40 | /**
41 | * An activity representing a single WiFi detail screen. This
42 | * activity is only used narrow width devices. On tablet-size devices,
43 | * item details are presented side-by-side with a list of items
44 | * in a {@link WifiListActivity}.
45 | */
46 | @EActivity(R.layout.activity_wifi_detail)
47 | public class WifiDetailActivity extends AppCompatActivity {
48 | @ViewById
49 | protected Toolbar toolbar;
50 |
51 | @Extra
52 | protected String rfId;
53 |
54 | @InstanceState
55 | protected boolean initialized;
56 |
57 | @AfterViews
58 | protected void init() {
59 | setSupportActionBar(toolbar);
60 |
61 | // Show the Up button in the action bar.
62 | ActionBar actionBar = getSupportActionBar();
63 | if (actionBar != null) {
64 | actionBar.setDisplayHomeAsUpEnabled(true);
65 | }
66 |
67 | // savedInstanceState is non-null when there is fragment state
68 | // saved from previous configurations of this activity
69 | // (e.g. when rotating the screen from portrait to landscape).
70 | // In this case, the fragment will automatically be re-added
71 | // to its container so we don't need to manually add it.
72 | // For more information, see the Fragments API guide at:
73 | //
74 | // http://developer.android.com/guide/components/fragments.html
75 | //
76 | if (!initialized) {
77 | // Create the detail fragment and add it to the activity
78 | // using a fragment transaction.
79 | getSupportFragmentManager().beginTransaction()
80 | .replace(
81 | R.id.container,
82 | WifiDetailFragment_.builder()
83 | .rfId(rfId)
84 | .build()
85 | )
86 | .commit();
87 |
88 | initialized = true;
89 | }
90 |
91 | getSupportLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks() {
92 | @Override
93 | public Loader onCreateLoader(int id, Bundle args) {
94 | return new CursorLoader(WifiDetailActivity.this)
95 | .table(Database.TABLE_SAMPLES)
96 | .columns(new String[]{Database.COL_SSID})
97 | .selection(Database.COL_RFID + " = ?")
98 | .selectionArgs(new String[]{rfId});
99 | }
100 |
101 | @Override
102 | public void onLoadFinished(Loader loader, Cursor data) {
103 | if(data != null && data.moveToFirst()) {
104 | getSupportActionBar().setTitle(data.getString(0));
105 | getSupportActionBar().setSubtitle(AccessPoint.readableBssid(rfId));
106 | } else {
107 | getSupportActionBar().setTitle(AccessPoint.readableBssid(rfId));
108 | getSupportActionBar().setSubtitle(null);
109 | }
110 | }
111 |
112 | @Override
113 | public void onLoaderReset(Loader loader) {
114 | getSupportActionBar().setTitle(rfId);
115 | getSupportActionBar().setSubtitle(null);
116 | }
117 | });
118 | }
119 |
120 | @Override
121 | public boolean onOptionsItemSelected(MenuItem item) {
122 | final int id = item.getItemId();
123 |
124 | if (id == android.R.id.home) {
125 | // This ID represents the Home or Up button. In the case of this
126 | // activity, the Up button is shown. For
127 | // more details, see the Navigation pattern on Android Design:
128 | //
129 | // http://developer.android.com/design/patterns/navigation.html#up-vs-back
130 | //
131 | navigateUpTo(new Intent(this, WifiListActivity_.class));
132 | return true;
133 | }
134 |
135 | return super.onOptionsItemSelected(item);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/WifiDetailFragment.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.Intent;
22 | import android.database.Cursor;
23 | import android.net.Uri;
24 | import android.os.Bundle;
25 | import android.support.v4.app.Fragment;
26 | import android.support.v4.app.LoaderManager;
27 | import android.support.v4.content.Loader;
28 | import android.view.View;
29 | import android.widget.TextView;
30 |
31 | import org.androidannotations.annotations.AfterViews;
32 | import org.androidannotations.annotations.Click;
33 | import org.androidannotations.annotations.EFragment;
34 | import org.androidannotations.annotations.FragmentArg;
35 | import org.androidannotations.annotations.ViewById;
36 | import org.fitchfamily.android.wifi_backend.Configuration;
37 | import org.fitchfamily.android.wifi_backend.R;
38 | import org.fitchfamily.android.wifi_backend.database.Database;
39 |
40 | /**
41 | * A fragment representing a single WiFi detail screen.
42 | * This fragment is either contained in a {@link WifiListActivity}
43 | * in two-pane mode (on tablets) or a {@link WifiDetailActivity}
44 | * on handsets.
45 | */
46 | @EFragment(R.layout.wifi_detail)
47 | public class WifiDetailFragment extends Fragment {
48 | @FragmentArg
49 | protected String rfId;
50 |
51 | @ViewById
52 | protected TextView accuracy;
53 |
54 | @ViewById
55 | protected View container;
56 |
57 | @ViewById
58 | protected TextView samples;
59 |
60 | private double lat, lon, acc;
61 | private int smp;
62 | private String ssid;
63 |
64 | @AfterViews
65 | protected void init() {
66 | container.setVisibility(View.INVISIBLE);
67 |
68 | getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks() {
69 | @Override
70 | public Loader onCreateLoader(int id, Bundle args) {
71 | return new CursorLoader(getContext())
72 | .table(Database.TABLE_SAMPLES)
73 | .selection(Database.COL_RFID + " = ?")
74 | .selectionArgs(new String[]{rfId})
75 | .columns(new String[]{
76 | Database.COL_LATITUDE,
77 | Database.COL_LONGITUDE,
78 | Database.COL_RADIUS,
79 | Database.COL_SSID,
80 | Database.COL_LAT1,
81 | Database.COL_LON1,
82 | Database.COL_LAT2,
83 | Database.COL_LON2,
84 | Database.COL_LAT3,
85 | Database.COL_LON3
86 | });
87 | }
88 |
89 | @Override
90 | public void onLoadFinished(Loader loader, Cursor cursor) {
91 | if (cursor != null && cursor.moveToFirst()) {
92 | container.setVisibility(View.VISIBLE);
93 |
94 | lat = cursor.getDouble(0);
95 | lon = cursor.getDouble(1);
96 | acc = Math.max(Configuration.with(getContext()).accessPointAssumedAccuracy(), cursor.getFloat(2));
97 | ssid = cursor.getString(3);
98 | smp = countSamples(cursor, 4);
99 |
100 | WifiDetailFragment.this.accuracy.setText(accuracy());
101 | WifiDetailFragment.this.samples.setText(samples());
102 | } else {
103 | container.setVisibility(View.INVISIBLE);
104 | }
105 | }
106 |
107 | @Override
108 | public void onLoaderReset(Loader loader) {
109 | container.setVisibility(View.INVISIBLE);
110 | }
111 | });
112 | }
113 |
114 | private static boolean hasSample(Cursor cursor, int index) {
115 | return cursor.getDouble(index) != 0.d || cursor.getDouble(index + 1) != 0.d;
116 | }
117 |
118 | private static int countSamples(Cursor cursor, int index) {
119 | int result = 0;
120 |
121 | for(int i = 0; i < 3; i++) {
122 | if(hasSample(cursor, index + (i * 2))) {
123 | result++;
124 | }
125 | }
126 |
127 | return result;
128 | }
129 |
130 | private String accuracy() {
131 | return getString(R.string.wifi_detail_accuracy, getString(R.string.pref_meters, String.valueOf((int) acc)));
132 | }
133 |
134 | private String samples() {
135 | return getString(R.string.pref_samples, String.valueOf(smp));
136 | }
137 |
138 | @Click
139 | protected void map() {
140 | startActivity(new Intent(android.content.Intent.ACTION_VIEW,
141 | Uri.parse("geo:" + lat + "," + lon + "?q=" + lat + "," + lon)
142 | ));
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/WifiListActivity.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.database.Cursor;
22 | import android.os.Bundle;
23 | import android.support.v4.app.LoaderManager;
24 | import android.support.v4.app.NavUtils;
25 | import android.support.v4.content.Loader;
26 | import android.support.v7.app.ActionBar;
27 | import android.support.v7.app.AppCompatActivity;
28 | import android.support.v7.widget.RecyclerView;
29 | import android.support.v7.widget.Toolbar;
30 | import android.text.TextUtils;
31 | import android.view.MenuItem;
32 | import android.widget.EditText;
33 |
34 | import org.androidannotations.annotations.AfterViews;
35 | import org.androidannotations.annotations.EActivity;
36 | import org.androidannotations.annotations.TextChange;
37 | import org.androidannotations.annotations.ViewById;
38 | import org.fitchfamily.android.wifi_backend.Configuration;
39 | import org.fitchfamily.android.wifi_backend.R;
40 | import org.fitchfamily.android.wifi_backend.database.Database;
41 |
42 | import java.util.ArrayList;
43 | import java.util.List;
44 |
45 | /**
46 | * An activity representing a list of WiFis. This activity
47 | * has different presentations for handset and tablet-size devices. On
48 | * handsets, the activity presents a list of items, which when touched,
49 | * lead to a {@link WifiDetailActivity} representing
50 | * item details. On tablets, the activity presents the list of items and
51 | * item details side-by-side using two vertical panes.
52 | */
53 | @EActivity(R.layout.activity_wifi_list)
54 | public class WifiListActivity extends AppCompatActivity {
55 | private static final int LOADER_ID = 0;
56 |
57 | /**
58 | * Whether or not the activity is in two-pane mode, i.e. running on a tablet
59 | * device.
60 | */
61 | private boolean twoPane;
62 |
63 | @ViewById(R.id.wifi_list)
64 | protected RecyclerView recyclerView;
65 |
66 | @ViewById
67 | protected Toolbar toolbar;
68 |
69 | @ViewById
70 | EditText searchTerm;
71 |
72 | private WifiListAdapter adapter = new WifiListAdapter().listener(new WifiListAdapter.Listener() {
73 | @Override
74 | public void onWifiClicked(String rfId) {
75 | if (twoPane) {
76 | getSupportFragmentManager().beginTransaction()
77 | .replace(
78 | R.id.wifi_detail_container,
79 | WifiDetailFragment_.builder()
80 | .rfId(rfId)
81 | .build()
82 | )
83 | .commit();
84 | } else {
85 | WifiDetailActivity_.intent(WifiListActivity.this)
86 | .rfId(rfId)
87 | .start();
88 | }
89 | }
90 | });
91 |
92 | @AfterViews
93 | protected void init() {
94 | setSupportActionBar(toolbar);
95 |
96 | // Show the Up button in the action bar.
97 | ActionBar actionBar = getSupportActionBar();
98 | if (actionBar != null) {
99 | actionBar.setDisplayHomeAsUpEnabled(true);
100 | }
101 |
102 | recyclerView.setAdapter(adapter);
103 | getSupportLoaderManager().initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks() {
104 | @Override
105 | public Loader onCreateLoader(int id, Bundle args) {
106 | CursorLoader loader = new CursorLoader(WifiListActivity.this)
107 | .table(Database.TABLE_SAMPLES)
108 | .columns(new String[]{Database.COL_SSID, Database.COL_RFID})
109 | .sortOrder(Database.COL_SSID + " ASC");
110 |
111 | updateLoaderSelection(loader);
112 |
113 | return loader;
114 | }
115 |
116 | @Override
117 | public void onLoadFinished(Loader loader, Cursor data) {
118 | adapter.swap(data);
119 | }
120 |
121 | @Override
122 | public void onLoaderReset(Loader loader) {
123 | adapter.swap(null);
124 | }
125 | });
126 |
127 | if (findViewById(R.id.wifi_detail_container) != null) {
128 | // The detail container view will be present only in the
129 | // large-screen layouts (res/values-w900dp).
130 | // If this view is present, then the
131 | // activity should be in two-pane mode.
132 | twoPane = true;
133 | }
134 | }
135 |
136 | @Override
137 | public boolean onOptionsItemSelected(MenuItem item) {
138 | final int id = item.getItemId();
139 |
140 | if (id == android.R.id.home) {
141 | // This ID represents the Home or Up button. In the case of this
142 | // activity, the Up button is shown. Use NavUtils to allow users
143 | // to navigate up one level in the application structure. For
144 | // more details, see the Navigation pattern on Android Design:
145 | //
146 | // http://developer.android.com/design/patterns/navigation.html#up-vs-back
147 | //
148 | NavUtils.navigateUpFromSameTask(this);
149 | return true;
150 | }
151 |
152 | return super.onOptionsItemSelected(item);
153 | }
154 |
155 | @TextChange(R.id.search_term)
156 | protected void searchTermChanged() {
157 | Loader loader = getSupportLoaderManager().getLoader(LOADER_ID);
158 |
159 | if (loader != null) {
160 | updateLoaderSelection((CursorLoader) loader);
161 | loader.forceLoad();
162 | }
163 | }
164 |
165 | private void updateLoaderSelection(CursorLoader loader) {
166 | boolean onlyChanged = Configuration.listOption() == 1;
167 | final String search = searchTerm.getText().toString();
168 |
169 | String selection = "";
170 | List selectionArgs = new ArrayList<>();
171 |
172 | if (!TextUtils.isEmpty(search)) {
173 | selection = Database.COL_RFID + " LIKE ? OR " + Database.COL_SSID + " LIKE ?";
174 |
175 | // two times because there are two placeholders
176 | selectionArgs.add("%" + /* remove ":" because they are not saved at the database */ search.replaceAll(":", "") + "%");
177 | selectionArgs.add("%" + search + "%");
178 | }
179 |
180 | if (onlyChanged) {
181 | if (TextUtils.isEmpty(selection)) {
182 | selection = Database.COL_CHANGED + "<> 0";
183 | } else {
184 | selection = Database.COL_CHANGED + "<> 0 AND (" + selection + ")";
185 | }
186 | }
187 |
188 | loader
189 | .selection(selection)
190 | .selectionArgs(selectionArgs.toArray(new String[selectionArgs.size()]));
191 | }
192 |
193 | @Override
194 | public void onBackPressed() {
195 | // clear search field on first back press
196 |
197 | if (TextUtils.isEmpty(searchTerm.getText().toString())) {
198 | super.onBackPressed();
199 | } else {
200 | searchTerm.setText("");
201 | }
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/WifiListAdapter.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.database.Cursor;
22 | import android.support.annotation.NonNull;
23 | import android.support.v7.widget.RecyclerView;
24 | import android.view.LayoutInflater;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.widget.TextView;
28 |
29 | import org.fitchfamily.android.wifi_backend.R;
30 | import org.fitchfamily.android.wifi_backend.database.AccessPoint;
31 | import org.fitchfamily.android.wifi_backend.database.Database;
32 |
33 | public class WifiListAdapter extends CursorAdapter {
34 | private final View.OnClickListener clickListener = new View.OnClickListener() {
35 | @Override
36 | public void onClick(View v) {
37 | if(listener != null) {
38 | String rfId = (String) v.getTag();
39 |
40 | listener.onWifiClicked(rfId);
41 | }
42 | }
43 | };
44 |
45 | private Listener listener;
46 | private int columnSsid;
47 | private int columnRfId;
48 |
49 | public WifiListAdapter() {
50 | setHasStableIds(true);
51 | }
52 |
53 | @Override
54 | public long getItemId(int position) {
55 | return getItem(position).getString(columnRfId).hashCode();
56 | }
57 |
58 | @Override
59 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
60 | View view = LayoutInflater.from(parent.getContext())
61 | .inflate(R.layout.wifi_list_content, parent, false);
62 | view.setOnClickListener(clickListener);
63 | return new ViewHolder(view);
64 | }
65 |
66 | @Override
67 | protected void onCursorChanged(@NonNull Cursor cursor) {
68 | super.onCursorChanged(cursor);
69 | columnSsid = cursor.getColumnIndexOrThrow(Database.COL_SSID);
70 | columnRfId = cursor.getColumnIndexOrThrow(Database.COL_RFID);
71 | }
72 |
73 | @Override
74 | public void bind(ViewHolder holder, Cursor cursor) {
75 | holder.bind(cursor.getString(columnSsid), cursor.getString(columnRfId));
76 | }
77 |
78 | public class ViewHolder extends RecyclerView.ViewHolder {
79 | private final TextView title, id;
80 | private final View view;
81 |
82 | public ViewHolder(View view) {
83 | super(view);
84 | this.view = view;
85 |
86 | id = (TextView) view.findViewById(R.id.id);
87 | title = (TextView) view.findViewById(R.id.title);
88 | }
89 |
90 | public ViewHolder bind(String ssid, String rfId) {
91 | view.setTag(rfId);
92 |
93 | title.setText(ssid);
94 | id.setText(AccessPoint.readableBssid(rfId));
95 |
96 | return this;
97 | }
98 | }
99 |
100 | public WifiListAdapter listener(Listener listener) {
101 | this.listener = listener;
102 | return this;
103 | }
104 |
105 | public Listener listener() {
106 | return listener;
107 | }
108 |
109 | public interface Listener {
110 | void onWifiClicked(String rfId);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/reset/ResetDatabaseDialogFragment.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data.reset;
2 |
3 | import android.app.Dialog;
4 | import android.content.DialogInterface;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | import android.support.v4.app.DialogFragment;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v7.app.AlertDialog;
10 |
11 | import org.fitchfamily.android.wifi_backend.R;
12 |
13 | public class ResetDatabaseDialogFragment extends DialogFragment {
14 | private static final String TAG = "ResetDatabaseDialogFragment";
15 |
16 | @NonNull
17 | @Override
18 | public Dialog onCreateDialog(Bundle savedInstanceState) {
19 | return new AlertDialog.Builder(getContext())
20 | .setTitle(R.string.data_reset)
21 | .setMessage(R.string.data_reset_warning)
22 | .setNegativeButton(R.string.data_reset_no, null)
23 | .setPositiveButton(R.string.data_reset_yes, new DialogInterface.OnClickListener() {
24 | @Override
25 | public void onClick(DialogInterface dialogInterface, int i) {
26 | ResetProgressDialog_.builder().build().show(getFragmentManager());
27 | }
28 | })
29 | .create();
30 | }
31 |
32 | public void show(FragmentManager fragmentManager) {
33 | show(fragmentManager, TAG);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/reset/ResetProgressDialog.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data.reset;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.app.Dialog;
22 | import android.app.ProgressDialog;
23 | import android.os.Bundle;
24 | import android.support.annotation.NonNull;
25 | import android.support.v4.app.FragmentManager;
26 | import android.util.Log;
27 | import android.widget.Toast;
28 |
29 | import com.octo.android.robospice.persistence.DurationInMillis;
30 | import com.octo.android.robospice.persistence.exception.SpiceException;
31 | import com.octo.android.robospice.request.listener.RequestListener;
32 |
33 | import org.androidannotations.annotations.EFragment;
34 | import org.fitchfamily.android.wifi_backend.BuildConfig;
35 | import org.fitchfamily.android.wifi_backend.R;
36 | import org.fitchfamily.android.wifi_backend.data.ResetSpiceRequest;
37 | import org.fitchfamily.android.wifi_backend.ui.BaseDialogFragment;
38 |
39 | @EFragment
40 | public class ResetProgressDialog extends BaseDialogFragment implements RequestListener {
41 | private static final String TAG = "WiFiBackendResetDlg";
42 |
43 | @Override
44 | public void onStart() {
45 | super.onStart();
46 |
47 | getSpiceManager().execute(
48 | new ResetSpiceRequest(getContext().getApplicationContext()),
49 | TAG,
50 | DurationInMillis.ALWAYS_EXPIRED,
51 | this
52 | );
53 | }
54 |
55 | @NonNull
56 | @Override
57 | public Dialog onCreateDialog(Bundle savedInstanceState) {
58 | ProgressDialog progressDialog = new ProgressDialog(getActivity());
59 | progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
60 | progressDialog.setIndeterminate(true);
61 | progressDialog.setMessage(getString(R.string.data_reset));
62 | progressDialog.setProgressNumberFormat(null);
63 | progressDialog.setCancelable(false);
64 | progressDialog.setCanceledOnTouchOutside(false);
65 |
66 | return progressDialog;
67 | }
68 |
69 | public void show(FragmentManager fragmentManager) {
70 | show(fragmentManager, TAG);
71 | }
72 |
73 | @Override
74 | public void onRequestSuccess(ResetSpiceRequest.Result result) {
75 | dismissAllowingStateLoss();
76 | }
77 |
78 | @Override
79 | public void onRequestFailure(SpiceException spiceException) {
80 | // should not happen
81 | Toast.makeText(getContext(), "reset failed", Toast.LENGTH_SHORT).show();
82 |
83 | if (BuildConfig.DEBUG) {
84 | Log.w(TAG, "error cleaning database", spiceException);
85 | }
86 |
87 | dismissAllowingStateLoss();
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/transfer/ExportProgressDialog.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data.transfer;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.net.Uri;
22 | import android.support.v4.app.FragmentManager;
23 |
24 | import com.octo.android.robospice.request.SpiceRequest;
25 |
26 | import org.androidannotations.annotations.EFragment;
27 | import org.androidannotations.annotations.FragmentArg;
28 | import org.fitchfamily.android.wifi_backend.Configuration;
29 | import org.fitchfamily.android.wifi_backend.R;
30 | import org.fitchfamily.android.wifi_backend.data.ExportSpiceRequest;
31 |
32 | @EFragment
33 | public class ExportProgressDialog extends OperationProgressDialog {
34 |
35 | private static final String TAG = "WiFiBackendExportDlg";
36 |
37 | @FragmentArg
38 | protected Uri uri;
39 |
40 | @Override
41 | protected String getMessage() {
42 | String message = getString(R.string.data_export_all);
43 | switch (Configuration.exportOption()) {
44 | case Configuration.EXPORT_OPTION_CHANGED:
45 | message = getString(R.string.data_export_changed);;
46 | break;
47 |
48 | default:
49 | }
50 |
51 | return message;
52 | }
53 |
54 | @Override
55 | protected String getFailureMessage() {
56 | return getString(R.string.data_export_error);
57 | }
58 |
59 | @Override
60 | protected int getMaxProgress() {
61 | return ExportSpiceRequest.MAX_PROGRESS;
62 | }
63 |
64 | @Override
65 | protected SpiceRequest getRequest() {
66 | return new ExportSpiceRequest(getContext(), uri);
67 | }
68 |
69 | @Override
70 | protected Object getCacheKey() {
71 | return uri.toString();
72 | }
73 |
74 | public void show(FragmentManager fragmentManager) {
75 | show(fragmentManager, TAG);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/transfer/ImportProgressDialog.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data.transfer;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.net.Uri;
22 | import android.support.v4.app.FragmentManager;
23 |
24 | import com.octo.android.robospice.request.SpiceRequest;
25 |
26 | import org.androidannotations.annotations.EFragment;
27 | import org.androidannotations.annotations.FragmentArg;
28 | import org.fitchfamily.android.wifi_backend.R;
29 | import org.fitchfamily.android.wifi_backend.data.ImportSpiceRequest;
30 |
31 | @EFragment
32 | public class ImportProgressDialog extends OperationProgressDialog {
33 |
34 | private static final String TAG = "WiFiBackendImportDlg";
35 |
36 | @FragmentArg
37 | protected Uri uri;
38 |
39 | public void show(FragmentManager fragmentManager) {
40 | show(fragmentManager, TAG);
41 | }
42 |
43 | @Override
44 | protected String getMessage() {
45 | return getString(R.string.data_import);
46 | }
47 |
48 | @Override
49 | protected String getFailureMessage() {
50 | return getString(R.string.data_import_error);
51 | }
52 |
53 | @Override
54 | protected int getMaxProgress() {
55 | return ImportSpiceRequest.MAX_PROGRESS;
56 | }
57 |
58 | @Override
59 | protected SpiceRequest getRequest() {
60 | return new ImportSpiceRequest(getActivity(), uri);
61 | }
62 |
63 | @Override
64 | protected Object getCacheKey() {
65 | return uri.toString();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/data/transfer/OperationProgressDialog.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.data.transfer;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.app.Dialog;
22 | import android.app.ProgressDialog;
23 | import android.os.Bundle;
24 | import android.support.annotation.NonNull;
25 | import android.widget.Toast;
26 |
27 | import com.octo.android.robospice.persistence.DurationInMillis;
28 | import com.octo.android.robospice.persistence.exception.SpiceException;
29 | import com.octo.android.robospice.request.SpiceRequest;
30 | import com.octo.android.robospice.request.listener.PendingRequestListener;
31 | import com.octo.android.robospice.request.listener.RequestProgress;
32 | import com.octo.android.robospice.request.listener.RequestProgressListener;
33 |
34 | import org.androidannotations.annotations.EFragment;
35 | import org.androidannotations.annotations.InstanceState;
36 | import org.fitchfamily.android.wifi_backend.ui.BaseDialogFragment;
37 |
38 | @EFragment
39 | public abstract class OperationProgressDialog extends BaseDialogFragment implements RequestProgressListener, PendingRequestListener {
40 | private ProgressDialog progressDialog;
41 |
42 | @InstanceState
43 | protected boolean hasStartedRequest;
44 |
45 | @Override
46 | public void onStart() {
47 | super.onStart();
48 |
49 | if(!hasStartedRequest) {
50 | getSpiceManager().execute(getRequest(), getCacheKey(), DurationInMillis.ALWAYS_EXPIRED, this);
51 |
52 | hasStartedRequest = true;
53 | } else {
54 | getSpiceManager().addListenerIfPending(getRequest().getResultType(), getCacheKey(), this);
55 | }
56 | }
57 |
58 | @NonNull
59 | @Override
60 | public Dialog onCreateDialog(Bundle savedInstanceState) {
61 | final int maxProgress = getMaxProgress();
62 |
63 | progressDialog = new ProgressDialog(getActivity());
64 | progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
65 | progressDialog.setIndeterminate(maxProgress == 0);
66 | progressDialog.setTitle(getMessage());
67 | progressDialog.setMax(getMaxProgress());
68 | progressDialog.setProgressNumberFormat(null);
69 | progressDialog.setCancelable(false);
70 | progressDialog.setCanceledOnTouchOutside(false);
71 |
72 | return progressDialog;
73 | }
74 |
75 | protected abstract String getMessage();
76 | protected abstract String getFailureMessage();
77 | protected abstract SpiceRequest getRequest();
78 | protected abstract Object getCacheKey();
79 | protected int getMaxProgress() {
80 | return 0;
81 | };
82 |
83 | @Override
84 | public void onRequestProgressUpdate(RequestProgress progress) {
85 | if(progressDialog != null) {
86 | progressDialog.setProgress((int) progress.getProgress());
87 | }
88 | }
89 |
90 | @Override
91 | public void onRequestNotFound() {
92 | dismissAllowingStateLoss();
93 | }
94 |
95 | @Override
96 | public void onRequestSuccess(R result) {
97 | dismissAllowingStateLoss();
98 | }
99 |
100 | @Override
101 | public void onRequestFailure(SpiceException exception) {
102 | Toast.makeText(getActivity(), getFailureMessage(), Toast.LENGTH_LONG).show();
103 | dismissAllowingStateLoss();
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/statistic/DatabaseStatistic.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.statistic;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import com.google.auto.value.AutoValue;
22 |
23 | @AutoValue
24 | public abstract class DatabaseStatistic {
25 | public static Builder builder() {
26 | return new AutoValue_DatabaseStatistic.Builder();
27 | }
28 |
29 | DatabaseStatistic() {
30 |
31 | }
32 |
33 | public abstract int accessPointCount();
34 | public abstract int accessPointChangeCount();
35 |
36 | @AutoValue.Builder
37 | public abstract static class Builder {
38 | Builder() {
39 |
40 | }
41 |
42 | public abstract Builder accessPointCount(int count);
43 | public abstract Builder accessPointChangeCount(int count);
44 | public abstract DatabaseStatistic build();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/ui/statistic/DatabaseStatisticLoader.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.ui.statistic;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.content.BroadcastReceiver;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.content.IntentFilter;
25 | import android.support.v4.content.AsyncTaskLoader;
26 | import android.support.v4.content.LocalBroadcastManager;
27 |
28 | import org.fitchfamily.android.wifi_backend.database.SamplerDatabase;
29 |
30 | public class DatabaseStatisticLoader extends AsyncTaskLoader {
31 | private BroadcastReceiver changeReceiver;
32 |
33 | public DatabaseStatisticLoader(Context context) {
34 | super(context);
35 | }
36 |
37 | @Override
38 | public DatabaseStatistic loadInBackground() {
39 | return DatabaseStatistic.builder()
40 | .accessPointCount(SamplerDatabase.getInstance(getContext()).getAccessPointCount(false))
41 | .accessPointChangeCount(SamplerDatabase.getInstance(getContext()).getAccessPointCount(true))
42 | .build();
43 | }
44 |
45 | @Override
46 | protected void onStartLoading() {
47 | super.onStartLoading();
48 |
49 | if(changeReceiver == null) {
50 | changeReceiver = new BroadcastReceiver() {
51 | @Override
52 | public void onReceive(Context context, Intent intent) {
53 | onContentChanged();
54 | }
55 | };
56 |
57 | LocalBroadcastManager.getInstance(getContext()).registerReceiver(changeReceiver, new IntentFilter(SamplerDatabase.ACTION_DATA_CHANGED));
58 | }
59 |
60 | forceLoad();
61 | }
62 |
63 | @Override
64 | protected void onReset() {
65 | super.onReset();
66 |
67 | LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(changeReceiver);
68 | changeReceiver = null;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/util/AgeValue.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.util;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.os.SystemClock;
22 |
23 | public class AgeValue {
24 | public static AgeValue create() {
25 | return new AgeValue();
26 | }
27 |
28 | private T value;
29 | private long time;
30 |
31 | private AgeValue() {
32 |
33 | }
34 |
35 | /**
36 | * Use this function to set the value
37 | * @param value the new value
38 | * @return this object
39 | */
40 | public AgeValue value(T value) {
41 | this.value = value;
42 | this.time = now();
43 |
44 | return this;
45 | }
46 |
47 | /**
48 | * Use this function to get the last value
49 | * @return the last value
50 | */
51 | public T value() {
52 | return value;
53 | }
54 |
55 | /**
56 | * Use this function to get the age of the last value
57 | * @return the age of the last value in milliseconds
58 | */
59 | public long age() {
60 | if(value == null) {
61 | return Long.MAX_VALUE;
62 | } else {
63 | return now() - time;
64 | }
65 | }
66 |
67 | /**
68 | * Use this function to get the time which is never decreasing
69 | * @return the time in milliseconds
70 | */
71 | private static long now() {
72 | return SystemClock.elapsedRealtime();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/util/CountingInputStream.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.data.util;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.support.annotation.NonNull;
22 |
23 | import java.io.FilterInputStream;
24 | import java.io.IOException;
25 | import java.io.InputStream;
26 |
27 | public class CountingInputStream extends FilterInputStream {
28 | private long bytesRead = 0;
29 |
30 | public CountingInputStream(InputStream inputStream) {
31 | super(inputStream);
32 | }
33 |
34 | @Override
35 | public int read() throws IOException {
36 | final int result = super.read();
37 |
38 | if(result != -1) {
39 | bytesRead++;
40 | }
41 |
42 | return result;
43 | }
44 |
45 | @Override
46 | public int read(@NonNull byte[] buffer) throws IOException {
47 | final int result = super.read(buffer);
48 |
49 | if(result != -1) {
50 | bytesRead += result;
51 | }
52 |
53 | return result;
54 | }
55 |
56 | @Override
57 | public int read(@NonNull byte[] buffer, int byteOffset, int byteCount) throws IOException {
58 | final int result = super.read(buffer, byteOffset, byteCount);
59 |
60 | if(result != -1) {
61 | bytesRead += result;
62 | }
63 |
64 | return result;
65 | }
66 |
67 | public long getBytesRead() {
68 | return bytesRead;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/util/SimpleLocation.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.util;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.support.annotation.Nullable;
22 |
23 | import com.google.auto.value.AutoValue;
24 | import org.fitchfamily.android.wifi_backend.util.distanceCache;
25 |
26 | @AutoValue
27 | public abstract class SimpleLocation {
28 |
29 | public static Builder builder() {
30 | return new AutoValue_SimpleLocation.Builder();
31 | }
32 |
33 | public abstract double latitude();
34 | public abstract double longitude();
35 | public abstract float radius();
36 | public abstract boolean changed();
37 |
38 | private static distanceCache distance = new distanceCache();
39 |
40 | public static SimpleLocation fromAndroidLocation(android.location.Location location) {
41 | return builder()
42 | .latitude(location.getLatitude())
43 | .longitude(location.getLongitude())
44 | .radius(location.getAccuracy())
45 | .changed(true)
46 | .build();
47 | }
48 |
49 | public android.location.Location toAndroidLocation() {
50 | android.location.Location location = new android.location.Location("wifi");
51 | location.setLatitude(latitude());
52 | location.setLongitude(longitude());
53 | location.setAccuracy(radius());
54 |
55 | return location;
56 | }
57 |
58 | public static SimpleLocation fromLatLon(double lat, double lon, boolean changed) {
59 | return builder().latitude(lat).longitude(lon).radius(150f).changed(changed).build();
60 | }
61 |
62 | public static SimpleLocation fromLatLon(String lat, String lon, boolean changed) {
63 | return fromLatLon(Double.parseDouble(lat),Double.parseDouble(lon),changed);
64 | }
65 |
66 | public float distanceTo(SimpleLocation location) {
67 | return distanceTo(location.toAndroidLocation());
68 | }
69 |
70 | public float distanceTo(android.location.Location location) {
71 | return distance.distanceBetween(this.toAndroidLocation(), location);
72 | }
73 |
74 | @AutoValue.Builder
75 | public abstract static class Builder {
76 | Builder() {
77 | }
78 |
79 | public abstract Builder latitude(double latitude);
80 | public abstract Builder longitude(double longitude);
81 | public abstract Builder radius(float radius);
82 | public abstract Builder changed(boolean changed);
83 | public abstract SimpleLocation build();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/util/distanceCache.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.util;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | import android.location.Location;
21 | import android.support.v4.util.LruCache;
22 | import android.util.Log;
23 |
24 | import org.fitchfamily.android.wifi_backend.BuildConfig;
25 |
26 | public class distanceCache {
27 | private static final String TAG = "WiFiBackendDistCache";
28 | private static final boolean DEBUG = BuildConfig.DEBUG;
29 |
30 | private class cacheKey {
31 | double lat1;
32 | double lon1;
33 | double lat2;
34 | double lon2;
35 |
36 | cacheKey(Location first, Location second) {
37 | lat1 = first.getLatitude();
38 | lon1 = first.getLongitude();
39 | lat2 = second.getLatitude();
40 | lon2 = second.getLongitude();
41 | }
42 |
43 | private int longHash(long f) {
44 | return (int)(f ^ (f >>> 32));
45 | }
46 |
47 | public int hashCode() {
48 | int result = 101;
49 | result = 37 * result + longHash(Double.doubleToLongBits(lat1));
50 | result = 37 * result + longHash(Double.doubleToLongBits(lon1));
51 | result = 37 * result + longHash(Double.doubleToLongBits(lat2));
52 | result = 37 * result + longHash(Double.doubleToLongBits(lon2));
53 | return result;
54 | }
55 |
56 | public boolean equals(Object obj) {
57 | cacheKey other = (cacheKey)obj;
58 |
59 | return (lat1 == other.lat1) && (lon1 == other.lon1) &&
60 | (lat2 == other.lat2) && (lon2 == other.lon2);
61 | }
62 | }
63 | protected class distanceRec {
64 | public float distance;
65 | }
66 |
67 | private static final LruCache distanceCache = new LruCache<>(1000);
68 | private static long myHits = 0;
69 | private static long myMisses = 0;
70 |
71 | public synchronized float distanceBetween(Location loc1, Location loc2) {
72 | cacheKey key = new cacheKey(loc1, loc2);
73 | cacheKey key1 = new cacheKey(loc2, loc1);
74 | distanceRec cachedValue = distanceCache.get(key);
75 | if (cachedValue == null) {
76 | cachedValue = distanceCache.get(key1);
77 | }
78 | if (cachedValue == null) {
79 | myMisses++;
80 | cachedValue = new distanceRec();
81 | cachedValue.distance = loc1.distanceTo(loc2);
82 | distanceCache.put(key,cachedValue);
83 | } else
84 | myHits++;
85 | return cachedValue.distance;
86 | }
87 |
88 | public void logCacheStats() {
89 | Log.i(TAG, "LRU stats: Hits=" + distanceCache.hitCount() +
90 | ", Misses=" + distanceCache.missCount() +
91 | ", Entries=" + distanceCache.size() +
92 | ", MyHits=" + myHits +
93 | ", MyMisses=" + myMisses);
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/wifi/WifiAccessPoint.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.wifi;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import com.google.auto.value.AutoValue;
22 |
23 | @AutoValue
24 | public abstract class WifiAccessPoint {
25 | WifiAccessPoint() {
26 |
27 | }
28 |
29 | public static Builder builder() {
30 | return new AutoValue_WifiAccessPoint.Builder();
31 | }
32 |
33 | public abstract String ssid();
34 | public abstract String rfId();
35 | public abstract int level();
36 | public abstract int rfType();
37 |
38 | @AutoValue.Builder
39 | public abstract static class Builder {
40 | Builder() {
41 |
42 | }
43 |
44 | public abstract Builder ssid(String ssid);
45 | public abstract Builder rfId(String rfId);
46 | public abstract Builder level(int level);
47 | public abstract WifiAccessPoint build();
48 | public abstract Builder rfType(int type);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/wifi/WifiBlacklist.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.wifi;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import java.util.Locale;
22 |
23 | public abstract class WifiBlacklist {
24 | private WifiBlacklist() {
25 |
26 | }
27 |
28 | public static boolean ignore(String SSID) {
29 | String SSIDLower = SSID.toLowerCase(Locale.US);
30 |
31 | return (SSIDLower.endsWith("_nomap") || // Google unsubscibe option
32 |
33 | SSID.startsWith("Audi") || // some cars seem to have this AP on-board
34 | SSID.startsWith("BusWiFi") || // Some transit buses in LA Calif metro area
35 | SSID.startsWith("CellSpot") || // T-Mobile US portable cell based WiFi
36 | SSID.startsWith("CoachAmerica") || // Charter bus service with on board WiFi
37 | SSID.startsWith("DisneyLandResortExpress") || // Bus with on board WiFi
38 | SSID.startsWith("HUAWEI-") ||
39 | SSID.startsWith("Samsung Galaxy") || // mobile AP
40 | SSID.startsWith("TaxiLinQ") || // Mobile AP, see http://www.mobile-knowledge.com/products/driver-solutions/taxilinq/
41 |
42 | SSIDLower.contains("admin@ms ") || // WLAN network on Hurtigruten ships
43 | SSIDLower.contains("android") || // mobile AP
44 | SSIDLower.contains("contiki-wifi") || // WLAN network on board of bus
45 | SSIDLower.contains("db ic bus") || // WLAN network on board of German bus
46 | SSIDLower.contains("deinbus.de") || // WLAN network on board of German bus
47 | SSIDLower.contains("ecolines") || // WLAN network on board of German bus
48 | SSIDLower.contains("eurolines_wifi") || // WLAN network on board of German bus
49 | SSIDLower.contains("fernbus") || // WLAN network on board of German bus
50 | SSIDLower.contains("flixbus") || // WLAN network on board of German bus
51 | SSIDLower.contains("guest@ms ") || // WLAN network on Hurtigruten ships
52 | SSIDLower.contains("ipad") || // mobile AP
53 | SSIDLower.contains("iphone") || // mobile AP
54 | SSIDLower.contains("mobile hotspot") || // e.g "MetroPCS Portable Mobile Hotspot"
55 | SSIDLower.contains("motorola") || // mobile AP
56 | SSIDLower.contains("muenchenlinie") || // WLAN network on board of bus
57 | SSIDLower.contains("nsb_interakti") ||
58 | SSIDLower.contains("postbus") || // WLAN network on board of bus line
59 | SSIDLower.contains("telekom_ice") || // WLAN network on DB trains
60 |
61 | SSIDLower.contentEquals("amtrakconnect") || // WLAN network on USA Amtrak trains
62 | SSIDLower.contentEquals("amtrak") || // WLAN network on USA Amtrak trains
63 | SSIDLower.contentEquals("megabus") // WLAN network on MegaBus US bus
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/wifi/WifiCompat.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.wifi;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import android.net.wifi.WifiManager;
22 |
23 | public abstract class WifiCompat {
24 | private WifiCompat() {
25 |
26 | }
27 |
28 | public static boolean isScanAlwaysAvailable(WifiManager wifiManager) {
29 | try {
30 | return wifiManager.isScanAlwaysAvailable();
31 | } catch (NoSuchMethodError e) {
32 | return false;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/org/fitchfamily/android/wifi_backend/wifi/WifiReceiver.java:
--------------------------------------------------------------------------------
1 | package org.fitchfamily.android.wifi_backend.wifi;
2 |
3 | /*
4 | * WiFi Backend for Unified Network Location
5 | * Copyright (C) 2014,2015 Tod Fitch
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | import java.util.ArrayList;
22 | import java.util.Collections;
23 | import java.util.List;
24 | import java.util.Locale;
25 |
26 | import android.content.BroadcastReceiver;
27 | import android.content.Context;
28 | import android.content.Intent;
29 | import android.net.wifi.ScanResult;
30 | import android.net.wifi.WifiManager;
31 | import android.os.Bundle;
32 | import android.support.annotation.NonNull;
33 | import android.util.Log;
34 |
35 | import org.fitchfamily.android.wifi_backend.BuildConfig;
36 | import org.fitchfamily.android.wifi_backend.database.Database;
37 |
38 | public class WifiReceiver extends BroadcastReceiver {
39 | private static final String TAG = "WiFiReceiver";
40 | private static final boolean DEBUG = BuildConfig.DEBUG;
41 |
42 | private boolean scanStarted = false;
43 | private static long scanStartTime;
44 | private final WifiManager wifiManager;
45 | private final WifiReceivedCallback callback;
46 |
47 | public WifiReceiver(WifiManager wifiManager, WifiReceivedCallback callback) {
48 | if (DEBUG) {
49 | Log.i(TAG, "WifiReceiver() constructor");
50 | }
51 |
52 | this.callback = callback;
53 | this.wifiManager = wifiManager;
54 | }
55 |
56 | public void onReceive(Context c, Intent intent) {
57 | if (!scanStarted()) {
58 | if(DEBUG) {
59 | Log.i(TAG, "Scan received but no scan started");
60 | }
61 | } else {
62 | scanStarted(false);
63 | }
64 |
65 | List configs = wifiManager.getScanResults();
66 |
67 | if(configs == null) {
68 | if(DEBUG) {
69 | Log.d(TAG, "wifi.getScanResults() == null");
70 | }
71 |
72 | return;
73 | }
74 |
75 | if (DEBUG) {
76 | Log.i(TAG, "Got " + configs.size() + " wifi access points");
77 | }
78 |
79 | List accessPoints = new ArrayList<>(configs.size());
80 |
81 | for (ScanResult config : configs) {
82 | accessPoints.add(
83 | WifiAccessPoint.builder()
84 | .ssid(config.SSID)
85 | // some strange devices use a dot instead of :
86 | .rfId(config.BSSID.toUpperCase(Locale.US).replace(".", ":"))
87 | .level(config.level)
88 | .rfType(Database.TYPE_WIFI)
89 | .build()
90 | );
91 | }
92 |
93 | callback.processWiFiScanResults(Collections.unmodifiableList(accessPoints));
94 | }
95 |
96 | public boolean scanStarted() {
97 | return scanStarted;
98 | }
99 |
100 | private void scanStarted(boolean scanStarted) {
101 | if (scanStarted)
102 | this.scanStartTime = System.currentTimeMillis();
103 | else {
104 | if (DEBUG)
105 | Log.i(TAG, "WiFi Scan time = " + (System.currentTimeMillis()-this.scanStartTime));
106 | }
107 | this.scanStarted = scanStarted;
108 | }
109 |
110 | public void startScan() {
111 | if (!wifiManager.isWifiEnabled() && !WifiCompat.isScanAlwaysAvailable(wifiManager)) {
112 | if(DEBUG) {
113 | Log.i(TAG, "Wifi is disabled and we can't scan either. Not doing anything.");
114 | }
115 | scanStarted(false);
116 | } else {
117 | if (scanStarted()) {
118 | if (DEBUG) {
119 | Log.i(TAG, "startScan(): Scan already in progress.");
120 | }
121 | } else {
122 | if (DEBUG) {
123 | Log.i(TAG, "startScan(): Starting scan.");
124 | }
125 | scanStarted(true);
126 | wifiManager.startScan();
127 | }
128 | }
129 | }
130 |
131 | public interface WifiReceivedCallback {
132 | void processWiFiScanResults(@NonNull List accessPoints);
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi-v11/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-hdpi-v11/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-hdpi/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi-v11/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-mdpi-v11/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-mdpi/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi-v11/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-xhdpi-v11/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-xhdpi/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi-v11/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-xxhdpi-v11/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-xxhdpi/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_stat_no_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/drawable-xxxhdpi/ic_stat_no_location.png
--------------------------------------------------------------------------------
/app/src/main/res/layout-w900dp/activity_wifi_list.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
21 |
22 |
28 |
29 |
35 |
36 |
42 |
43 |
50 |
51 |
52 |
53 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_wifi_detail.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_wifi_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
20 |
21 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/wifi_detail.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
17 |
18 |
24 |
25 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/wifi_list_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | WLAN Standortdienst
4 | WLAN Standortdienst
5 |
8 |
9 |
10 | GPS Einstellungen
11 |
12 | Erforderliche Genauigkeit
13 | GPS-Genauigkeit muss mindestens … betragen (Meter)
14 |
15 | Standortabstand
16 | Mindestabstand zwischen GPS-Standorten (Meter)
17 |
18 | Zeitlicher Standortabstand
19 | Zeitlicher Mindestabstand zwischen GPS-Werten (Sekunden)
20 |
21 | GPS Gültigkeitsdauer
22 | Die Nutzungsdauer eines GPS-Signals (wenn kein neues verfügbar ist) (Sekunden).
23 |
24 |
25 | WLAN-Annahmen
26 |
27 | Mindestreichweite
28 | Kleinstmögliche angenommene WLAN-Reichweite (Meter).
29 |
30 | Bewegungserkennung
31 | Größtmögliche angenommene WLAN-Reichweite (Meter).
32 |
33 | Bewegungserkennungsschutz
34 | Messwerte an einem neuen Ort bevor einem WLAN vertraut wird
35 |
36 | Bekannte WLANs
37 |
38 |
39 | %s Meter
40 | %s Sekunden
41 | %s Messwerte
42 | %1$d WLANs
43 |
44 | Einstellungen
45 | Erweitert
46 | Externe Bibliotheken
47 | Website
48 |
49 | Berühren um erforderlichen Standortzugriff zu erlauben
50 |
51 | WLANs
52 | WLAN Details
53 |
54 | Genauigkeit: %s
55 | Auf der Karte anzeigen
56 |
57 | Export aller Daten
58 | Export geänderte Daten
59 | Datenexport fehlgeschlagen
60 |
61 | Daten importieren
62 | Datenimport fehlgeschlagen
63 |
64 | Suchen (mit SSID oder RFID)
65 |
66 | Datenbank zurücksetzen
67 | Die Datenbank kann nur widerhergestellt werden, wenn ein Backup angelegt wurde
68 | Daten löschen
69 | Daten behalten
70 |
71 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | WiFi Location Service
7 | Service de localisation Wi-Fi
8 | Géolocalise en utilisant une base de données des antennes Wi-Fi générée et stockée sur le téléphone
9 |
10 |
11 | Paramétrage GPS
12 |
13 | Précision exigée
14 | L\'erreur de précision GPS ne doit pas dépasser cette valeur (en mètres).
15 |
16 | Distance entre les enregistrements
17 | Distance minimale entre les enregistrements GPS (en mètres)
18 |
19 | Intervalle entre les enregistrements
20 | Intervalle de temps entre les enregistrements GPS (en secondes)
21 |
22 | Temps de validité de la position GPS
23 | Temps pendant lequel la dernière position GPS est valide (en secondes)
24 |
25 |
26 | Paramétrage des points d\'accès Wi-Fi
27 |
28 | Portée minimale du point d\'accès Wi-Fi
29 | Portée minimale présumée pour un point d\'accès Wi-Fi (en mètres).
30 |
31 | Seuil de déplacement
32 | Portée maximale présumée pour un point d\'accès Wi-Fi (en mètres).
33 |
34 | Protection contre le déplacement
35 | Nombre de détections à une nouvelle position avant de déplacer le point d\'accès Wi-Fi.
36 |
37 | Nombre de points d\'accès Wi-Fi connus
38 |
39 | Nombre de points d\'accès Wi-Fi (nouveaux ou mis à jour)
40 |
41 |
42 | %s mètres
43 | %s secondes
44 | %s enregistrements
45 | %1$d APs
46 | %1$d APs
47 |
48 | Paramètres
49 | Avancé
50 | Bibliothèques externes
51 | Site internet
52 |
53 | Taper pour autoriser la permission de localisation (nécessaire)
54 |
55 | Wi-Fi
56 | Détails Wi-Fi
57 |
58 | Portée observée : %s
59 | Voir sur la carte
60 |
61 | Exporter toutes les données
62 | Exporter les données modifiées
63 | Impossible d\'exporter les données
64 |
65 | Importer les données
66 | Impossible d\'importer les données
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | Usługa lokalizacji WiFi
7 | Usługa lokalizacji WiFi
8 | Określaj lokalizację za pomocą bazy sieci WiFi na telefonie
9 |
10 |
11 | Ustawienia GPS
12 |
13 | Wymagana precyzja
14 | Maksymalny akceptowalny błąd odczytu GPS (w metrach).
15 |
16 | Odległość próbki
17 | Minimalna odległość pomiędzy próbkami lokalizacji GPS (w metrach).
18 |
19 | Interwał próbki
20 | Czas pomiędzy próbkami lokalizacji GPS (w sekundach).
21 |
22 | Czas poprawności GPS
23 | Czas poprawności ostatniego odczytu GPS (w sekundach).
24 |
25 |
26 | Założenia nadajników WiFi
27 |
28 | Minimalny zasięg nadajnika
29 | Minimalny założony zasięg nadajnika WiFi (w metrach).
30 |
31 | Próg przemieszczenia
32 | Maksymalny założony zasięg nadajnika WiFi (w metrach).
33 |
34 | Potwierdzenie przemieszczenia
35 | Liczba próbek nadajnika w nowej lokalizacji, zanim zostanie zaufany.
36 |
37 | Liczba znanych nadajników
38 |
39 | Liczba nowych i uaktualnionych nadajników
40 |
41 |
42 | %s metrów
43 | %s sekund
44 | %s próbek
45 | %1$d sieci
46 | %1$d sieci
47 |
48 | Ustawienia
49 | Zaawansowane
50 | Zewnętrzne biblioteki
51 | Strona internetowa
52 |
53 | Stuknij, aby udzielić wymaganego uprawnienia lokalizacji
54 |
55 | Sieci
56 | Szczegóły
57 |
58 | Zaobserwowany zasięg: %s
59 | Pokaż na mapie
60 |
61 | Eksportuj wszystkie dane
62 | Eksportuj zmienione dane
63 | Nie można wyeksportować danych
64 |
65 | Importuj dane
66 | Nie można zaimportować danych
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Услуга локације помоћу бежичних
4 | Услуга локације помоћу бежичних
5 | Лоцирање помоћу личне базе података бежичних мрежа на телефону
6 |
7 |
8 | ГПС поставке
9 |
10 | Захтевана прецизност
11 | Грешка ГПС-а не сме бити већа од (метара).
12 |
13 | Размак узорака
14 | Најмања удаљеност између узорака ГПС локације (метара).
15 |
16 | Интервал узорака
17 | Време између узорака ГПС локације (секунди).
18 |
19 | Време важења ГПС-а
20 | Време за које је последњи ГПС сигнал важећи (секунди).
21 |
22 |
23 | Претпоставке бежичних АП-а
24 |
25 | Најмања удаљеност АП-а
26 | Претпостављени најмањи домет АП-а (метара).
27 |
28 | Праг померања
29 | Претпостављени највећи домет АП-а (метара).
30 |
31 | Чување померања
32 | Број узорака на новој локацији пре него што се АП сматра поузданим.
33 |
34 | Број познатих АП-а
35 |
36 | Број нових или ажурираних АП-а
37 |
38 |
39 | %s метара
40 | %s секунди
41 | %s узорака
42 | %1$d АП-а
43 |
44 | Поставке
45 | Напредно
46 | Спољашње библиотеке
47 | Вебсајт
48 |
49 | Тапните да одобрите потребне дозволе за локацију
50 |
51 | Бежични
52 | Детаљи бежичног
53 |
54 | Прецизност: %s
55 | Прикажи на мапи
56 |
57 | Извоз свих података
58 | Извоз измењених података
59 | Не могу да извезем податке
60 |
61 | Увоз података
62 | Не могу да увезем податке
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/values-uk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | WiFi Location Service
7 | Сервіс позиціювання WiFi
8 | Позиціювання на основі локальної бази даних WiFi телефона.
9 |
10 |
11 | Налаштування GPS
12 |
13 | Необхідна точність
14 | Похибка GPS повинна бути не більшою за вказане число (метрів).
15 |
16 | Відстань між зразками
17 | Мінімальна відстань між зразками позиціювання GPS (метрів).
18 |
19 | Інтервал між зразками
20 | Час між зразками позиціювання GPS (секунд).
21 |
22 | час валідності GPS
23 | Час, на протязі якого сигнал GPS вважається дійсним (секунд).
24 |
25 |
26 | Припущення WiFi точки доступу
27 |
28 | Мінімальний діапазон точки доступу
29 | Мінімальний допустимий діапазон точки доступу (метрів).
30 |
31 | Поріг зсуву
32 | Максимально допустимий діапазон точки доступу (метрів).
33 |
34 | Захист зсуву
35 | Кількість зразків позиціювання перед підтвердженням зсуву точки доступу.
36 |
37 | Кількість відомих точок доступу
38 |
39 | Кількість нових чи оновлених точок доступу
40 |
41 |
42 | Метрів: %s
43 | Секунд: %s
44 | Зразків: %s
45 | Точок доступу: %1$d
46 | Точок доступу: %1$d
47 |
48 | Налаштування
49 | Розширені
50 | Зовнішні бібліотеки
51 | Сайт
52 |
53 | Натисніть для надання доступу до позиціювання
54 |
55 | WiFi мережі
56 | Подробиці WiFi
57 |
58 | Діапазон спостереження: %s
59 | Показати на карті
60 |
61 | Експортувати всі дані
62 | Експортувати лише змінені дані
63 | Не вдалося експортувати дані
64 |
65 | Імпорт даних
66 | Не вдалося імпортувати дані
67 |
68 | Пошук (за SSID чи RFID)
69 |
70 | Скинути базу даних
71 | Базу даних можливо буде відновити лише за умови, що зроблено резервну копію перед видаленням
72 | Видалити дані
73 | Лишити дані
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v19/constants.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/constants.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/defaults.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 20
5 | 0
6 | 0
7 | 2
8 |
9 |
10 | 50
11 | 1250
12 | 500
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 8dp
4 | 16dp
5 | 4dp
6 | 200dp
7 | 16dp
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/libraries.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | The Android Open Source Project
6 |
7 |
8 | Android Support Library
9 | The Android Support Library
10 | package is a set of code libraries that provide backward-compatible versions of Android
11 | framework APIs as well as features that are only available through the library APIs.
12 |
13 |
14 | https://developer.android.com/tools/support-library/index.html#overview
15 |
16 | 23.0.0
17 |
18 | true
19 |
20 | https://android.googlesource.com/platform/frameworks/support
21 |
22 |
23 | android.support
24 |
25 | apache_2_0
26 |
27 |
28 |
29 |
30 | Glen Smith
31 | https://sourceforge.net/u/userid-28390/profile/
32 |
33 | OpenCSV
34 | A Simple CSV Parser for Java under a commercial-friendly Apache 2.0 license.
35 | http://opencsv.sourceforge.net
36 |
37 |
38 | true
39 |
40 |
41 |
42 |
43 | apache_2_0
44 |
45 |
46 |
47 |
48 | Google
49 |
50 |
51 | Guava
52 | The Guava project contains several of Google\'s core libraries that we rely on in our Java-based projects: collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, and so forth.
53 | https://github.com/google/guava/blob/master/README.md
54 | 19.0
55 |
56 | true
57 | https://github.com/google/guava
58 |
59 | com.google.common
60 |
61 | apache_2_0
62 |
63 |
64 |
65 |
66 | Stéphane Nicolas
67 | https://github.com/stephanenicolas
68 |
69 | RoboSpice
70 | RoboSpice is a modular android library that
71 | makes writing asynchronous network requests easy!
72 |
73 |
74 | https://github.com/stephanenicolas/robospice/blob/release/README.md
75 |
76 | 1.4.14
77 |
78 | true
79 | https://github.com/stephanenicolas/robospice
80 |
81 |
82 | com.octo.android.robospice
83 |
84 | apache_2_0
85 |
86 |
87 |
88 |
89 | Machinarius
90 | https://github.com/Machinarius
91 |
92 |
93 | Support PreferenceFragment
94 | Unofficial
95 | PreferenceFragment compatibility layer for Android 1.6 and up.
96 |
97 |
98 | https://github.com/Machinarius/PreferenceFragment-Compat/blob/master/README.md
99 |
100 | 0.1.1
101 |
102 | true
103 |
104 | https://github.com/Machinarius/PreferenceFragment-Compat
105 |
106 |
107 |
108 | com.github.machinarius.preferencefragment
109 |
110 |
111 | apache_2_0
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | WiFi Location Service
7 | WiFi Location Service
8 | Locate using private on phone WiFi database
9 |
10 |
11 | GPS Setup
12 |
13 | Required Accuracy
14 | GPS error must be no more than (meters).
15 |
16 | Sample distance
17 | Minimum distance between GPS location samples (meters).
18 |
19 | Sample interval
20 | Time between GPS location samples (seconds).
21 |
22 | GPS valid time
23 | The time in which the last GPS signal is valid (seconds).
24 |
25 |
26 | WiFi AP Assumptions
27 |
28 | Minimum AP range
29 | Minimum assumed range of an AP (meters).
30 |
31 | Moved threshold
32 | Maximum assumed range of an AP (meters).
33 |
34 | Move guard
35 | Samples at new location before a moved AP is trusted.
36 |
37 | Number of known APs
38 |
39 | Number of new or updated APs
40 |
41 |
42 | %s meters
43 | %s seconds
44 | %s samples
45 | %1$d APs
46 | %1$d APs
47 |
48 | Settings
49 | Advanced
50 | External libraries
51 | Website
52 |
53 | Tap to grant the necessary location permission
54 |
55 | WiFis
56 | WiFi Detail
57 |
58 | Observed Range: %s
59 | Show on map
60 |
61 | Export all data
62 | Export changed data
63 | Couldn\'t export data
64 |
65 | Import data
66 | Couldn\'t import data
67 |
68 | Search (by SSID or RFID)
69 |
70 | Reset database
71 | The database can only be restored if you created an backup before the deletion
72 | Delete the data
73 | Keep the data
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/advanced.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
14 |
23 |
32 |
33 |
42 |
43 |
44 |
46 |
55 |
64 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
14 |
15 |
19 |
20 |
23 |
24 |
28 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/web_hi_res_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/app/src/main/web_hi_res_512.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:2.3.3'
8 | }
9 | }
10 |
11 | allprojects {
12 | repositories {
13 | jcenter()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/42.txt:
--------------------------------------------------------------------------------
1 | - Add Ukrainian translation
2 | - Update build environment
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | This is a backend for the µg Project's network location provider that uses locally acquired WiFi AP data to resolve user location.
2 |
3 | This backend consists of two parts sharing a common database. One part passively
4 | monitors the GPS. If the GPS has acquired and has a good position accuracy, then
5 | the WiFi APs detected by the phone are stored.
6 |
7 | The other part is the actual location provider which uses the database to
8 | estimate location when the GPS is not available or has not yet gotten its first
9 | fix. The use of stored WiFi AP can dramatically decrease the GPS time to first
10 | fix.
11 |
12 | This backend performs no network data. All data acquired by the phone stays on
13 | the phone and no queries are made to a centralized AP location provider.
14 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/Screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/fastlane/metadata/android/en-US/images/phoneScreenshots/Screenshot1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/Screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/fastlane/metadata/android/en-US/images/phoneScreenshots/Screenshot2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | UnifiedNlp location provider (local WiFi database)
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | WiFi Location Service - A local RF based back end for the µg Project
2 |
--------------------------------------------------------------------------------
/get_it_on_f-droid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/get_it_on_f-droid.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/n76/wifi_backend/ab5279a72d50ce90a2ead580cd04bbf2d98d0241/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Mar 13 11:19:18 PDT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------