aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFil <fil.bergamo@riseup.net>2017-03-07 23:07:50 +0100
committerFil <fil.bergamo@riseup.net>2017-03-07 23:07:50 +0100
commit6cd05512a7bca3becff60ae470f43793744c7f86 (patch)
treeb05dd0d004f10f9c5255d1732893593b286d0b1e
parent8b111e0799432fc5a6ead191e1029cc1446a8c91 (diff)
downloadpackages_apps_repwifi-6cd05512a7bca3becff60ae470f43793744c7f86.tar.gz
packages_apps_repwifi-6cd05512a7bca3becff60ae470f43793744c7f86.tar.bz2
packages_apps_repwifi-6cd05512a7bca3becff60ae470f43793744c7f86.zip
Removed bin directory, renamed root directory
-rw-r--r--app/AndroidManifest.xml57
-rw-r--r--app/assets/repwifi-logo-0.pngbin0 -> 226975 bytes
-rw-r--r--app/gen/fil/libre/repwifiapp/BuildConfig.java6
-rw-r--r--app/gen/fil/libre/repwifiapp/R.java128
-rw-r--r--app/ic_launcher-web.pngbin0 -> 41793 bytes
-rw-r--r--app/ic_launcher2-web.pngbin0 -> 21946 bytes
-rw-r--r--app/ic_launcher_bis-web.pngbin0 -> 22368 bytes
-rw-r--r--app/ic_launcher_tris-web.pngbin0 -> 20766 bytes
-rw-r--r--app/libs/android-support-v4.jarbin0 -> 393056 bytes
-rw-r--r--app/previews.xml118
-rw-r--r--app/proguard-project.txt20
-rw-r--r--app/project.properties14
-rw-r--r--app/res/drawable-hdpi/ic_launcher.pngbin0 -> 4669 bytes
-rw-r--r--app/res/drawable-hdpi/ic_launcher2.pngbin0 -> 2326 bytes
-rw-r--r--app/res/drawable-hdpi/ic_launcher_bis.pngbin0 -> 2377 bytes
-rw-r--r--app/res/drawable-hdpi/ic_launcher_tris.pngbin0 -> 2229 bytes
-rw-r--r--app/res/drawable-mdpi/ic_launcher.pngbin0 -> 2884 bytes
-rw-r--r--app/res/drawable-mdpi/ic_launcher2.pngbin0 -> 1540 bytes
-rw-r--r--app/res/drawable-mdpi/ic_launcher_bis.pngbin0 -> 1550 bytes
-rw-r--r--app/res/drawable-mdpi/ic_launcher_tris.pngbin0 -> 1507 bytes
-rw-r--r--app/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6144 bytes
-rw-r--r--app/res/drawable-xhdpi/ic_launcher2.pngbin0 -> 3083 bytes
-rw-r--r--app/res/drawable-xhdpi/ic_launcher_bis.pngbin0 -> 3104 bytes
-rw-r--r--app/res/drawable-xhdpi/ic_launcher_tris.pngbin0 -> 2925 bytes
-rw-r--r--app/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 9506 bytes
-rw-r--r--app/res/drawable-xxhdpi/ic_launcher2.pngbin0 -> 4723 bytes
-rw-r--r--app/res/drawable-xxhdpi/ic_launcher_bis.pngbin0 -> 4814 bytes
-rw-r--r--app/res/drawable-xxhdpi/ic_launcher_tris.pngbin0 -> 4465 bytes
-rw-r--r--app/res/layout/activity_credits.xml17
-rw-r--r--app/res/layout/activity_input_password.xml65
-rw-r--r--app/res/layout/activity_long_task.xml25
-rw-r--r--app/res/layout/activity_main.xml57
-rw-r--r--app/res/layout/activity_network_details.xml38
-rw-r--r--app/res/layout/activity_select_network.xml58
-rw-r--r--app/res/layout/activity_show_status.xml43
-rw-r--r--app/res/menu/activity_main.xml9
-rw-r--r--app/res/values-large/styles.xml10
-rw-r--r--app/res/values-v11/styles.xml11
-rw-r--r--app/res/values-v14/styles.xml12
-rw-r--r--app/res/values/colors.xml7
-rw-r--r--app/res/values/strings.xml25
-rw-r--r--app/res/values/strings_activity_input_password.xml17
-rw-r--r--app/res/values/styles.xml21
-rw-r--r--app/src/fil/libre/repwifiapp/Commons.java156
-rw-r--r--app/src/fil/libre/repwifiapp/activities/CreditsActivity.java56
-rw-r--r--app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java112
-rw-r--r--app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java174
-rw-r--r--app/src/fil/libre/repwifiapp/activities/MainActivity.java378
-rw-r--r--app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java145
-rw-r--r--app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java222
-rw-r--r--app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java131
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java196
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java106
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/Engine.java397
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/Engine4p2.java131
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/Engine6p0.java360
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/IEngine.java41
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/NetworkButton.java41
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/NetworkManager.java288
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/RootCommand.java109
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/Utils.java205
61 files changed, 4006 insertions, 0 deletions
diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml
new file mode 100644
index 0000000..ba324d2
--- /dev/null
+++ b/app/AndroidManifest.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="fil.libre.repwifiapp"
+ android:versionCode="0"
+ android:versionName="0.0.9" >
+
+ <uses-sdk
+ android:minSdkVersion="17"
+ android:targetSdkVersion="17" />
+
+ <uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application
+ android:icon="@drawable/ic_launcher_bis"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme"
+ android:allowBackup="true" >
+ <activity
+ android:name="fil.libre.repwifiapp.activities.MainActivity"
+ android:screenOrientation="portrait"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="fil.libre.repwifiapp.activities.SelectNetworkActivity"
+ android:label="@string/title_activity_select_network" >
+ </activity>
+ <activity
+ android:name="fil.libre.repwifiapp.activities.InputPasswordActivity" android:label="@string/title_activity_input_password"
+ android:windowSoftInputMode="adjustResize|stateVisible" >
+ </activity>
+ <activity
+ android:name="fil.libre.repwifiapp.activities.ConnectActivity"
+ android:label="@string/title_activity_connect" >
+ </activity>
+ <activity
+ android:name="fil.libre.repwifiapp.activities.ShowStatusActivity"
+ android:label="@string/title_activity_show_status" >
+ </activity>
+ <activity
+ android:name="fil.libre.repwifiapp.activities.LongTaskActivity" >
+ </activity>
+ <activity
+ android:name="fil.libre.repwifiapp.activities.NetworkDetailsActivity" >
+ </activity>
+ <activity
+ android:name="fil.libre.repwifiapp.activities.CreditsActivity">
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/app/assets/repwifi-logo-0.png b/app/assets/repwifi-logo-0.png
new file mode 100644
index 0000000..c9613ae
--- /dev/null
+++ b/app/assets/repwifi-logo-0.png
Binary files differ
diff --git a/app/gen/fil/libre/repwifiapp/BuildConfig.java b/app/gen/fil/libre/repwifiapp/BuildConfig.java
new file mode 100644
index 0000000..c886576
--- /dev/null
+++ b/app/gen/fil/libre/repwifiapp/BuildConfig.java
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package fil.libre.repwifiapp;
+
+public final class BuildConfig {
+ public final static boolean DEBUG = true;
+} \ No newline at end of file
diff --git a/app/gen/fil/libre/repwifiapp/R.java b/app/gen/fil/libre/repwifiapp/R.java
new file mode 100644
index 0000000..e145272
--- /dev/null
+++ b/app/gen/fil/libre/repwifiapp/R.java
@@ -0,0 +1,128 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package fil.libre.repwifiapp;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class color {
+ public static final int ThemeDark=0x7f040001;
+ public static final int ThemeLight=0x7f040000;
+ public static final int White=0x7f040003;
+ public static final int black=0x7f040002;
+ }
+ public static final class drawable {
+ public static final int ic_launcher=0x7f020000;
+ public static final int ic_launcher2=0x7f020001;
+ public static final int ic_launcher_bis=0x7f020002;
+ public static final int ic_launcher_tris=0x7f020003;
+ }
+ public static final class id {
+ public static final int btn_back=0x7f080017;
+ public static final int btn_delete=0x7f08000f;
+ public static final int btn_disconnect=0x7f080016;
+ public static final int btn_manage_nets=0x7f08000b;
+ public static final int btn_rescan=0x7f080012;
+ public static final int btn_scan=0x7f08000a;
+ public static final int chk_show_pass=0x7f080004;
+ public static final int chk_show_pass_details=0x7f08000e;
+ public static final int img_logo=0x7f08000c;
+ public static final int layout=0x7f080006;
+ public static final int layout_selnets=0x7f080010;
+ public static final int login_form=0x7f080001;
+ public static final int menu_credits=0x7f080018;
+ public static final int progbar=0x7f080007;
+ public static final int scrollview=0x7f080013;
+ public static final int sign_in_button=0x7f080005;
+ public static final int table_networks=0x7f080014;
+ public static final int txt_credits=0x7f080000;
+ public static final int txt_insert_pass=0x7f080002;
+ public static final int txt_main=0x7f080009;
+ public static final int txt_msg=0x7f080008;
+ public static final int txt_net_details=0x7f08000d;
+ public static final int txt_password=0x7f080003;
+ public static final int txt_selnets=0x7f080011;
+ public static final int txt_status=0x7f080015;
+ }
+ public static final class layout {
+ public static final int activity_credits=0x7f030000;
+ public static final int activity_input_password=0x7f030001;
+ public static final int activity_long_task=0x7f030002;
+ public static final int activity_main=0x7f030003;
+ public static final int activity_network_details=0x7f030004;
+ public static final int activity_select_network=0x7f030005;
+ public static final int activity_show_status=0x7f030006;
+ }
+ public static final class menu {
+ public static final int activity_main=0x7f070000;
+ }
+ public static final class string {
+ public static final int action_sign_in_register=0x7f050017;
+ public static final int action_sign_in_short=0x7f050018;
+ public static final int app_name=0x7f050000;
+ public static final int back_main=0x7f05000b;
+ public static final int button_text_next=0x7f050005;
+ public static final int credit_text=0x7f050013;
+ public static final int delete=0x7f050010;
+ public static final int disconnect=0x7f05000c;
+ public static final int error_field_required=0x7f05001e;
+ public static final int error_incorrect_password=0x7f05001d;
+ public static final int error_invalid_email=0x7f05001b;
+ public static final int error_invalid_password=0x7f05001c;
+ public static final int force_disconnect=0x7f05000d;
+ public static final int hello_world=0x7f050009;
+ public static final int insert_nets_password=0x7f050006;
+ public static final int login_progress_signing_in=0x7f05001a;
+ public static final int manage_networks=0x7f050011;
+ public static final int menu_credits=0x7f050001;
+ public static final int menu_forgot_password=0x7f050019;
+ /** Strings related to login
+ */
+ public static final int prompt_email=0x7f050015;
+ public static final int prompt_password=0x7f050016;
+ public static final int rescan=0x7f050004;
+ public static final int scan_networks=0x7f050002;
+ public static final int show_password=0x7f050007;
+ public static final int title_activity_connect=0x7f050008;
+ public static final int title_activity_credits=0x7f050012;
+ public static final int title_activity_input_password=0x7f050014;
+ public static final int title_activity_long_task=0x7f05000e;
+ public static final int title_activity_manage_networks=0x7f05000f;
+ public static final int title_activity_select_network=0x7f050003;
+ public static final int title_activity_show_status=0x7f05000a;
+ }
+ public static final class style {
+ /**
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+
+
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+
+
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+
+ API 11 theme customizations can go here.
+
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+
+ API 14 theme customizations can go here.
+ */
+ public static final int AppBaseTheme=0x7f060000;
+ /** Application theme.
+ All customizations that are NOT specific to a particular API-level can go here.
+ */
+ public static final int AppTheme=0x7f060001;
+ public static final int LoginFormContainer=0x7f060002;
+ }
+}
diff --git a/app/ic_launcher-web.png b/app/ic_launcher-web.png
new file mode 100644
index 0000000..df56b4e
--- /dev/null
+++ b/app/ic_launcher-web.png
Binary files differ
diff --git a/app/ic_launcher2-web.png b/app/ic_launcher2-web.png
new file mode 100644
index 0000000..e0a9dc8
--- /dev/null
+++ b/app/ic_launcher2-web.png
Binary files differ
diff --git a/app/ic_launcher_bis-web.png b/app/ic_launcher_bis-web.png
new file mode 100644
index 0000000..8a9e987
--- /dev/null
+++ b/app/ic_launcher_bis-web.png
Binary files differ
diff --git a/app/ic_launcher_tris-web.png b/app/ic_launcher_tris-web.png
new file mode 100644
index 0000000..a5e4d32
--- /dev/null
+++ b/app/ic_launcher_tris-web.png
Binary files differ
diff --git a/app/libs/android-support-v4.jar b/app/libs/android-support-v4.jar
new file mode 100644
index 0000000..229e4eb
--- /dev/null
+++ b/app/libs/android-support-v4.jar
Binary files differ
diff --git a/app/previews.xml b/app/previews.xml
new file mode 100644
index 0000000..daf3adb
--- /dev/null
+++ b/app/previews.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<previews>
+
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+ <preview
+ name="Config1"
+ activity="com.example.repwifiapp.CreditsActivity"
+ config="layout-sw320dp-w320dp-h533dp-normal-long-port-notnight-hdpi-finger-keyssoft-nokeys-navexposed-trackball-800x480-v17"
+ device="3.7in WVGA (Nexus One)"
+ devicestate="Portrait"
+ target="Android 4.2.2"
+ theme="@style/AppTheme" >
+ </preview>
+
+</previews> \ No newline at end of file
diff --git a/app/proguard-project.txt b/app/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/app/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/app/project.properties b/app/project.properties
new file mode 100644
index 0000000..a3ee5ab
--- /dev/null
+++ b/app/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17
diff --git a/app/res/drawable-hdpi/ic_launcher.png b/app/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..50093ae
--- /dev/null
+++ b/app/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/app/res/drawable-hdpi/ic_launcher2.png b/app/res/drawable-hdpi/ic_launcher2.png
new file mode 100644
index 0000000..78d26b2
--- /dev/null
+++ b/app/res/drawable-hdpi/ic_launcher2.png
Binary files differ
diff --git a/app/res/drawable-hdpi/ic_launcher_bis.png b/app/res/drawable-hdpi/ic_launcher_bis.png
new file mode 100644
index 0000000..1ddfad3
--- /dev/null
+++ b/app/res/drawable-hdpi/ic_launcher_bis.png
Binary files differ
diff --git a/app/res/drawable-hdpi/ic_launcher_tris.png b/app/res/drawable-hdpi/ic_launcher_tris.png
new file mode 100644
index 0000000..ddaa253
--- /dev/null
+++ b/app/res/drawable-hdpi/ic_launcher_tris.png
Binary files differ
diff --git a/app/res/drawable-mdpi/ic_launcher.png b/app/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..e2fe865
--- /dev/null
+++ b/app/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/app/res/drawable-mdpi/ic_launcher2.png b/app/res/drawable-mdpi/ic_launcher2.png
new file mode 100644
index 0000000..4a61a75
--- /dev/null
+++ b/app/res/drawable-mdpi/ic_launcher2.png
Binary files differ
diff --git a/app/res/drawable-mdpi/ic_launcher_bis.png b/app/res/drawable-mdpi/ic_launcher_bis.png
new file mode 100644
index 0000000..c205105
--- /dev/null
+++ b/app/res/drawable-mdpi/ic_launcher_bis.png
Binary files differ
diff --git a/app/res/drawable-mdpi/ic_launcher_tris.png b/app/res/drawable-mdpi/ic_launcher_tris.png
new file mode 100644
index 0000000..935010c
--- /dev/null
+++ b/app/res/drawable-mdpi/ic_launcher_tris.png
Binary files differ
diff --git a/app/res/drawable-xhdpi/ic_launcher.png b/app/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71ed985
--- /dev/null
+++ b/app/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/app/res/drawable-xhdpi/ic_launcher2.png b/app/res/drawable-xhdpi/ic_launcher2.png
new file mode 100644
index 0000000..01fc7ef
--- /dev/null
+++ b/app/res/drawable-xhdpi/ic_launcher2.png
Binary files differ
diff --git a/app/res/drawable-xhdpi/ic_launcher_bis.png b/app/res/drawable-xhdpi/ic_launcher_bis.png
new file mode 100644
index 0000000..4a0f08f
--- /dev/null
+++ b/app/res/drawable-xhdpi/ic_launcher_bis.png
Binary files differ
diff --git a/app/res/drawable-xhdpi/ic_launcher_tris.png b/app/res/drawable-xhdpi/ic_launcher_tris.png
new file mode 100644
index 0000000..5992ef4
--- /dev/null
+++ b/app/res/drawable-xhdpi/ic_launcher_tris.png
Binary files differ
diff --git a/app/res/drawable-xxhdpi/ic_launcher.png b/app/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..5545989
--- /dev/null
+++ b/app/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/res/drawable-xxhdpi/ic_launcher2.png b/app/res/drawable-xxhdpi/ic_launcher2.png
new file mode 100644
index 0000000..aaf68c6
--- /dev/null
+++ b/app/res/drawable-xxhdpi/ic_launcher2.png
Binary files differ
diff --git a/app/res/drawable-xxhdpi/ic_launcher_bis.png b/app/res/drawable-xxhdpi/ic_launcher_bis.png
new file mode 100644
index 0000000..ea36964
--- /dev/null
+++ b/app/res/drawable-xxhdpi/ic_launcher_bis.png
Binary files differ
diff --git a/app/res/drawable-xxhdpi/ic_launcher_tris.png b/app/res/drawable-xxhdpi/ic_launcher_tris.png
new file mode 100644
index 0000000..0bf88f3
--- /dev/null
+++ b/app/res/drawable-xxhdpi/ic_launcher_tris.png
Binary files differ
diff --git a/app/res/layout/activity_credits.xml b/app/res/layout/activity_credits.xml
new file mode 100644
index 0000000..871536c
--- /dev/null
+++ b/app/res/layout/activity_credits.xml
@@ -0,0 +1,17 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/ThemeDark">
+
+ <TextView
+ android:id="@+id/txt_credits"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:textColor="@color/ThemeLight"
+ android:textColorLink="@color/ThemeLight"
+ android:textSize="7pt"
+ android:scrollbars = "vertical" />
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/res/layout/activity_input_password.xml b/app/res/layout/activity_input_password.xml
new file mode 100644
index 0000000..a024879
--- /dev/null
+++ b/app/res/layout/activity_input_password.xml
@@ -0,0 +1,65 @@
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context=".InputPasswordActivity" >
+
+
+
+ <ScrollView
+ android:id="@+id/login_form"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background = "@color/black" >
+
+ <LinearLayout
+ style="@style/LoginFormContainer"
+ android:orientation="vertical"
+ android:background="@color/black"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/txt_insert_pass"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textCursorDrawable="@null"
+ android:textColor="@color/ThemeLight"
+ android:textSize="10pt"
+ android:layout_marginBottom="10dp"
+ android:background="@color/black"
+ android:maxLines = "10"
+ android:text="@string/insert_nets_password" />
+
+ <EditText
+ android:id="@+id/txt_password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"
+ android:textColor="@color/ThemeLight"
+ android:textSize="10pt"
+ android:maxLines="1"
+ android:singleLine="true" />
+
+ <CheckBox
+ android:id="@+id/chk_show_pass"
+ android:textColor="@color/ThemeLight"
+ android:text="@string/show_password"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:id="@+id/sign_in_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@color/ThemeDark"
+ android:textColor="@color/ThemeLight"
+ android:layout_gravity="right"
+ android:layout_marginTop="16dp"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:text="@string/button_text_next"
+ android:onClick="onBtnNextClick" />
+
+ </LinearLayout>
+ </ScrollView>
+
+</merge> \ No newline at end of file
diff --git a/app/res/layout/activity_long_task.xml b/app/res/layout/activity_long_task.xml
new file mode 100644
index 0000000..769144e
--- /dev/null
+++ b/app/res/layout/activity_long_task.xml
@@ -0,0 +1,25 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/black" >
+
+ <ProgressBar
+ android:id="@+id/progbar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true" />
+
+ <TextView
+ android:id="@+id/txt_msg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:layout_below="@id/progbar"
+ android:padding="10dp"
+ android:textColor="@color/ThemeLight" />
+
+
+</RelativeLayout> \ No newline at end of file
diff --git a/app/res/layout/activity_main.xml b/app/res/layout/activity_main.xml
new file mode 100644
index 0000000..3818751
--- /dev/null
+++ b/app/res/layout/activity_main.xml
@@ -0,0 +1,57 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="15dp"
+ android:background="@color/black" >
+
+ <TextView
+ android:id="@+id/txt_main"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textColor="@color/ThemeLight"
+ android:background="@color/black"
+ android:maxLines = "10"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp"
+ android:text="" />
+
+ <Button
+ android:id="@+id/btn_scan"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:layout_centerHorizontal="true"
+ android:textColor="@color/ThemeLight"
+ android:background="@color/ThemeDark"
+ android:text="@string/scan_networks"
+ android:onClick="btnScanClick"
+ android:layout_marginTop="15dp"
+ android:layout_marginBottom="20dp" />
+
+ <Button
+ android:id="@+id/btn_manage_nets"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/btn_scan"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:layout_centerHorizontal="true"
+ android:textColor="@color/ThemeLight"
+ android:background="@color/ThemeDark"
+ android:text="@string/manage_networks"
+ android:onClick="btnManageClick"
+ android:layout_marginBottom="20dp" />
+
+ <ImageView
+ android:id="@+id/img_logo"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/btn_manage_nets"
+ android:layout_margin="20dp" >
+
+ </ImageView>
+
+ </RelativeLayout> \ No newline at end of file
diff --git a/app/res/layout/activity_network_details.xml b/app/res/layout/activity_network_details.xml
new file mode 100644
index 0000000..a36c957
--- /dev/null
+++ b/app/res/layout/activity_network_details.xml
@@ -0,0 +1,38 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="15dp"
+ android:background="@color/black"
+ tools:context=".NetworkDetailsActivity" >
+
+ <TextView
+ android:id="@+id/txt_net_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:textColor="@color/ThemeLight"
+ android:textSize="7pt"
+ android:background="@color/black" />
+
+ <CheckBox
+ android:id="@+id/chk_show_pass_details"
+ android:layout_below="@id/txt_net_details"
+ android:textColor="@color/ThemeLight"
+ android:text="@string/show_password"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:id="@+id/btn_delete"
+ android:layout_below="@id/chk_show_pass_details"
+ android:layout_marginTop="15dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textColor="@color/ThemeLight"
+ android:background="@color/ThemeDark"
+ android:text="@string/delete"
+ android:onClick="btnDeleteClick" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/app/res/layout/activity_select_network.xml b/app/res/layout/activity_select_network.xml
new file mode 100644
index 0000000..2dd7958
--- /dev/null
+++ b/app/res/layout/activity_select_network.xml
@@ -0,0 +1,58 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/layout_selnets"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="15dp"
+ tools:context=".SelectNetworkActivity"
+ android:background="@color/black" >
+
+ <TextView
+ android:id="@+id/txt_selnets"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textColor="@color/ThemeLight"
+ android:textSize="10pt"
+ android:maxLines = "5"
+ android:scrollbars = "vertical"
+ android:layout_marginBottom="10dp" />
+
+ <Button
+ android:id="@+id/btn_rescan"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_selnets"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:layout_centerHorizontal="true"
+ android:textColor="@color/ThemeLight"
+ android:background="@color/ThemeDark"
+ android:text="@string/rescan"
+ android:onClick="btnScanClick" />
+
+ <ScrollView
+ android:id="@+id/scrollview"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_below="@id/btn_rescan"
+ android:layout_centerHorizontal="true"
+ android:scrollbars="vertical"
+ android:fillViewport="true"
+ android:textColor="@color/ThemeLight"
+ android:background="@color/White" >
+
+ <TableLayout
+ android:id="@+id/table_networks"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:isScrollContainer="true"
+ android:textColor="@color/ThemeLight"
+ android:background="@color/black" >
+ </TableLayout>
+
+
+ </ScrollView>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/app/res/layout/activity_show_status.xml b/app/res/layout/activity_show_status.xml
new file mode 100644
index 0000000..9f7e584
--- /dev/null
+++ b/app/res/layout/activity_show_status.xml
@@ -0,0 +1,43 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="15dp"
+ android:background="@color/black"
+ tools:context=".ShowStatusActivity" >
+
+ <TextView
+ android:id="@+id/txt_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:background="@color/black"
+ android:textColor="@color/ThemeLight" />
+
+ <Button
+ android:id="@+id/btn_disconnect"
+ android:background="@color/ThemeDark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/txt_status"
+ android:layout_marginTop="10dp"
+ android:textColor="@color/ThemeLight"
+ android:text="@string/disconnect"
+ android:onClick="onBtnDisconnectClick"/>
+
+ <Button
+ android:id="@+id/btn_back"
+ android:background="@color/ThemeDark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/txt_status"
+ android:layout_marginTop="10dp"
+ android:textColor="@color/ThemeLight"
+ android:text="@string/back_main"
+ android:onClick="onBtnMainClick"/>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/app/res/menu/activity_main.xml b/app/res/menu/activity_main.xml
new file mode 100644
index 0000000..cd7c0cb
--- /dev/null
+++ b/app/res/menu/activity_main.xml
@@ -0,0 +1,9 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/menu_credits"
+ android:orderInCategory="100"
+ android:showAsAction="never"
+ android:title="@string/menu_credits" />
+
+</menu> \ No newline at end of file
diff --git a/app/res/values-large/styles.xml b/app/res/values-large/styles.xml
new file mode 100644
index 0000000..acd524d
--- /dev/null
+++ b/app/res/values-large/styles.xml
@@ -0,0 +1,10 @@
+<resources>
+
+ <style name="LoginFormContainer">
+ <item name="android:layout_width">400dp</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:padding">16dp</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/app/res/values-v11/styles.xml b/app/res/values-v11/styles.xml
new file mode 100644
index 0000000..541752f
--- /dev/null
+++ b/app/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/app/res/values-v14/styles.xml b/app/res/values-v14/styles.xml
new file mode 100644
index 0000000..f20e015
--- /dev/null
+++ b/app/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/app/res/values/colors.xml b/app/res/values/colors.xml
new file mode 100644
index 0000000..22767c8
--- /dev/null
+++ b/app/res/values/colors.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="ThemeLight">#FFA500</color>
+ <color name="ThemeDark">#5F021F</color>
+ <color name="black">#000000</color>
+ <color name="White">#FFFFFF</color>
+</resources> \ No newline at end of file
diff --git a/app/res/values/strings.xml b/app/res/values/strings.xml
new file mode 100644
index 0000000..00168b5
--- /dev/null
+++ b/app/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">RepWifi App</string>
+ <string name="menu_credits">Info and Credits</string>
+ <string name="scan_networks">Scan for Networks</string>
+ <string name="title_activity_select_network">Select Network</string>
+ <string name="rescan">Repeat Scan</string>
+ <string name="button_text_next">Next &gt;</string>
+ <string name="insert_nets_password">Insert a Password to connect to:</string>
+ <string name="show_password">Show password</string>
+ <string name="title_activity_connect">ConnectActivity</string>
+ <string name="hello_world">Hello world!</string>
+ <string name="title_activity_show_status">Connection status</string>
+ <string name="back_main">Back to main</string>
+ <string name="disconnect">Disconnect</string>
+ <string name="force_disconnect">Force Disconnection</string>
+ <string name="title_activity_long_task">LongTaskActivity</string>
+ <string name="title_activity_manage_networks">ManageNetworksActivity</string>
+ <string name="delete">Delete network info</string>
+ <string name="manage_networks">Manage Networks</string>
+ <string name="title_activity_credits">Credits</string>
+ <string name="credit_text">Copyright 2017 Filippo \&quot;Fil\&quot; Bergamo&lt;br/&gt;&lt;br/&gt;This app is Free Software.&lt;br/&gt;It\'s licensed under the terms of &lt;a href=&quot;https://www.gnu.org/licenses/gpl.txt&quot;&gt;GPL v3&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;This app is developed as a contribution to &lt;br/&gt;&lt;a href=&quot;http://www.replicant.us&quot;&gt;The Replicant Project&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;u&gt;&lt;big&gt;Thank GNUs:&lt;/big&gt;&lt;/u&gt;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Tibi \&quot;tct\&quot; Turbureanu&lt;/b&gt;&lt;br/&gt;for having done the initial job of porting libre WiFi to Replicant 4.2.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Wolfgang Wiedmeyer&lt;/b&gt;&lt;br/&gt;for porting libre WiFi to Replicant 6.0 and for helping with the scripts.&lt;br/&gt;&lt;br/&gt;To report on bugs, request features, or any help request, please refer to:&lt;br/&gt;&lt;a href=&quot;http://redmine.replicant.us/projects/replicant/boards&quot;&gt;Replicant\'s Forum&lt;/a&gt;&lt;br/&gt;</string>
+
+</resources> \ No newline at end of file
diff --git a/app/res/values/strings_activity_input_password.xml b/app/res/values/strings_activity_input_password.xml
new file mode 100644
index 0000000..4770a51
--- /dev/null
+++ b/app/res/values/strings_activity_input_password.xml
@@ -0,0 +1,17 @@
+<resources>
+
+ <string name="title_activity_input_password">Insert passwrod for network</string>
+
+ <!-- Strings related to login -->
+ <string name="prompt_email">Email</string>
+ <string name="prompt_password">Password</string>
+ <string name="action_sign_in_register"><b>Sign in</b> or register</string>
+ <string name="action_sign_in_short">Sign in</string>
+ <string name="menu_forgot_password">Recover lost password</string>
+ <string name="login_progress_signing_in">Signing in&#8230;</string>
+ <string name="error_invalid_email">This email address is invalid</string>
+ <string name="error_invalid_password">This password is too short</string>
+ <string name="error_incorrect_password">This password is incorrect</string>
+ <string name="error_field_required">This field is required</string>
+
+</resources> \ No newline at end of file
diff --git a/app/res/values/styles.xml b/app/res/values/styles.xml
new file mode 100644
index 0000000..c414ecc
--- /dev/null
+++ b/app/res/values/styles.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/app/src/fil/libre/repwifiapp/Commons.java b/app/src/fil/libre/repwifiapp/Commons.java
new file mode 100644
index 0000000..dcf8893
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/Commons.java
@@ -0,0 +1,156 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp;
+
+import java.io.File;
+
+import fil.libre.repwifiapp.helpers.Engine4p2;
+import fil.libre.repwifiapp.helpers.Engine6p0;
+import fil.libre.repwifiapp.helpers.IEngine;
+import fil.libre.repwifiapp.helpers.NetworkManager;
+
+
+
+public abstract class Commons {
+
+
+ //------------- Enviromnet Constants ----------------------------------------
+ public static final String v4p2 = "4.2";
+ public static final String v6p0 = "6.0";
+ public static final String SCAN_FILE_HDR = "bssid / frequency / signal level / flags / ssid";
+ public static final String INTERFACE_NAME="wlan0";
+ public static final String WORKDIR = "/data/misc/wifi";
+ public static final String PID_FILE = WORKDIR + "/pidfile";
+ public static final String SOCKET_DIR = WORKDIR + "/sockets/";
+ public static final String SOFTAP_FILE = WORKDIR + "/softap.conf";
+ public static final String P2P_CONF = WORKDIR + "/p2p_supplicant.conf";
+ public static final String WPA_CONF = WORKDIR + "/wpa_supplicant.conf";
+ public static final String ENTROPY_FILE = WORKDIR + "/entropy.bin";
+ public static final String OVERLAY_FILE = "/system/etc/wifi/wpa_supplicant_overlay.conf";
+ //------------------------------------------------------------------------------
+
+ //------------- Shared Engines -----------------------
+ public static IEngine connectionEngine = null;
+ public static NetworkManager storage = null;
+ //----------------------------------------------------
+
+
+ //------------- Shared Resources ---------------------
+ public static int colorThemeDark;
+ public static int colorThemeLight;
+ public static int colorBlack;
+ //----------------------------------------------------
+
+ //------------- Activity Interaction -----------------
+ public static final String EXTRA_APINFO = "ExAPInfo";
+ public static final String EXTRA_APINFO_ARR = "ExAPInfoArr";
+ public static final String EXTRA_CONSTATUS = "ExConSts";
+ public static final String EXTRA_BOOLEAN = "ExBool";
+ public static final String EXTRA_REQCODE = "ExReqCode";
+ public static final String EXTRA_RESCAN = "ExRescan";
+ public static final String EXTRA_DELETE = "ExDelete";
+
+ public class RequestCode{
+ public static final int NONE = 0;
+ public static final int SELECT_CONN = 1;
+ public static final int PASS_INPUT = 2;
+ public static final int STATUS_SHOW = 3;
+ public static final int STATUS_GET = 4;
+ public static final int CONNECT = 5;
+ public static final int NETWORKS_GET = 6;
+ public static final int SELECT_DETAILS = 7;
+ public static final int DETAILS_SHOW = 8;
+ public static final int NETWORK_DELETE = 9;
+ }
+ //----------------------------------------------------
+
+
+ //----------------- Application Files --------------------
+ private static String APP_DATA_FOLDER;
+ public static void setAppDataFolder(String path){
+ File f = new File(path);
+ if (f.exists()){
+ APP_DATA_FOLDER = path;
+ }
+ }
+ public static String getNetworkStorageFile(){
+ if (APP_DATA_FOLDER == null){
+ return null;
+ }else{
+ return APP_DATA_FOLDER + "/repwifi_storage.conf";
+ }
+ }
+ public static String getScriptScan(){
+ return APP_DATA_FOLDER + "/scan.sh";
+ }
+ public static String getScriptScanRes(){
+ return APP_DATA_FOLDER + "/get_scan_results.sh";
+ }
+ public static String getScriptDhcpcd(){
+ return APP_DATA_FOLDER + "/run_dhcpcd.sh";
+ }
+ public static String getScanFile(){
+ return APP_DATA_FOLDER + "/scanres.txt";
+ }
+ public static String getStatusFile(){
+ return APP_DATA_FOLDER + "/tmpStatus";
+ }
+ public static String getGwFile(){
+ return APP_DATA_FOLDER + "/gw.txt";
+ }
+ public static String getTempOutFile(){
+ return APP_DATA_FOLDER + "/tmpout.txt";
+ }
+ //--------------------------------------------------------
+
+
+ //----------- Initialization methods ---------------------------
+ public static void initObjects()throws Exception{
+
+ initEngine();
+ initNetworkStorage();
+ }
+
+ private static void initEngine() throws Exception{
+
+ String vers = android.os.Build.VERSION.RELEASE;
+
+ if (vers.startsWith(Commons.v4p2)){
+ Commons.connectionEngine = new Engine4p2();
+ }
+ else if(vers.startsWith(Commons.v6p0)){
+ Commons.connectionEngine = new Engine6p0();
+ }
+ else{
+ throw new Exception("System version not recognized!");
+ }
+
+ }
+
+ private static void initNetworkStorage() throws Exception{
+
+ Commons.storage = new NetworkManager(getNetworkStorageFile());
+
+ }
+ //--------------------------------------------------------------
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/CreditsActivity.java b/app/src/fil/libre/repwifiapp/activities/CreditsActivity.java
new file mode 100644
index 0000000..4a0cb4c
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/CreditsActivity.java
@@ -0,0 +1,56 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.activities;
+
+import fil.libre.repwifiapp.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.text.Html;
+import android.text.method.LinkMovementMethod;
+import android.text.method.ScrollingMovementMethod;
+import android.view.Menu;
+import android.widget.TextView;
+
+public class CreditsActivity extends Activity {
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_credits);
+
+ String content = getResources().getString(R.string.credit_text);
+ TextView tv = (TextView)findViewById(R.id.txt_credits);
+ tv.setMovementMethod(new ScrollingMovementMethod());
+ tv.setText(Html.fromHtml(content));
+ tv.setMovementMethod(LinkMovementMethod.getInstance());
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ //getMenuInflater().inflate(R.menu.activity_credits, menu);
+ return true;
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java b/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java
new file mode 100644
index 0000000..e46d7d9
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java
@@ -0,0 +1,112 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.activities;
+
+
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.AccessPointInfo;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.InputType;
+import android.view.Menu;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.EditText;
+import android.widget.TextView;
+
+
+public class InputPasswordActivity extends Activity implements OnCheckedChangeListener{
+
+ AccessPointInfo apinfo = null;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.activity_input_password);
+
+ CheckBox c = (CheckBox)findViewById(R.id.chk_show_pass);
+ c.setOnCheckedChangeListener(this);
+
+ setTitle("Input password");
+
+ TextView v = (TextView)findViewById(R.id.txt_insert_pass);
+
+ //get the network to set password to:
+ this.apinfo = (AccessPointInfo)getIntent().getSerializableExtra(Commons.EXTRA_APINFO);
+ v.append(" " + apinfo.getSSID());
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ //super.onCreateOptionsMenu(menu);
+ //getMenuInflater().inflate(R.menu.activity_input_password, menu);
+ return true;
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+
+ if(buttonView == findViewById(R.id.chk_show_pass)){
+ chkShowPassChanged();
+ }
+ }
+
+ public void onBtnNextClick(View v){
+
+ EditText txpass = (EditText)findViewById(R.id.txt_password);
+ String pass = txpass.getText().toString();
+ if (pass.length()>0){
+
+ this.apinfo.setPassword(pass);
+
+ Intent intent = new Intent();
+ intent.putExtra(Commons.EXTRA_APINFO, this.apinfo);
+ setResult(RESULT_OK, intent);
+ finish();
+
+ }
+
+
+ }
+
+ public void chkShowPassChanged(){
+
+ CheckBox c = (CheckBox)findViewById(R.id.chk_show_pass);
+ EditText txtPass = (EditText)findViewById(R.id.txt_password);
+
+ if (c.isChecked()){
+ txtPass.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ txtPass.setSelection(txtPass.getText().length());
+ }else{
+ txtPass.setInputType(129);
+ txtPass.setSelection(txtPass.getText().length());
+ }
+
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java b/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java
new file mode 100644
index 0000000..a9f010a
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java
@@ -0,0 +1,174 @@
+package fil.libre.repwifiapp.activities;
+
+
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.AccessPointInfo;
+import fil.libre.repwifiapp.helpers.ConnectionStatus;
+import fil.libre.repwifiapp.helpers.Utils;
+
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.Menu;
+import android.widget.TextView;
+import android.app.Activity;
+import android.content.Intent;
+
+public class LongTaskActivity extends Activity {
+
+
+ private class Task extends AsyncTask<Object, Object, Object>{
+
+ private int REQ_CODE;
+
+ public Task(int reqCode, Object input){
+ this.REQ_CODE = reqCode;
+ }
+
+ @Override
+ protected Object doInBackground(Object... params) {
+
+ Object ret = null;
+
+ switch (this.REQ_CODE){
+
+ case Commons.RequestCode.CONNECT:
+
+ ret = Commons.connectionEngine.connect((AccessPointInfo)params[0]);
+ break;
+
+ case Commons.RequestCode.NETWORKS_GET:
+
+ ret = Commons.connectionEngine.getAvailableNetworks();
+ break;
+
+ case Commons.RequestCode.STATUS_GET:
+
+ ret = Commons.connectionEngine.getConnectionStatus();
+ break;
+
+ default:
+
+ break;
+
+ }
+
+ return ret;
+
+ }
+
+ protected void onPostExecute(Object result) {
+ taskCompleted(result, this.REQ_CODE);
+ }
+
+ }
+
+ private AccessPointInfo currentNetwork = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState){
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_long_task);
+
+ startTask();
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu){
+ return true;
+ }
+
+ private void startTask() {
+
+ //retrieve the request code:
+ Intent intent = getIntent();
+ if (! intent.hasExtra(Commons.EXTRA_REQCODE)){
+ this.setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ Object input = null;
+ int reqCode = intent.getExtras().getInt(Commons.EXTRA_REQCODE);
+
+ switch (reqCode) {
+
+ case Commons.RequestCode.CONNECT:
+ setTitle("Connecting...");
+ setMessage("Connecting...");
+ //Extract AccessPointInfo
+ input = intent.getExtras().getSerializable(Commons.EXTRA_APINFO);
+ currentNetwork = (AccessPointInfo)input;
+ break;
+
+ case Commons.RequestCode.NETWORKS_GET:
+ setTitle("Scanning...");
+ setMessage("Scanning for Networks...");
+
+ case Commons.RequestCode.STATUS_GET:
+ setTitle("Checking status...");
+ setMessage("Checking status...");
+
+ default:
+ setTitle("Please wait...");
+ setMessage("Please wait...");
+ break;
+ }
+
+ Task task = new Task(reqCode, input);
+ task.execute(input);
+
+ }
+
+ private void taskCompleted(Object result, int reqCode){
+
+ Utils.logDebug("Finished long task reqCode: "+ reqCode,1);
+
+ //Return to caller:
+ Intent intent = this.getIntent();
+
+
+ switch (reqCode){
+
+ case Commons.RequestCode.CONNECT:
+
+ intent.putExtra(Commons.EXTRA_BOOLEAN, (Boolean)result);
+ intent.putExtra(Commons.EXTRA_APINFO, this.currentNetwork);
+ break;
+
+ case Commons.RequestCode.NETWORKS_GET:
+
+ intent.putExtra(Commons.EXTRA_APINFO_ARR, (AccessPointInfo[])result);
+ break;
+
+ case Commons.RequestCode.STATUS_GET:
+
+ intent.putExtra(Commons.EXTRA_CONSTATUS, (ConnectionStatus)result);
+ break;
+
+ default:
+
+ Utils.logDebug("Task terminating in null: ",1);
+ break;
+
+ }
+
+ this.setResult(RESULT_OK, intent);
+ finish();
+
+ }
+
+
+ private void setMessage(String msg) {
+ TextView txt = (TextView)findViewById(R.id.txt_msg);
+ txt.setText(msg);
+ }
+
+ @Override
+ public void onBackPressed() {
+ //suppress
+ }
+
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/MainActivity.java b/app/src/fil/libre/repwifiapp/activities/MainActivity.java
new file mode 100644
index 0000000..aa92767
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/MainActivity.java
@@ -0,0 +1,378 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.activities;
+
+
+
+
+
+import java.io.IOException;
+
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Commons.RequestCode;
+import fil.libre.repwifiapp.helpers.AccessPointInfo;
+import fil.libre.repwifiapp.helpers.ConnectionStatus;
+import fil.libre.repwifiapp.helpers.NetworkManager;
+import fil.libre.repwifiapp.helpers.RootCommand;
+import fil.libre.repwifiapp.helpers.Utils;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+public class MainActivity extends Activity{
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ setImage();
+ setupSharedResources();
+
+ RootCommand su = new RootCommand(null);
+ try {
+ su.execute();
+ } catch (Exception e) {
+ Utils.logError("Error while trying to get first Super User access. Aborting.",e);
+ finish();
+ }
+
+ try {
+ Commons.initObjects();
+ } catch (Exception e) {
+ Utils.logError("Error on creating engine. Aborting.",e);
+ finish();
+ }
+
+
+ checkConnectionStatus();
+
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.activity_main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle item selection
+ switch (item.getItemId()) {
+ case R.id.menu_credits:
+ launchCreditsActivity();
+ return true;
+
+ default:
+ return true;
+ }
+ }
+
+ @Override
+ public void onRestart(){
+ super.onRestart();
+
+ ConnectionStatus status = Commons.connectionEngine.getConnectionStatus();
+ if (status != null && status.isConnected()){
+ launchStatusActivity(status);
+ }
+
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent){
+
+ Utils.logDebug("Main onActivityResult(): ",1);
+
+ if (intent == null){
+ return;
+ }
+
+ if (resultCode != RESULT_OK){
+ return;
+ }
+
+ AccessPointInfo i = null;
+ if (intent.hasExtra(Commons.EXTRA_APINFO)){
+ i = (AccessPointInfo)intent.getExtras().getSerializable(Commons.EXTRA_APINFO);
+ }
+
+ switch (requestCode) {
+
+ case RequestCode.PASS_INPUT:
+ handleResultSetPass(i);
+ break;
+
+ case RequestCode.SELECT_CONN:
+ boolean rescan = (boolean)intent.getExtras().getBoolean(Commons.EXTRA_RESCAN);
+ handleResultSelect(i, rescan);
+ break;
+
+ case RequestCode.CONNECT:
+ boolean conres = intent.getExtras().getBoolean(Commons.EXTRA_BOOLEAN);
+ handleFinishedConnecting(conres, i);
+ break;
+
+ case RequestCode.STATUS_GET:
+ ConnectionStatus status = (ConnectionStatus)intent.getExtras().getSerializable(Commons.EXTRA_CONSTATUS);
+ handleResultGetStatus(status);
+ break;
+
+ case RequestCode.NETWORKS_GET:
+ AccessPointInfo[] nets = (AccessPointInfo[])intent.getExtras().getSerializable(Commons.EXTRA_APINFO_ARR);
+ launchSelectActivity(nets, true);
+
+ case RequestCode.STATUS_SHOW:
+ //do nothing
+ break;
+
+ case RequestCode.SELECT_DETAILS:
+ launchDetailsActivity(i);
+ break;
+
+ case RequestCode.DETAILS_SHOW:
+ boolean del = intent.getExtras().getBoolean(Commons.EXTRA_DELETE);
+ if (del){ deleteNetwork(i); }
+ break;
+
+ default:
+
+ break;
+
+ }
+
+
+ }
+
+ private void setImage(){
+
+ ImageView img = (ImageView)findViewById(R.id.img_logo);
+
+ try {
+ Drawable d = Drawable.createFromStream(getAssets().open("repwifi-logo-0.png"),null);
+ img.setImageDrawable(d);
+ } catch (IOException e) {
+ Utils.logError("Error while loading logo image",e);
+ }
+
+ }
+
+ private void setupSharedResources(){
+ Commons.colorThemeDark = getResources().getColor(R.color.ThemeDark);
+ Commons.colorThemeLight = getResources().getColor(R.color.ThemeLight);
+ Commons.colorBlack = getResources().getColor(R.color.black);
+ Commons.setAppDataFolder(getExternalFilesDir(null).getAbsolutePath());
+ }
+
+ private void handleResultSelect(AccessPointInfo i, boolean rescan){
+
+ if (rescan){
+
+ doScan();
+
+ }else if (i != null){
+
+ if (i.needsPassword()){
+
+ //try to fetch network's password from storage
+ AccessPointInfo fromStorage = Commons.storage.getSavedNetwork(i);
+ if (fromStorage == null){
+
+ launchPasswordActivity(i);
+ return;
+
+ }else{
+ //use fetched network
+ i = fromStorage;
+ }
+
+ }
+
+ connectToNetwork(i);
+ }
+
+ }
+
+ private void handleResultSetPass(AccessPointInfo i){
+ connectToNetwork(i);
+ }
+
+ private void handleResultGetStatus(ConnectionStatus status){
+ if (status != null && status.isConnected()){
+ launchStatusActivity(status);
+ }
+ }
+
+ private void handleFinishedConnecting(boolean connectionResult, AccessPointInfo info){
+
+ if(connectionResult && info.needsPassword()){
+
+ //Save network
+ if (Commons.storage.save(info)){
+ Toast toast2 = Toast.makeText(getApplicationContext(), "Network Saved!",Toast.LENGTH_LONG);
+ toast2.show();
+
+ }else {
+ Toast toast2 = Toast.makeText(getApplicationContext(), "FAILED to save network!",Toast.LENGTH_LONG);
+ toast2.show();
+ }
+
+ checkConnectionStatus();
+
+ }else{
+ //alert that connection failed
+ Toast toast = Toast.makeText(getApplicationContext(), "FAILED to connect!", Toast.LENGTH_LONG);
+ toast.show();
+ }
+ }
+
+ private void launchPasswordActivity(AccessPointInfo info){
+
+ Intent intent = new Intent();
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.setClass(getApplicationContext(), InputPasswordActivity.class);
+ intent.putExtra(Commons.EXTRA_APINFO, info);
+
+ startActivityForResult(intent, RequestCode.PASS_INPUT);
+
+ }
+
+ private void launchStatusActivity(ConnectionStatus status){
+
+ Intent intent = new Intent();
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(Commons.EXTRA_CONSTATUS, status);
+ intent.setClass(getApplicationContext(), ShowStatusActivity.class);
+ startActivityForResult(intent, RequestCode.STATUS_SHOW);
+
+ }
+
+ private void launchSelectActivity(AccessPointInfo[] nets,boolean forConnection){
+
+ Intent intent = new Intent(this, SelectNetworkActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(Commons.EXTRA_APINFO_ARR, nets);
+
+ if (forConnection){
+ intent.putExtra(Commons.EXTRA_REQCODE, RequestCode.SELECT_CONN);
+ startActivityForResult(intent, RequestCode.SELECT_CONN);
+ }
+ else{
+ intent.putExtra(Commons.EXTRA_REQCODE, RequestCode.SELECT_DETAILS);
+ startActivityForResult(intent, RequestCode.SELECT_DETAILS);
+ }
+
+ }
+
+ private void launchDetailsActivity(AccessPointInfo info){
+
+ Intent intent = new Intent(this, NetworkDetailsActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(Commons.EXTRA_APINFO, info);
+ startActivityForResult(intent, RequestCode.DETAILS_SHOW);
+
+ }
+
+ private void launchCreditsActivity(){
+
+ Intent intent = new Intent(this, CreditsActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ startActivityForResult(intent, RequestCode.NONE);
+
+ }
+
+ private void deleteNetwork(AccessPointInfo info){
+
+ NetworkManager manager = new NetworkManager(Commons.getNetworkStorageFile());
+ String msg = "";
+ if (manager.remove(info)){
+ msg = "Network info deleted!";
+ }else{
+ msg = "FAILED to delete network info!";
+ }
+
+ Toast toast = Toast.makeText(this, msg, Toast.LENGTH_LONG);
+ toast.show();
+
+ }
+
+ private void connectToNetwork(AccessPointInfo info){
+
+ Intent intent = new Intent(this, LongTaskActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(Commons.EXTRA_REQCODE, RequestCode.CONNECT);
+ intent.putExtra(Commons.EXTRA_APINFO, info);
+ startActivityForResult(intent, RequestCode.CONNECT);
+
+ }
+
+ private void checkConnectionStatus(){
+
+ Intent intent = new Intent(this, LongTaskActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(Commons.EXTRA_REQCODE, RequestCode.STATUS_GET);
+ startActivityForResult(intent, RequestCode.STATUS_GET);
+
+ }
+
+ private void doScan(){
+
+ Intent intent = new Intent(this, LongTaskActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(Commons.EXTRA_REQCODE, RequestCode.NETWORKS_GET);
+ startActivityForResult(intent, RequestCode.NETWORKS_GET);
+
+ }
+
+ public void btnScanClick(View v){
+
+ doScan();
+
+ }
+
+ public void btnManageClick(View v){
+
+ NetworkManager manager = new NetworkManager(Commons.getNetworkStorageFile());
+ AccessPointInfo[] infos = manager.getKnownNetworks();
+
+ if (infos == null || infos.length == 0){
+ Toast toast = Toast.makeText(this, "No saved network", Toast.LENGTH_LONG);
+ toast.show();
+ }
+ else{
+ launchSelectActivity(infos, false);
+ }
+
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java b/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java
new file mode 100644
index 0000000..e43eee2
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java
@@ -0,0 +1,145 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.activities;
+
+import java.util.Date;
+
+
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.AccessPointInfo;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.text.format.DateFormat;
+import android.view.Menu;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+
+public class NetworkDetailsActivity extends Activity implements OnCheckedChangeListener {
+
+ private AccessPointInfo currentNetwor;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_network_details);
+
+ CheckBox c = (CheckBox)findViewById(R.id.chk_show_pass_details);
+ c.setOnCheckedChangeListener(this);
+
+ Intent intent = getIntent();
+ if (! intent.hasExtra(Commons.EXTRA_APINFO)){
+ this.setResult(RESULT_CANCELED);
+ this.finish();
+ return;
+ }
+
+ this.currentNetwor = (AccessPointInfo)intent.getExtras().getSerializable(Commons.EXTRA_APINFO);
+ if (this.currentNetwor == null){
+ this.setResult(RESULT_CANCELED);
+ this.finish();
+ return;
+ }
+
+ loadNetwork(false);
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ //getMenuInflater().inflate(R.menu.activity_manage_networks, menu);
+ return true;
+ }
+
+ private void loadNetwork(boolean showPassword){
+
+ setTitle(this.currentNetwor.getSSID());
+
+ TextView v = (TextView)findViewById(R.id.txt_net_details);
+ v.setText("SSID: " + this.currentNetwor.getSSID());
+ v.append("\nBSSID: " + this.currentNetwor.getBSSID());
+
+ long lastused = this.currentNetwor.getLastTimeUsed();
+ if (lastused > 0){
+ Date ts = new Date(lastused);
+ String formstring = "dd-MMM-yyyy kk:mm:ss";
+ v.append("\nLast Used: " + DateFormat.format(formstring, ts));
+ }
+
+ if (showPassword){
+ v.append("\n\nPassword:\n" + this.currentNetwor.getPassword());
+ }else{
+ v.append("\n\n\n");
+ }
+
+ }
+
+ public void btnDeleteClick(View v){
+
+
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
+ dlgAlert.setMessage("Are you sure you want to delete this network?");
+ dlgAlert.setPositiveButton("Yes",new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ returnResult(true);
+ }
+ });
+ dlgAlert.setNegativeButton("NO",new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ //nothing
+ }
+ });
+
+ dlgAlert.setCancelable(true);
+ dlgAlert.create().show();
+
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+
+ if (buttonView == findViewById(R.id.chk_show_pass_details)){
+ loadNetwork(isChecked);
+ }
+
+ }
+
+ private void returnResult(boolean delete){
+
+ Intent i = new Intent();
+ i.putExtra(Commons.EXTRA_DELETE, delete);
+ i.putExtra(Commons.EXTRA_APINFO, this.currentNetwor);
+ this.setResult(RESULT_OK,i);
+ finish();
+
+ }
+
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java b/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java
new file mode 100644
index 0000000..275ce08
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java
@@ -0,0 +1,222 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.activities;
+
+
+
+
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.AccessPointInfo;
+import fil.libre.repwifiapp.helpers.NetworkButton;
+import fil.libre.repwifiapp.helpers.Utils;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.content.Intent;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.Button;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+public class SelectNetworkActivity extends Activity implements OnClickListener {
+
+ private AccessPointInfo[] aps;
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_select_network);
+
+ setTitle("Select network");
+
+ getNetworks();
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ //getMenuInflater().inflate(R.menu.activity_select_network, menu);
+ return true;
+ }
+
+ private void writeOut(String msg) {
+
+ TextView v = (TextView)findViewById(R.id.txt_selnets);
+ v.setText(msg);
+
+ }
+
+ private void getNetworks(){
+
+ Intent intent = getIntent();
+ if(! intent.hasExtra(Commons.EXTRA_APINFO_ARR)){
+ this.setResult(RESULT_CANCELED);
+ finish();
+ return;
+ }
+ AccessPointInfo[] nets = (AccessPointInfo[])intent.getExtras().getSerializable(Commons.EXTRA_APINFO_ARR);
+ if (nets == null){
+ this.setResult(RESULT_CANCELED);
+ finish();
+ return;
+ }
+
+ int reqCode = intent.getExtras().getInt(Commons.EXTRA_REQCODE);
+
+ this.aps = nets;
+
+ if (reqCode == Commons.RequestCode.SELECT_CONN){
+ showNetworksForConnection(nets);
+ }
+ else{
+ showNetworksForManagement(nets);
+ }
+
+ }
+
+ public void btnScanClick(View v){
+ returnResults(null, true);
+ }
+
+ @Override
+ public void onClick(View v) {
+
+ if (v instanceof NetworkButton){
+ networkNameClick((NetworkButton)v);
+ }
+
+ }
+
+ public void networkNameClick(NetworkButton b){
+
+ for(AccessPointInfo i : this.aps){
+
+ if (i.getBSSID().equals(b.getNetworkBSSID())){
+
+ returnResults(i,false);
+
+ }
+
+ }
+ }
+
+ private void returnResults(AccessPointInfo i, boolean rescan){
+
+ Intent intent = new Intent();
+ intent.putExtra(Commons.EXTRA_APINFO, i);
+ intent.putExtra(Commons.EXTRA_RESCAN, rescan);
+ setResult(RESULT_OK, intent);
+ finish();
+
+ }
+
+ private void showNetworksForConnection(AccessPointInfo[] info) {
+
+ if (info == null){
+ Utils.logError("Unable to retrieve network list!");
+ writeOut("Unable to retrieve network list!");
+ return;
+ }
+
+ if (info.length == 0){
+ writeOut("No network found.");
+ toggleBtnRescan(true);
+ return;
+ }
+
+ writeOut("Select the network you want to connect to:");
+ toggleBtnRescan(false);
+
+ for (AccessPointInfo i : info){
+
+ addButtonForNetwork(i);
+
+ }
+
+ }
+
+ private void showNetworksForManagement(AccessPointInfo[] info){
+
+ if (info == null || info.length == 0){
+ return;
+ }
+
+ writeOut("Select network info to manage:");
+ toggleBtnRescan(false);
+
+ for (AccessPointInfo i : info){
+
+ addButtonForNetwork(i);
+
+ }
+
+ }
+
+ private void toggleBtnRescan(boolean enable) {
+
+ Button b = (Button)findViewById(R.id.btn_rescan);
+ if (enable){
+ b.setVisibility(View.VISIBLE);
+ }
+ else{
+ b.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private void addButtonForNetwork(AccessPointInfo info){
+
+ TableLayout s = (TableLayout)findViewById(R.id.table_networks);
+ TableLayout.LayoutParams tableParams = new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT);
+ TableRow row = new TableRow(this);
+ TableRow.LayoutParams rowParams = new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ rowParams.gravity = Gravity.FILL_HORIZONTAL;
+ row.setPadding(10, 10, 10, 10);
+ row.setLayoutParams(rowParams);
+ row.setGravity(Gravity.FILL_HORIZONTAL);
+ row.setLayoutParams(rowParams);
+
+ NetworkButton button = new NetworkButton(this, info.getBSSID());
+
+ TableRow.LayoutParams params = new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ button.setLayoutParams(params);
+ button.setBackgroundColor(Commons.colorThemeDark);
+ button.setTextColor(Commons.colorThemeLight);
+ button.setTextSize(20);
+ button.setPadding(10, 10, 10, 10);
+ button.setGravity(Gravity.CENTER_HORIZONTAL);
+ button.setText(info.getSSID());
+ button.setOnClickListener(this);
+
+ row.addView(button,params);
+ s.addView(row,tableParams);
+ s.setGravity(Gravity.FILL_HORIZONTAL);
+
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java b/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java
new file mode 100644
index 0000000..2674737
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java
@@ -0,0 +1,131 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+
+
+package fil.libre.repwifiapp.activities;
+
+
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.ConnectionStatus;
+import fil.libre.repwifiapp.helpers.Utils;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.view.Menu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class ShowStatusActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_show_status);
+ showStatus();
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ //getMenuInflater().inflate(R.menu.activity_show_status, menu);
+ return true;
+ }
+
+ @Override
+ public void onRestart(){
+ super.onRestart();
+ showStatus();
+ }
+
+ private void setMessage(String msg){
+ TextView view = (TextView)findViewById(R.id.txt_status);
+ view.setText(msg);
+ }
+
+ private void showStatus(){
+
+ ConnectionStatus status = Commons.connectionEngine.getConnectionStatus();
+ if (status == null){
+ this.finish();
+
+ }else if (status.isConnected()){
+ Utils.logDebug("StatusActivity isConnected,showing buttons");
+ setMessage("Connected to " + status.SSID + "\n\n" + "IP Address: " + status.IP + "\n");
+ toggleBtnDisconnect(true);
+
+
+ }else{
+ Utils.logDebug("StatusActivity status Else");
+ setMessage("Status:\n" + status.status);
+ toggleBtnDisconnect(false);
+
+ }
+ }
+
+ private void toggleBtnDisconnect(boolean enable){
+
+ Button b = (Button)findViewById(R.id.btn_disconnect);
+ Button bk = (Button)findViewById(R.id.btn_back);
+ b.setEnabled(enable);
+ bk.setEnabled(! enable);
+
+ if (enable){
+ b.setVisibility(View.VISIBLE);
+ bk.setVisibility(View.INVISIBLE);
+ }else{
+ b.setVisibility(View.INVISIBLE);
+ bk.setVisibility(View.VISIBLE);
+ }
+
+ }
+
+ public void onBtnDisconnectClick(View v){
+
+ boolean res = Commons.connectionEngine.disconnect();
+ String msg = "";
+ if (res){
+ msg = "Disconnected.";
+ }
+ else{
+ msg = "FAILED to disconnect!";
+ }
+
+ Toast toast = Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT);
+ toast.show();
+
+ showStatus();
+
+ }
+
+ public void onBtnMainClick(View v){
+ finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ moveTaskToBack(true);
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java b/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java
new file mode 100644
index 0000000..65c8b24
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java
@@ -0,0 +1,196 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import fil.libre.repwifiapp.Commons;
+
+
+public class AccessPointInfo implements Serializable{
+
+ private static final long serialVersionUID = 1L;
+
+ private String _ssid;
+ private String _bssid;
+ private String _auth;
+ private String _level;
+ private String _freq;
+ private String _password;
+ private long _lastTimeUsed;
+
+ public AccessPointInfo(String ssid, String bssid, String authType, String level, String freq){
+
+ this._ssid = ssid;
+ this._bssid = bssid;
+ this._auth = authType;
+ this._level = level;
+ this._freq = freq;
+
+ }
+
+ public String getSSID(){
+ return this._ssid;
+ }
+
+ public String getBSSID(){
+ return this._bssid;
+ }
+
+ public String getAuthType(){
+ return this._auth;
+ }
+
+ public String getSignlalStrength(){
+ return this._level;
+ }
+
+ public String getFrequency(){
+ return this._freq;
+ }
+
+ public long getLastTimeUsed(){
+ return this._lastTimeUsed;
+ }
+
+ public void setLastTimeUsed(long timeStampInMillis){
+ this._lastTimeUsed = timeStampInMillis;
+ }
+
+ public boolean isOlderThan(int days){
+
+ if (this._lastTimeUsed == 0){
+ return false;
+ }
+
+ long timeDiff = System.currentTimeMillis() - this._lastTimeUsed;
+ long spanMillis = Utils.daysToMilliseconds(days);
+
+ if (timeDiff > spanMillis){
+ return true;
+ }else{
+ return false;
+ }
+
+
+ }
+
+ public String getPassword(){
+ return this._password;
+ }
+
+ public void setPassword(String password){
+ this._password = password;
+ }
+
+ public boolean needsPassword(){
+
+ if ( (this._auth == null) || (this._auth.equals("")) ){
+ //TODO
+ //check if default behavior should be with or without password,
+ //when no auth info is available.
+ return false;
+ }
+
+ if (this._auth.contains("WPA2") || this._auth.contains("WPA")){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ }
+
+ protected static AccessPointInfo parseLine(String line){
+
+ try{
+
+ String[] params = line.split("\t");
+ if (params.length != 5){
+ return null;
+ }
+
+ String bssid = params[0];
+ String freq = params[1];
+ String level = params[2];
+ String auth = params[3];
+ String ssid = params [4];
+
+ AccessPointInfo info = new AccessPointInfo(ssid, bssid, auth, level, freq);
+ return info;
+
+ }catch (Exception e){
+ Utils.logError("Error while parsing line: " + line, e);
+ return null;
+ }
+
+ }
+
+ public static AccessPointInfo[] parseScanResult(String scanResultFile){
+
+ try {
+
+ File f = new File(scanResultFile);
+ if (! f.exists()){
+ Utils.logError("AccessPointInfo.parseScanResult(): The provided scan result file doesn't exist");
+ return null;
+ }
+
+ String[] lines = Utils.readFileLines(Commons.getScanFile());
+ List<AccessPointInfo> nets = new ArrayList<AccessPointInfo>();
+
+ for(String l : lines){
+ if (l.startsWith(Commons.SCAN_FILE_HDR)){
+ //strip off the header
+ continue;
+ }
+
+ if (l.trim().equals("")){
+ //empty line, skip.
+ continue;
+ }
+
+ //try to parse line into network info
+ AccessPointInfo info = AccessPointInfo.parseLine(l);
+ if (info == null){
+ Utils.logError("Failed to parse line into AccessPointInfo: " + l);
+ continue;
+ }
+
+ nets.add(info);
+
+ }
+
+ AccessPointInfo[] a = new AccessPointInfo[nets.size()];
+ a = nets.toArray(a);
+ return a;
+
+ } catch (Exception e) {
+ Utils.logError("Error while parsing scan results in class AccessPointInfo",e);
+ return null;
+ }
+
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java b/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java
new file mode 100644
index 0000000..f7cb8d7
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java
@@ -0,0 +1,106 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import java.io.Serializable;
+
+public class ConnectionStatus implements Serializable{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ public static final String STATUS_CONNECTED = "COMPLETED";
+ public static final String STATUS_INACTIVE = "INACTIVE";
+ public static final String STATUS_DISCONNECTED = "DISCONNECTED";
+ public static final String STATUS_UNDEFINED = "UNDEFINED";
+
+ public String status;
+ public String SSID;
+ public String BSSID;
+ public String IP;
+
+ private static final String F_SEP = "=";
+ private static final String KeyStatus = "wpa_state";
+ private static final String KeySSID = "ssid";
+ private static final String KeyBSSID = "bssid";
+ private static final String KeyIP = "ip_address";
+
+ public static ConnectionStatus parseWpaCliOutput(String wpaCliOutput){
+
+ if (wpaCliOutput == null){
+ return null;
+ }
+
+ if (wpaCliOutput.trim().length() == 0){
+ return null;
+ }
+
+ String[] lines = wpaCliOutput.split("\n");
+
+ ConnectionStatus s = new ConnectionStatus();
+ for(String line : lines){
+
+ if (line.trim().equals("")){
+ continue;
+ }
+
+ String[] fields = line.split(F_SEP);
+ if(fields.length < 2){
+ continue;
+ }
+
+ String key = fields[0];
+ String val = fields[1];
+
+ if (key.equals(KeyBSSID)){
+ s.BSSID = val;
+ }
+ else if (key.equals(KeySSID)){
+ s.SSID = val;
+ }
+ else if (key.equals(KeyStatus)){
+ s.status = val;
+ }
+ else if (key.equals(KeyIP)){
+ s.IP = val;
+ }
+
+ }
+
+ return s;
+
+ }
+
+ public boolean isConnected(){
+
+ if (this.status == null){
+ return false;
+ }
+
+ if (this.status.equals(STATUS_CONNECTED)){
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/Engine.java b/app/src/fil/libre/repwifiapp/helpers/Engine.java
new file mode 100644
index 0000000..cdddb0b
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/Engine.java
@@ -0,0 +1,397 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import fil.libre.repwifiapp.Commons;
+
+
+public abstract class Engine implements IEngine{
+
+ protected String getCmdWpaSup(){
+ return "wpa_supplicant -B -dd -i" + Commons.INTERFACE_NAME + " -C\"" +Commons.SOCKET_DIR + "\" -P\"" + Commons.PID_FILE + "\"";
+ }
+
+ protected String getCmdWpaCli() {
+ return "wpa_cli -p" + Commons.SOCKET_DIR + " -P" + Commons.PID_FILE + " -i" + Commons.INTERFACE_NAME;
+ }
+
+ protected abstract String getCmdWpaStart();
+
+ public static final String DNS1 = "193.183.98.154";
+ public static final String DNS2 = "87.98.175.85";
+
+ public boolean deleteFileIfExists(String filePath){
+
+ if (filePath == null){
+ return false;
+ }
+
+ if (filePath.contains("*")){
+ //it's safer to reject bulk rm'ing
+ return false;
+ }
+
+ if (filePath.contains(" -r ")){
+ //only file rm'ing acceppted
+ return false;
+ }
+
+ return executeRootCmd("if [ -e \""+ filePath + "\" ]; then rm \"" + filePath + "\"; fi");
+ }
+
+ public boolean chmodFile(String filePath, String mod){
+ return executeRootCmd("chmod " + mod + " \"" + filePath + "\"");
+ }
+
+ @Override
+ public boolean killPreviousConnections() {
+
+ Utils.logDebug("killing wpa_supplicant..:");
+ if (executeRootCmd("killall -SIGINT wpa_supplicant")){
+ Utils.logDebug("Killed wpa_supplicant");
+ }else{
+ Utils.logDebug("Wpa_supplicant NOT killed.");
+ }
+
+ Utils.logDebug("killing dhcpcd..");
+ if (executeRootCmd("killall -SIGINT dhcpcd")){
+ Utils.logDebug("Killed dhcpcd");
+ }else{
+ Utils.logDebug("dhcpcd NOT killed.");
+ }
+
+
+ return true;
+
+ }
+
+ @Override
+ public boolean clearWorkingDir(){
+
+ Utils.logDebug("clearWorkingDir():");
+
+ if (executeRootCmd("rm -r " + Commons.SOCKET_DIR)){
+ Utils.logDebug("removed socket dir");
+ }
+
+ if (executeRootCmd("rm " + Commons.ENTROPY_FILE)){
+ Utils.logDebug("removed entropy file");
+ }
+
+ if (executeRootCmd("rm " + Commons.PID_FILE)){
+ Utils.logDebug("removed pidfile");
+ }
+
+ if (executeRootCmd("rm " + Commons.SOFTAP_FILE)){
+ Utils.logDebug("removed softap file");
+ }
+
+ if (executeRootCmd("rm " + Commons.WPA_CONF)){
+ Utils.logDebug("removed wpa conf file");
+ }
+
+ if (executeRootCmd("rm " + Commons.P2P_CONF)){
+ Utils.logDebug("removed p2p conf file");
+ }
+
+
+ return true;
+
+ }
+
+ @Override
+ public boolean startWpaSupplicant(){
+
+ Utils.logDebug("startWpaSupplicant():");
+
+ if (executeRootCmd(getCmdWpaSup())){
+ return true;
+ }else{
+ Utils.logDebug("Failed to start wpa");
+ return false;
+ }
+
+ }
+
+ @Override
+ public AccessPointInfo[] getAvailableNetworks(){
+
+ Utils.logDebug("getAvailableNetworks():");
+
+ killPreviousConnections();
+
+ if (! clearWorkingDir()){
+ Utils.logError("Failed clearing dir");
+ return null;
+ }
+
+ if (! startWpaSupplicant()){
+ Utils.logError("Failed starting wpa_supplicant");
+ return null;
+ }
+
+ if (! createScanScripts()){
+ Utils.logError("Failed creating scripts");
+ return null;
+ }
+
+ if (! scanNetworks()){
+ Utils.logError("failed scanning networks");
+ return null;
+ }
+
+ if (!getScanResults()){
+ Utils.logError("failed getting scan results");
+ return null;
+ }
+
+ //chmod 666 scan_file to make it readable
+ if (!chmodFile(Commons.getScanFile(), "666")){
+ Utils.logError("failed chmodding scan_file");
+ return null;
+ }
+
+ AccessPointInfo[] a = AccessPointInfo.parseScanResult(Commons.getScanFile());
+ if (a == null){
+ Utils.logError("Unable to parse scan file into AccessPointInfo array");
+ }
+
+
+ return a;
+
+ }
+
+ @Override
+ public abstract boolean connect(AccessPointInfo info);
+
+ @Override
+ public boolean disconnect(){
+
+ if (! isWpaSupplicantRunning()){
+ return true;
+ }
+
+ try {
+
+ RootCommand su = new RootCommand(getCmdWpaCli() + " disconnect");
+ if (su.execute() == 0){
+ String out = su.getOutput();
+ if (out != null && out.trim().replace("\n", "").equals("OK")){
+ return true;
+ }else {
+ return false;
+ }
+ }
+ else{
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while enabling network", e);
+ return false;
+ }
+ }
+
+ /***
+ * returns null if unable to determine connection status for any reason.
+ */
+ @Override
+ public ConnectionStatus getConnectionStatus(){
+
+ Utils.logDebug("called getConnecitonStatus()");
+ if (! isWpaSupplicantRunning()){
+ //wpa_supplicant is not running.
+ //unable to determin status.
+ Utils.logDebug("wpa not running, cannot get connection status.");
+ return null;
+
+ }
+
+ try {
+
+ RootCommand su = new RootCommand(getCmdWpaCli() + " status");
+ if(su.execute() == 0){
+ String out = su.getOutput();
+ if (out == null || out.trim().equals("")){
+ return null;
+ }
+ else {
+ return ConnectionStatus.parseWpaCliOutput(out);
+ }
+ }
+ else {
+ return null;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while executing wpa_cli status", e);
+ return null;
+ }
+
+ }
+
+ public boolean runDhcpcd(){
+
+ return executeRootCmd("dhcpcd " + Commons.INTERFACE_NAME);
+
+ }
+
+ public boolean interfaceUp(){
+ return executeRootCmd("ifconfig " + Commons.INTERFACE_NAME + " up");
+ }
+
+ protected boolean executeRootCmd(String cmd){
+
+ try {
+
+ RootCommand c = new RootCommand(cmd);
+ if ( c.execute() == 0){
+ return true;
+ }else {
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error executing \"" + cmd + "\"",e);
+ return false;
+ }
+ }
+
+ protected boolean isWpaSupplicantRunning(){
+
+ boolean retval = false;
+
+ try {
+
+ RootCommand su = new RootCommand("pidof wpa_supplicant");
+ if (su.execute() == 0){
+
+ if (su.getOutput().trim().equals("")){
+ retval = false;
+ }else{
+ retval = true;
+ }
+
+ }else {
+ retval = false;
+ }
+
+
+ } catch (Exception e) {
+ Utils.logError("Exception during isWpaSupplicantRunning()",e);
+ retval = false;
+ }
+
+ return retval;
+
+ }
+
+ protected boolean scanNetworks(){
+
+ return executeRootCmd("bash " + Commons.getScriptScan());
+
+ }
+
+ protected boolean getScanResults(){
+
+ return executeRootCmd("bash " + Commons.getScriptScanRes());
+
+ }
+
+ protected boolean createScanScripts(){
+
+ try {
+
+ String scan = getCmdWpaCli() + " scan\n" +
+ "if [ $? -ne 0 ]; then\n" +
+ "exit 1\n" +
+ "fi\n" +
+ "sleep 2s\n";
+
+ String scanRes = "if [ -e \"" + Commons.getScanFile() + "\" ]; then\n" +
+ " rm \"" + Commons.getScanFile() + "\"\n" +
+ "fi\n" +
+ getCmdWpaCli() + " scan_results > \""+ Commons.getScanFile() + "\"\n" +
+ "if [ $? -ne 0 ]; then\n" +
+ " exit 1\n" +
+ "fi\n" +
+ "sleep 1s\n";
+
+
+ //Try to create and chmod script scan
+ /* executeRootCmd("echo > " + Commons.getSCRIPT_SCAN());
+ chmodFile(Commons.getSCRIPT_SCAN(), "666");*/
+
+
+ if (! Utils.writeFile(Commons.getScriptScan(),scan,true) ){
+
+ Exception e = Utils.getLastException();
+ if (e != null){
+ Utils.logError("Error while writing scan script.",e);
+ }
+
+ return false;
+ }
+
+ //Try to create and chmod script scanres
+ /*executeRootCmd("echo > " + Commons.getSCRIPT_SCANRES());
+ chmodFile(Commons.getSCRIPT_SCANRES(), "666");*/
+
+ if (! Utils.writeFile(Commons.getScriptScanRes(),scanRes,true) ){
+
+ Exception e = Utils.getLastException();
+ if (e != null){
+ Utils.logError("Error while writing getScanResults script.",e);
+ }
+
+ return false;
+ }
+
+
+ return true;
+
+ } catch (Exception e) {
+
+ Utils.logError("Error while creating the scanning script.",e);
+ return false;
+ }
+
+ }
+
+ /*protected boolean createDhcpcdScritp(){
+
+ String scriptDhcp = "dhcpcd "+ Commons.INTERFACE_NAME + "\n" +
+ "sleep 3s\n";
+
+ if (! Utils.writeFile(Commons.getScriptDhcpcd(),scriptDhcp,true) ){
+
+ Exception e = Utils.getLastException();
+ if (e != null){
+ Utils.logError("Error while writing dhcpcd script.",e);
+ }
+
+ return false;
+ }
+
+ return true;
+
+ }*/
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/Engine4p2.java b/app/src/fil/libre/repwifiapp/helpers/Engine4p2.java
new file mode 100644
index 0000000..12d8da8
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/Engine4p2.java
@@ -0,0 +1,131 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import fil.libre.repwifiapp.Commons;
+
+
+public class Engine4p2 extends Engine{
+
+ @Override
+ protected String getCmdWpaStart(){
+ return "wpa_supplicant -B -dd -i" + Commons.INTERFACE_NAME + " -C\"" + Commons.SOCKET_DIR + "\" -c\"" + Commons.WPA_CONF + "\" -P\"" + Commons.PID_FILE + "\"";
+ }
+
+ public boolean loadModules(){
+ try {
+ //TODO
+ //implement kernel modules loading
+ return true;
+ } catch (Exception e) {
+ Utils.logError("Error while loading kernel modules",e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean connect(AccessPointInfo info){
+
+ killPreviousConnections();
+
+ if (info == null){
+ Utils.logDebug("Engine's connect() received a null AccessPointInfo");
+ return false;
+ }
+
+ if (! createConfigFile(info)){
+ return false;
+ }
+
+ //launch wpa_supplicant specifying our custom configuration and the socket file
+ if (! executeRootCmd(getCmdWpaStart())){
+ Utils.logError("wpa_supplicant connection command failed.");
+ return false;
+ }
+
+ //negotiate DHCP lease
+ if (!runDhcpcd()){
+ return false;
+ }
+
+ //set DNS's
+ if (! executeRootCmd("setprop net.dns1 " + DNS1)){
+ Utils.logError("setting dns1 failed");
+ return false;
+ }
+
+ if (! executeRootCmd("setprop net.dns2 " + DNS2)){
+ Utils.logError("setting dns2 failed");
+ return false;
+ }
+
+ //TODO
+ //implement wpa_cli command to query wpa_supplicant's state
+ //in order to confirm that connection was successful.
+
+ return true;
+
+ }
+
+ private boolean createConfigFile(AccessPointInfo info){
+
+ try {
+
+ if (! deleteFileIfExists(Commons.WPA_CONF)){
+ Utils.logError("Unable to remove wpa_supplicant.conf before writing it.");
+ return false;
+ }
+
+ String configText = "ctrl_interface=DIR=" + Commons.SOCKET_DIR + "\n" +
+ "update_config=1\n" +
+ "network={\n"+
+ " ssid=\"" + info.getSSID() + "\"\n";
+
+ if (info.needsPassword()){
+ configText += " psk=\""+ info.getPassword() + "\"\n";
+ }else {
+ configText += " key_mgmt=NONE\n";
+ }
+
+ configText += "}\n";
+
+ if ( ! Utils.writeFile(Commons.WPA_CONF, configText, true) ){
+ Utils.logError("Unable to write wpa_supplicant.conf file!");
+ return false;
+ }
+
+ //chmod wpa_supplicant.conf, in order to make it accessible
+ if(chmodFile(Commons.WPA_CONF, "666")){
+ return true;
+ }else {
+ Utils.logError("Unable to chmod wpa_supplicant.conf");
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while creating wpa_supplicant.conf",e);
+ return false;
+ }
+
+ }
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java b/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java
new file mode 100644
index 0000000..24096d2
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java
@@ -0,0 +1,360 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import fil.libre.repwifiapp.Commons;
+
+
+public class Engine6p0 extends Engine{
+
+ @Override
+ protected String getCmdWpaStart(){
+ return "wpa_supplicant -B -dd -i" + Commons.INTERFACE_NAME + " -C" + Commons.SOCKET_DIR + " -P" + Commons.PID_FILE + " -I" + Commons.OVERLAY_FILE + " -e" + Commons.ENTROPY_FILE;
+ }
+
+ @Override
+ public boolean connect(AccessPointInfo info){
+
+ killPreviousConnections();
+
+ if (info == null){
+ Utils.logDebug("Engine's connect() received a null AccessPointInfo");
+ return false;
+ }
+
+ //clear any previously set network
+ if (! destroyNetwork()){
+ Utils.logDebug("Unable to ndc destroy network");
+ return false;
+ }
+
+ //clear interface's ip
+ if (! clearAddrs()){
+ Utils.logDebug("Unable to ndc clearaddrs");
+ return false;
+ }
+
+ //bring up interface
+ if(! interfaceUp()){
+ Utils.logDebug("Unable to bring up interface.");
+ return false;
+ }
+
+ //launch wpa_supplicant specifying our custom configuration and the socket file
+ if (! executeRootCmd(getCmdWpaStart())){
+ Utils.logDebug("Unable to run wpa start");
+ return false;
+ }
+
+ //create new network and get network id
+ String netID = createNetworkGetId();
+ if (netID == null){
+ Utils.logDebug("Unable to fetch network id");
+ return false;
+ }
+
+ //set network SSID
+ if (! setNetworkSSID(info.getSSID(), netID)){
+ Utils.logDebug("Failed to set network ssid");
+ return false;
+ }
+
+ //set password (if any)
+ if(! setNetworkPSK(info, netID)){
+ Utils.logDebug("Failed to set network psk");
+ return false;
+ }
+
+ // select the network we just created
+ if (! selectNetwork(netID)){
+ Utils.logDebug("Unable to wpa_cli select network");
+ return false;
+ }
+
+ //enable the newtork
+ if (! enableNetwork(netID)){
+ Utils.logDebug("Unable to wpa_cli enable_newtork");
+ return false;
+ }
+
+ //try to reassociate to Access Point
+ if (! reassociate()){
+ Utils.logDebug("Unable to wpa_cli reassociate");
+ return false;
+ }
+
+ //get DHCP
+ Utils.logDebug("Attempt to run dhcpcd..");
+ if (!runDhcpcd()){
+ Utils.logDebug("Failed to run dhcpcd");
+ return false;
+ }
+
+ //try to fetch gateway
+ String gw = getGateway();
+ if (gw == null || gw.trim().length() < 7){
+ //failed to get gateway
+ Utils.logDebug("Failed to get gateway");
+ return false;
+ }
+
+ if (! executeRootCmd("ndc network create 1")){
+ Utils.logDebug("Failed to wpa_cli network create 1 ");
+ return false;
+ }
+
+ if (! executeRootCmd("ndc network interface add 1 " + Commons.INTERFACE_NAME)){
+ Utils.logDebug("Failed to add interface.");
+ return false;
+ }
+
+ // set route to gateway for all traffic
+ if (! executeRootCmd("ndc network route add 1 " + Commons.INTERFACE_NAME + " 0.0.0.0/0 " + gw)){
+ Utils.logDebug("Failed to add route to gateway");
+ return false;
+ }
+
+ //set DNS
+ if (! executeRootCmd("ndc resolver setnetdns 1 " + " " + DNS1 + " " + DNS2)){
+ Utils.logDebug("Failed to set DNS");
+ return false;
+ }
+
+ //use network
+ if (! executeRootCmd("ndc network default set 1")){
+ Utils.logDebug("Failed to set network as default");
+ return false;
+ }
+
+ //TODO
+ //implement wpa_cli query for status
+ //in order to be sure that connection is extablished
+
+ return true;
+
+
+
+ }
+
+ private String createNetworkGetId(){
+
+ try {
+
+ RootCommand su = new RootCommand(getCmdWpaCli() + " add_network");
+ if(su.execute() == 0){
+ String out = su.getOutput();
+ if (out == null || out.trim().equals("")){
+ return null;
+ }
+ else {
+ return out.replace("\n", "");
+ }
+ }
+ else {
+ return null;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while creating network", e);
+ return null;
+ }
+
+ }
+
+ private boolean destroyNetwork(){
+ return executeRootCmd("ndc network destroy 1");
+ }
+
+ private boolean setNetworkSSID(String ssid, String networkID){
+
+ try {
+
+ RootCommand su = new RootCommand(getCmdWpaCli() + " set_network " + networkID + " ssid '\"" + ssid + "\"'" );
+ if (su.execute() == 0){
+ String out = su.getOutput();
+ if (out != null && out.trim().replace("\n", "").equals("OK")){
+ return true;
+ }else {
+ return false;
+ }
+ }
+ else{
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while setting network SSID", e);
+ return false;
+ }
+
+ }
+
+ private boolean setNetworkPSK(AccessPointInfo info, String networkID){
+
+ try {
+
+ String cmdSetPass = null;
+ if (info.needsPassword()){
+ cmdSetPass = getCmdWpaCli() + " set_network " + networkID + " psk '\"" + info.getPassword() + "\"'";
+ }
+ else{
+ cmdSetPass = getCmdWpaCli() + " set_network " + networkID + " key_mgmt NONE";
+ }
+
+ RootCommand su = new RootCommand(cmdSetPass);
+ if (su.execute() == 0){
+ String out = su.getOutput();
+ if (out != null && out.trim().replace("\n", "").equals("OK")){
+ return true;
+ }else {
+ return false;
+ }
+ }
+ else{
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while setting network PSK", e);
+ return false;
+ }
+
+
+ }
+
+ private boolean selectNetwork(String networkID){
+
+ try {
+
+ RootCommand su = new RootCommand(getCmdWpaCli() + " select_network " + networkID);
+ if (su.execute() == 0){
+ String out = su.getOutput();
+ if (out != null && out.trim().replace("\n", "").equals("OK")){
+ return true;
+ }else {
+ return false;
+ }
+ }
+ else{
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while selecting network", e);
+ return false;
+ }
+
+ }
+
+ private boolean enableNetwork(String networkID){
+
+ try {
+
+ RootCommand su = new RootCommand(getCmdWpaCli() + " enable_network " + networkID);
+ if (su.execute() == 0){
+ String out = su.getOutput();
+ if (out != null && out.trim().replace("\n", "").equals("OK")){
+ return true;
+ }else {
+ return false;
+ }
+ }
+ else{
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while enabling network", e);
+ return false;
+ }
+
+ }
+
+ private boolean reassociate(){
+
+ try {
+
+ RootCommand su = new RootCommand(getCmdWpaCli() + " reassociate");
+ if (su.execute() == 0){
+ String out = su.getOutput();
+ if (out != null && out.trim().replace("\n", "").equals("OK")){
+ return true;
+ }else {
+ return false;
+ }
+ }
+ else{
+ return false;
+ }
+
+ } catch (Exception e) {
+ Utils.logError("Error while reassociating network", e);
+ return false;
+ }
+
+ }
+
+ private String getGateway(){
+
+ try {
+
+ RootCommand su = new RootCommand("ip route show dev " + Commons.INTERFACE_NAME);
+ if (su.execute() != 0){
+ Utils.logDebug("command failed show route");
+ return null;
+ }
+
+ //read command output
+ String out = su.getOutput();
+ if (out == null){
+ return null;
+ }
+
+ String[] lines = out.split("\n");
+
+ for (String l : lines){
+
+ if (l.contains("default via")){
+
+ String[] f = l.split(" ");
+ if (f.length > 2){
+
+ //found route's address:
+ return f[2];
+
+ }
+ }
+ }
+
+ return null;
+
+ } catch (Exception e) {
+ Utils.logError("Error while trying to fetch route",e);
+ return null;
+ }
+
+ }
+
+ private boolean clearAddrs(){
+ return executeRootCmd("ndc interface clearaddrs " + Commons.INTERFACE_NAME);
+ }
+
+} \ No newline at end of file
diff --git a/app/src/fil/libre/repwifiapp/helpers/IEngine.java b/app/src/fil/libre/repwifiapp/helpers/IEngine.java
new file mode 100644
index 0000000..67ffb86
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/IEngine.java
@@ -0,0 +1,41 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+
+public interface IEngine {
+
+ public boolean startWpaSupplicant();
+
+ public boolean killPreviousConnections();
+
+ public boolean clearWorkingDir();
+
+ public AccessPointInfo[] getAvailableNetworks();
+
+ public boolean connect(AccessPointInfo info);
+
+ public boolean disconnect();
+
+ public ConnectionStatus getConnectionStatus();
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/NetworkButton.java b/app/src/fil/libre/repwifiapp/helpers/NetworkButton.java
new file mode 100644
index 0000000..9a7c523
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/NetworkButton.java
@@ -0,0 +1,41 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import android.content.Context;
+import android.widget.Button;
+
+public class NetworkButton extends Button{
+
+ private String _bssid = "";
+
+ public NetworkButton(Context context, String networkBSSID){
+ super(context);
+ this._bssid = networkBSSID;
+ }
+
+ public String getNetworkBSSID(){
+ return this._bssid;
+ }
+
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java b/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java
new file mode 100644
index 0000000..bc59862
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java
@@ -0,0 +1,288 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import java.io.File;
+import java.util.ArrayList;
+
+public class NetworkManager {
+
+ private static final String F_SEP = "\t";
+ private static final int NET_MAX_AGE = 365; //Expressed in days
+
+ private String _knownNetworksFile = null;
+
+ public NetworkManager(String networksFilePath){
+ this._knownNetworksFile = networksFilePath;
+ }
+
+ private AccessPointInfo searchInFile(AccessPointInfo i){
+
+ if (i == null){
+ return null;
+ }
+
+ String bssid = i.getBSSID();
+ String ssid = i.getSSID();
+
+ if (bssid == null || ssid == null || bssid.trim().equals("") || ssid.trim().equals("")){
+ return null;
+ }
+
+ AccessPointInfo ret = null;
+ AccessPointInfo[] list = getKnownNetworks();
+
+ if (list == null){
+ return null;
+ }
+
+ for(AccessPointInfo toTest : list){
+
+ // try to match both bssid and ssid.
+ // if bssid doesn't match, but ssid does,
+ // then the network is a candidate.
+ // if no bssid equality is found,
+ // then return the best match (only ssid), if any
+ if (toTest.getSSID().equals(ssid)){
+
+ if (toTest.getBSSID().equals(bssid)){
+ i.setPassword(toTest.getPassword());
+ return i;
+
+ }else{
+ i.setPassword(toTest.getPassword());
+ ret = i;
+ }
+
+ }
+
+ }
+
+ return ret;
+
+ }
+
+ private boolean saveOrRemove(AccessPointInfo info, boolean save){
+
+ String iText = InfoToString(info);
+ if (iText == null){
+ return false;
+ }
+
+ AccessPointInfo[] existingNets = getKnownNetworks();
+
+ ArrayList<AccessPointInfo> newlist = new ArrayList<AccessPointInfo>();
+
+ if (existingNets == null || existingNets.length == 0){
+ //no existing storage yet, create it
+
+ if (save){
+ //set timestamp
+ info.setLastTimeUsed(System.currentTimeMillis());
+ newlist.add(info);
+ AccessPointInfo[] newContents = new AccessPointInfo[newlist.size()];
+ newContents = newlist.toArray(newContents);
+
+ return saveList(newContents);
+
+ }else{
+ //nothing to do, return
+ return true;
+ }
+
+ }
+
+ for(AccessPointInfo old : existingNets){
+
+ if (old == null){
+ continue;
+ }
+
+ if (old.getBSSID().equals(info.getBSSID()) && old.getSSID().equals(info.getSSID())){
+
+ //found previous entry for this network,
+ //if the call is for saving, overwrite the entry with the new one,
+ //else omit the line, to remove network from the saved list.
+ if (save){
+ info.setLastTimeUsed(System.currentTimeMillis());
+ newlist.add(info);
+ }
+
+ }else{
+ //other network, keep it in the file
+ // only if it's not older than the max age for a network
+ if (! info.isOlderThan(NET_MAX_AGE)){
+ newlist.add(old);
+ }
+ }
+
+ }
+
+ AccessPointInfo[] newContents = new AccessPointInfo[newlist.size()];
+ newContents = newlist.toArray(newContents);
+
+ return saveList(newContents);
+
+ }
+
+ private AccessPointInfo getFromString(String savedString){
+
+ if (savedString == null || savedString.trim().equals("")) {
+ return null;
+ }
+
+ String[] fields = savedString.split(F_SEP);
+
+ if (fields.length != 4 ){
+ return null;
+ }
+
+ String bssid = fields[0];
+ String ssid = fields[1];
+ String pass = fields[2];
+ String lastUsed = fields[3];
+
+ long lastusedmillis = 0;
+ try {
+ lastusedmillis = Long.parseLong(lastUsed);
+ } catch (NumberFormatException e) {
+ //invalid format
+ Utils.logError("Invalid time format in network manager \""+lastUsed +"\". Network BSSID: " + bssid, e);
+ }
+
+ if (bssid.trim().equals("") || ssid.trim().equals("") || pass.trim().equals("")){
+ return null;
+ }
+
+ AccessPointInfo i = new AccessPointInfo(ssid, bssid, null, null, null);
+ i.setPassword(pass);
+ i.setLastTimeUsed(lastusedmillis);
+
+ return i;
+
+ }
+
+ private String InfoToString(AccessPointInfo info){
+
+ if (info == null){
+ return null;
+ }
+
+ String bssid = info.getBSSID();
+ String ssid = info.getSSID();
+ String pass = info.getPassword();
+ String tsLastUsed = "" + info.getLastTimeUsed();
+
+ if (bssid == null || bssid.trim().equals("")){
+ return null;
+ }
+
+ if (ssid == null || ssid.trim().equals("")){
+ return null;
+ }
+
+ if (pass == null || pass.trim().equals("")){
+ return null;
+ }
+
+ String iText = info.getBSSID() + F_SEP + info.getSSID() + F_SEP + info.getPassword() + F_SEP + tsLastUsed;
+ return iText;
+
+ }
+
+ private boolean saveList(AccessPointInfo[] list){
+
+ if (list == null){
+ return false;
+ }
+
+ String[] lines = new String[list.length];
+
+ for (int i = 0; i<list.length; i++){
+
+ String storeString = InfoToString(list[i]);
+ if (storeString == null){
+ return false;
+ }
+ lines[i] = storeString;
+
+ }
+
+ return Utils.writeFileLines(this._knownNetworksFile,lines, true);
+
+ }
+
+ public AccessPointInfo[] getKnownNetworks(){
+
+ ArrayList<AccessPointInfo> list = new ArrayList<AccessPointInfo>();
+
+ File f = new File(this._knownNetworksFile);
+ if (! f.exists()){
+ return null;
+ }
+
+ String[] lines = Utils.readFileLines(_knownNetworksFile);
+ if (lines.length == 0){
+ return null;
+ }
+
+ for(String l : lines){
+
+ AccessPointInfo info = getFromString(l);
+ if (info != null){
+ list.add(info);
+ }
+
+ }
+
+ AccessPointInfo[] ret = new AccessPointInfo[list.size()];
+ ret = list.toArray(ret);
+
+ return ret;
+
+ }
+
+ public boolean isKnown(AccessPointInfo info){
+
+ AccessPointInfo i = searchInFile(info);
+ if (i == null){
+ return false;
+ }else {
+ return true;
+ }
+
+ }
+
+ public boolean save(AccessPointInfo info){
+ return saveOrRemove(info, true);
+ }
+
+ public boolean remove(AccessPointInfo info){
+ return saveOrRemove(info, false);
+ }
+
+ public AccessPointInfo getSavedNetwork(AccessPointInfo i){
+ return searchInFile(i);
+ }
+
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/RootCommand.java b/app/src/fil/libre/repwifiapp/helpers/RootCommand.java
new file mode 100644
index 0000000..3da4ae0
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/RootCommand.java
@@ -0,0 +1,109 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import fil.libre.repwifiapp.Commons;
+
+public class RootCommand {
+
+ private String _cmdOut = "";
+ private String _cmdTxt = "";
+
+ public RootCommand(String commandText){
+ this._cmdTxt = commandText;
+ }
+
+ public int execute() throws Exception{
+ return execute(0);
+ }
+
+ public int execute(int sleepSecsAfterCmd) throws Exception{
+
+ Process su = Runtime.getRuntime().exec("su");
+
+ DataOutputStream stdin = new DataOutputStream(su.getOutputStream());
+ InputStream os = su.getInputStream();
+ BufferedReader stdOut = new BufferedReader(new InputStreamReader(os));
+ InputStream es = su.getErrorStream();
+ BufferedReader stdError = new BufferedReader(new InputStreamReader(es));
+
+ if ( this._cmdTxt != null ){
+
+ Utils.logDebug("EXEC: " + this._cmdTxt);
+
+ this._cmdTxt += " > " + Commons.getTempOutFile();
+
+ stdin.writeBytes(this._cmdTxt + "\n");
+ stdin.flush();
+ }
+
+ /* if (sleepSecsAfterCmd > 0){
+ Thread.sleep(sleepSecsAfterCmd * 1000);
+ }*/
+
+ StringBuilder sb = new StringBuilder();
+ String s = null;
+
+ while ( (es.available() > 0) && (s = stdError.readLine()) != null) {
+ sb.append(s + "\n");
+ }
+
+ while ( (os.available() > 0) && (s = stdOut.readLine()) != null) {
+ sb.append(s + "\n");
+ }
+
+ this._cmdOut = sb.toString();
+
+ stdin.writeBytes("exit\n");
+ stdin.flush();
+
+ int res = su.waitFor();
+
+ Utils.logDebug("OUT: " + getOutput());
+
+ return res;
+
+ }
+
+ public String getOutput(){
+
+ String[] lastOut = Utils.readFileLines(Commons.getTempOutFile());
+ if (lastOut == null){
+ return this._cmdOut;
+ }
+
+ String fout = "";
+
+ for (String s : lastOut){
+ fout += s + "\n";
+ }
+
+ return fout;
+
+ }
+
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/Utils.java b/app/src/fil/libre/repwifiapp/helpers/Utils.java
new file mode 100644
index 0000000..2e5fa27
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/Utils.java
@@ -0,0 +1,205 @@
+//
+// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp 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.
+//
+// RepWifiApp 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+
+package fil.libre.repwifiapp.helpers;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.util.Log;
+
+public class Utils {
+
+ private static final long MILLIS_IN_DAY = 86400000;
+
+ public static final int logLevel = 1;
+
+ public static final String APP_NAME = "RepWifi";
+
+ private static Exception _lastException = null;
+
+ public static Exception getLastException(){
+ return _lastException;
+ }
+
+ public static void logError(String msg, Exception e){
+ Log.e(APP_NAME,msg,e);
+ }
+
+ public static void logError(String msg){
+ Log.e(APP_NAME,msg);
+ }
+
+ public static void logDebug(String msg){
+ logDebug(msg,0);
+ }
+
+ public static void logDebug(String msg, int level){
+
+ if (level < logLevel){
+ return;
+ }
+
+ Log.d(APP_NAME,msg);
+ }
+
+ public static boolean writeFile(String filePath, String text, boolean overwrite){
+
+
+ FileWriter writer = null;
+ boolean retval = false;
+ try {
+
+ writer = new FileWriter(filePath, (! overwrite));
+ writer.write(text);
+
+ retval = true;
+
+ } catch (Exception e) {
+ _lastException = e;
+ retval = false;
+ }
+ finally{
+
+ if (writer != null){
+ try {
+ writer.close();
+ } catch (IOException e) {
+ //suppress
+ }
+ }
+
+ }
+
+ return retval;
+
+ }
+
+ public static boolean writeFileLines(String filePath, String[] lines, boolean overwrite){
+
+ if (lines == null){
+ return false;
+ }
+
+ FileWriter writer = null;
+ boolean retval = false;
+ try {
+
+ writer = new FileWriter(filePath, (! overwrite));
+
+ if (lines.length == 0){
+ writer.write("");
+ }
+
+ for(String l : lines){
+ writer.write(l + "\n");
+ }
+
+ retval = true;
+
+ } catch (Exception e) {
+ _lastException = e;
+ retval = false;
+ }
+ finally{
+
+ if (writer != null){
+ try {
+ writer.close();
+ } catch (IOException e) {
+ //suppress
+ }
+ }
+
+ }
+
+ return retval;
+
+ }
+
+ public static String[] readFileLines(String filePath){
+
+ if (filePath == null){
+ return null;
+ }
+
+ File f = new File(filePath);
+ if (! f.exists()){
+ logError("File doesn't exist: " + filePath);
+ return null;
+ }
+
+ FileReader fr = null;
+ BufferedReader bufr = null;
+
+ List<String> lines = new ArrayList<String>();
+ String[] ret = null;
+
+ try {
+
+ fr = new FileReader(filePath);
+ bufr = new BufferedReader(fr);
+ String line ="";
+ while((line = bufr.readLine()) != null){
+ lines.add(line);
+ }
+
+ String[] ar = new String[lines.size()];
+ ret = lines.toArray(ar);
+
+ } catch (Exception e) {
+ logError("Error while reading file " + filePath,e);
+ ret = null;
+ }
+ finally{
+ try {
+ if (bufr != null){
+ bufr.close();
+ }
+ } catch (IOException ex) {
+ //suppress
+ }
+ try {
+ if (fr != null){
+ fr.close();
+ }
+ }catch(IOException exc){
+ //suppress
+ }
+ }
+
+ return ret;
+
+ }
+
+ public static long daysToMilliseconds(int days){
+ return (days * MILLIS_IN_DAY);
+ }
+
+ public static long millisecondsToDays(long milliseconds){
+ return (milliseconds / MILLIS_IN_DAY);
+ }
+
+}