aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFil <fil.bergamo@riseup.net>2018-07-04 19:14:17 +0200
committerFil <fil.bergamo@riseup.net>2018-07-04 19:29:53 +0200
commit121a4bec96d2f9b842c6d393d2b9c6356a9a4405 (patch)
treeda1c557520d670def2f755492e3afd62ce891cf6
parenta6b34d6c75109b831976bc872a5a0a47a08c1664 (diff)
downloadRepWifiApp-0.9-beta.tar.gz
RepWifiApp-0.9-beta.tar.bz2
RepWifiApp-0.9-beta.zip
Add full integration with the Connectivity Frameworkv0.9-beta
Fixes Issue #1867 "Download app not working". Uses proxy classes to hook into the application framework, solving almost any problem with missing connectivity features, creating a connection that is fully managed by the framework itself. Introduces a background service that performs all backend operations. Cleans up code design, refining structure of classes and entities.
-rw-r--r--CHANGELOG7
-rw-r--r--README.md14
-rw-r--r--TODO19
-rw-r--r--app/AndroidManifest.xml26
-rw-r--r--app/assets/repwifi-logo-0-small.pngbin0 -> 51798 bytes
-rw-r--r--app/assets/repwifi-logo-1-small.pngbin0 -> 59631 bytes
-rw-r--r--app/assets/repwifi-logo-1.pngbin0 -> 104414 bytes
-rw-r--r--app/gen/fil/libre/repwifiapp/R.java455
-rw-r--r--app/lint.xml3
-rw-r--r--app/res/drawable/top_frame.xml13
-rw-r--r--app/res/layout-land/activity_input_ssid.xml92
-rw-r--r--app/res/layout-land/activity_ipv4_settings.xml147
-rw-r--r--app/res/layout-land/activity_main.xml128
-rw-r--r--app/res/layout-land/activity_network_details.xml95
-rw-r--r--app/res/layout-land/activity_vpn_settings.xml92
-rw-r--r--app/res/layout/activity_input_ssid.xml1
-rw-r--r--app/res/layout/activity_ipv4_settings.xml11
-rw-r--r--app/res/layout/activity_main.xml87
-rw-r--r--app/res/layout/activity_show_status.xml29
-rw-r--r--app/res/layout/activity_vpn_settings.xml27
-rw-r--r--app/res/raw/make_system_app.sh93
-rw-r--r--app/res/values-fr/strings.xml34
-rw-r--r--app/res/values-fr/strings_activity_input_password.xml25
-rw-r--r--app/res/values-fr/strings_activity_settings.xml25
-rw-r--r--app/res/values/strings.xml46
-rw-r--r--app/res/values/strings_activity_input_password.xml8
-rw-r--r--app/res/values/strings_activity_settings.xml14
-rw-r--r--app/res/xml/general_settings.xml11
-rw-r--r--app/src/fil/libre/repwifiapp/ActivityLauncher.java41
-rw-r--r--app/src/fil/libre/repwifiapp/Commons.java295
-rw-r--r--app/src/fil/libre/repwifiapp/Prefs.java67
-rw-r--r--app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java41
-rw-r--r--app/src/fil/libre/repwifiapp/Utils.java (renamed from app/src/fil/libre/repwifiapp/helpers/Utils.java)245
-rw-r--r--app/src/fil/libre/repwifiapp/activities/ConnectionBoundActivity.java282
-rw-r--r--app/src/fil/libre/repwifiapp/activities/CreditsActivity.java6
-rw-r--r--app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java33
-rw-r--r--app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java19
-rw-r--r--app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java38
-rw-r--r--app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java217
-rw-r--r--app/src/fil/libre/repwifiapp/activities/MainActivity.java545
-rw-r--r--app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java13
-rw-r--r--app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java33
-rw-r--r--app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java23
-rw-r--r--app/src/fil/libre/repwifiapp/activities/SettingsActivity.java126
-rw-r--r--app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java253
-rw-r--r--app/src/fil/libre/repwifiapp/activities/VpnAndConnectionBoundActivity.java435
-rw-r--r--app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java227
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/ConnectivityManagerProxy.java98
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/FrameworkProxy.java126
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/LinkAddressProxy.java61
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/LinkPropertiesProxy.java90
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/NetworkCapabilitiesProxy.java90
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/NetworkInfoProxy.java102
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java581
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/RouteInfoProxy.java59
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java109
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/Engine6p0.java271
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/Logger.java160
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/OpenVpnManager.java237
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/RootCommand.java81
-rw-r--r--app/src/fil/libre/repwifiapp/helpers/ShellCommand.java107
-rw-r--r--app/src/fil/libre/repwifiapp/network/AccessPointInfo.java (renamed from app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java)94
-rw-r--r--app/src/fil/libre/repwifiapp/network/ConnectionResult.java95
-rw-r--r--app/src/fil/libre/repwifiapp/network/ConnectionStatus.java298
-rw-r--r--app/src/fil/libre/repwifiapp/network/DhcpSettings.java (renamed from app/src/fil/libre/repwifiapp/helpers/DhcpSettings.java)153
-rw-r--r--app/src/fil/libre/repwifiapp/network/Engine.java (renamed from app/src/fil/libre/repwifiapp/helpers/Engine.java)92
-rw-r--r--app/src/fil/libre/repwifiapp/network/Engine6p0.java315
-rw-r--r--app/src/fil/libre/repwifiapp/network/IEngine.java (renamed from app/src/fil/libre/repwifiapp/helpers/IEngine.java)12
-rw-r--r--app/src/fil/libre/repwifiapp/network/NetworkButton.java (renamed from app/src/fil/libre/repwifiapp/helpers/NetworkButton.java)4
-rw-r--r--app/src/fil/libre/repwifiapp/network/NetworkManager.java (renamed from app/src/fil/libre/repwifiapp/helpers/NetworkManager.java)114
-rw-r--r--app/src/fil/libre/repwifiapp/network/WpaCli.java (renamed from app/src/fil/libre/repwifiapp/helpers/WpaCli.java)161
-rw-r--r--app/src/fil/libre/repwifiapp/network/WpaSupplicant.java (renamed from app/src/fil/libre/repwifiapp/helpers/WpaSupplicant.java)40
-rw-r--r--app/src/fil/libre/repwifiapp/service/Channel.java148
-rw-r--r--app/src/fil/libre/repwifiapp/service/ConnectionManagementService.java720
-rw-r--r--app/src/fil/libre/repwifiapp/service/StatusManager.java139
75 files changed, 6639 insertions, 2359 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a1b22b7..3adee27 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,10 @@
+## [v0.9-beta] - 2018-07-04
+* FIXED Issue #1867 "Download app not working" (see below)
+* NEW: creates a network connection that is fully integrated with android's connectivity framework
+* NEW: all backend operations are now managed through a service
+* cleaned up code design, refined structure of classes and entities
+* massively restyled core logic: approaching version 1.0!
+
## [v0.6] - 2017-12-17
* NEW: introduced static IP/gateway settings per network.
* NEW: added OpenVPN support via interaction with de.blinkt.openvpn
diff --git a/README.md b/README.md
index 37c4d8a..edda03a 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
RepWifiApp is free software, released under GPLv3.
-Copyright 2017 Filippo "Fil" Bergamo.
+Copyright 2017, 2018 Filippo "Fil" Bergamo.
All icons and images included in RepWifiApp are licensed under:
Creative Commons Attribution-ShareAlike 3.0 Unported license
@@ -17,19 +17,23 @@ It exposes basic functions to search for available netwroks and conenct to them.
Thank GNUs:
-- Tibi "tct" Turbureanu:
+- Tiberiu (Technoethical):
for having done the initial job of porting libre WiFi to Replicant 4.2.
- Wolfgang Wiedmeyer:
for porting libre WiFi to Replicant 6.0 and for helping with the scripts.
+- Nicola Spanti (RyDroid):
+for the French Translation.
+
To report on bugs, request features, or any help request, please refer to:
-Replicant's Forum: "http://redmine.replicant.us/boards/9/topics/14079"
+Replicant's Forum: "https://redmine.replicant.us/boards/9/topics/14079"
+Replicant's Issue Tracker: "https://redmine.replicant.us/issues"
-Compiled APKs are released in the same page linked above.
-APKs are signed with this GnuPG key:
+Official APKs are released through F-Droid "https://f-droid.org/"
+Any unofficial or testing APKs are signed with this GnuPG key:
Key ID: CD07CEAD
Owner: Filippo Bergamo (AKA Fil)
diff --git a/TODO b/TODO
index 9d2e86f..9766754 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,18 @@
TODO
-as of 2017-12-17
+as of 2018-07-03
-*) turn backend engine into a service
-*) introduce support for EAP authentication (if possible at all)
+*) Design a better model for preferences using ContentProvider
+
+*) Control wpa_supplicant directly using documented sockets and commands:
+ this should be the preferred way of communicating with wpa_supplicant,
+ allowing a fine-graned control over the authentication process
+ and giving access to asynchronous events about the connection status.
+
+*) SQLite database for storing network details:
+ drop the current JSON/text-file model and build a more consistent,
+ more secure way of storing data.
+
+*) Support wpa_supplicant in AP mode to create a Wi-Fi hotspot
+
+*) Support captive portals (e.g. "public" Wi-Fi systems or on-campus Wi-Fi):
+ (needs thorough research)
diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml
index b967836..02b0b64 100644
--- a/app/AndroidManifest.xml
+++ b/app/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fil.libre.repwifiapp"
- android:versionCode="5"
- android:versionName="0.6.2" >
+ android:versionCode="9"
+ android:versionName="0.9-beta" >
<uses-sdk
android:minSdkVersion="17"
@@ -13,6 +13,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<application
android:allowBackup="true"
@@ -30,26 +31,23 @@
</intent-filter>
</receiver>
- <!--
<receiver
android:name="fil.libre.repwifiapp.RepWifiIntentReceiver"
android:description="@string/receiver_description"
android:enabled="true"
android:exported="false"
- android:icon="@drawable/ic_launcher2"
+ android:icon="@drawable/ic_stat_repwifi"
android:label="RepWifiIntentReceiver" >
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</receiver>
- -->
-
+
<activity
android:name="fil.libre.repwifiapp.activities.MainActivity"
android:label="@string/app_name"
- android:launchMode="singleTop"
- android:screenOrientation="portrait" >
+ android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -95,7 +93,17 @@
android:name="fil.libre.repwifiapp.activities.VpnSettingsActivity"
android:label="@string/title_activity_vpn_settings" >
</activity>
- <service android:name="de.blinkt.openvpn.api.IOpenVPNAPIService"></service>
+
+ <service android:name="de.blinkt.openvpn.api.IOpenVPNAPIService" >
+ </service>
+ <service
+ android:name="fil.libre.repwifiapp.service.ConnectionManagementService"
+ android:enabled="true"
+ android:exported="false"
+ android:process=":connsvc" >
+ </service>
</application>
+
+
</manifest>
diff --git a/app/assets/repwifi-logo-0-small.png b/app/assets/repwifi-logo-0-small.png
new file mode 100644
index 0000000..2e865d0
--- /dev/null
+++ b/app/assets/repwifi-logo-0-small.png
Binary files differ
diff --git a/app/assets/repwifi-logo-1-small.png b/app/assets/repwifi-logo-1-small.png
new file mode 100644
index 0000000..25276d1
--- /dev/null
+++ b/app/assets/repwifi-logo-1-small.png
Binary files differ
diff --git a/app/assets/repwifi-logo-1.png b/app/assets/repwifi-logo-1.png
new file mode 100644
index 0000000..511d3ab
--- /dev/null
+++ b/app/assets/repwifi-logo-1.png
Binary files differ
diff --git a/app/gen/fil/libre/repwifiapp/R.java b/app/gen/fil/libre/repwifiapp/R.java
index 4874e0a..025ab02 100644
--- a/app/gen/fil/libre/repwifiapp/R.java
+++ b/app/gen/fil/libre/repwifiapp/R.java
@@ -9,19 +9,19 @@ package fil.libre.repwifiapp;
public final class R {
public static final class array {
- public static final int debug_priority=0x7f050001;
- public static final int debug_priority_names=0x7f050000;
+ public static final int debug_priority=0x7f060001;
+ public static final int debug_priority_names=0x7f060000;
}
public static final class attr {
}
public static final class color {
- public static final int Anthracite=0x7f060006;
- public static final int ThemeDark=0x7f060001;
- public static final int ThemeDarkSecondary=0x7f060002;
- public static final int ThemeLight=0x7f060000;
- public static final int Transparent=0x7f060005;
- public static final int White=0x7f060004;
- public static final int black=0x7f060003;
+ public static final int Anthracite=0x7f070006;
+ public static final int ThemeDark=0x7f070001;
+ public static final int ThemeDarkSecondary=0x7f070002;
+ public static final int ThemeLight=0x7f070000;
+ public static final int Transparent=0x7f070005;
+ public static final int White=0x7f070004;
+ public static final int black=0x7f070003;
}
public static final class drawable {
public static final int button_bg=0x7f020000;
@@ -43,64 +43,69 @@ public final class R {
public static final int rw_prog_1=0x7f020010;
public static final int rw_prog_2=0x7f020011;
public static final int rw_prog_3=0x7f020012;
+ public static final int top_frame=0x7f020013;
}
public static final class id {
- public static final int btn_back=0x7f0a0016;
- public static final int btn_delete=0x7f0a0023;
- public static final int btn_disconnect=0x7f0a002a;
- public static final int btn_hidden_ssid=0x7f0a001c;
- public static final int btn_ip_settings=0x7f0a0021;
- public static final int btn_manage_nets=0x7f0a001d;
- public static final int btn_next_hidden_ssid=0x7f0a000c;
- public static final int btn_rescan=0x7f0a0026;
- public static final int btn_save_ip_settings=0x7f0a0015;
- public static final int btn_save_vpn_settings=0x7f0a002d;
- public static final int btn_scan=0x7f0a001b;
- public static final int btn_select_hidden_ssid=0x7f0a0008;
- public static final int btn_vpn_settings=0x7f0a0022;
- public static final int chk_show_pass=0x7f0a0006;
- public static final int chk_show_pass_details=0x7f0a0020;
- public static final int chk_use_dhcp=0x7f0a000e;
- public static final int img_logo=0x7f0a001e;
- public static final int img_logo_fil=0x7f0a0001;
- public static final int layout=0x7f0a0017;
- public static final int layout_selnets=0x7f0a0024;
- public static final int lbl_gateway=0x7f0a0013;
- public static final int lbl_ip_settings=0x7f0a000d;
- public static final int lbl_netmask=0x7f0a0011;
- public static final int lbl_static_ip=0x7f0a000f;
- public static final int lbl_vpn_settings=0x7f0a002b;
- public static final int line=0x7f0a0009;
- public static final int login_form=0x7f0a0003;
- public static final int menu_btn_closeapp=0x7f0a0035;
- public static final int menu_config=0x7f0a0036;
- public static final int menu_credits=0x7f0a0037;
- public static final int menu_settings=0x7f0a0034;
- public static final int pref_autoconnect=0x7f0a0031;
- public static final int pref_autostart=0x7f0a0033;
- public static final int pref_debug_prio=0x7f0a002e;
- public static final int pref_dns1=0x7f0a002f;
- public static final int pref_dns2=0x7f0a0030;
- public static final int pref_progbar=0x7f0a0032;
- public static final int progbar=0x7f0a0018;
- public static final int scrollview=0x7f0a0027;
- public static final int sign_in_button=0x7f0a0007;
- public static final int spin_vpn_profile=0x7f0a002c;
- public static final int table_networks=0x7f0a0028;
- public static final int txt_credits=0x7f0a0002;
- public static final int txt_credits_title=0x7f0a0000;
- public static final int txt_gateway=0x7f0a0014;
- public static final int txt_insert_pass=0x7f0a0004;
- public static final int txt_insert_ssid=0x7f0a000a;
- public static final int txt_main=0x7f0a001a;
- public static final int txt_msg=0x7f0a0019;
- public static final int txt_net_details=0x7f0a001f;
- public static final int txt_netmask=0x7f0a0012;
- public static final int txt_password=0x7f0a0005;
- public static final int txt_selnets=0x7f0a0025;
- public static final int txt_ssid=0x7f0a000b;
- public static final int txt_static_ip=0x7f0a0010;
- public static final int txt_status=0x7f0a0029;
+ public static final int btn_back=0x7f0b0017;
+ public static final int btn_delete=0x7f0b0027;
+ public static final int btn_disconnect=0x7f0b001f;
+ public static final int btn_hidden_ssid=0x7f0b0021;
+ public static final int btn_info=0x7f0b001e;
+ public static final int btn_ip_settings=0x7f0b0025;
+ public static final int btn_manage_nets=0x7f0b0022;
+ public static final int btn_next_hidden_ssid=0x7f0b000c;
+ public static final int btn_rescan=0x7f0b002a;
+ public static final int btn_save_ip_settings=0x7f0b0016;
+ public static final int btn_save_vpn_settings=0x7f0b0030;
+ public static final int btn_scan=0x7f0b0020;
+ public static final int btn_select_hidden_ssid=0x7f0b0008;
+ public static final int btn_vpn_settings=0x7f0b0026;
+ public static final int button_frame=0x7f0b000e;
+ public static final int chk_show_pass=0x7f0b0006;
+ public static final int chk_show_pass_details=0x7f0b0024;
+ public static final int chk_use_dhcp=0x7f0b000f;
+ public static final int img_logo=0x7f0b001d;
+ public static final int img_logo_fil=0x7f0b0001;
+ public static final int layout=0x7f0b0018;
+ public static final int layout_selnets=0x7f0b0028;
+ public static final int layout_vpn_profile=0x7f0b002e;
+ public static final int lbl_gateway=0x7f0b0014;
+ public static final int lbl_netmask=0x7f0b0012;
+ public static final int lbl_static_ip=0x7f0b0010;
+ public static final int lbl_vpn_settings=0x7f0b002d;
+ public static final int left_frame=0x7f0b000d;
+ public static final int line=0x7f0b0009;
+ public static final int login_form=0x7f0b0003;
+ public static final int menu_btn_closeapp=0x7f0b0039;
+ public static final int menu_config=0x7f0b003a;
+ public static final int menu_credits=0x7f0b003b;
+ public static final int menu_settings=0x7f0b0038;
+ public static final int pref_autoconnect=0x7f0b0034;
+ public static final int pref_autostart=0x7f0b0037;
+ public static final int pref_debug_prio=0x7f0b0031;
+ public static final int pref_dns1=0x7f0b0032;
+ public static final int pref_dns2=0x7f0b0033;
+ public static final int pref_monitor_connection=0x7f0b0035;
+ public static final int pref_progbar=0x7f0b0036;
+ public static final int progbar=0x7f0b0019;
+ public static final int scrollview=0x7f0b002b;
+ public static final int sign_in_button=0x7f0b0007;
+ public static final int spin_vpn_profile=0x7f0b002f;
+ public static final int table_networks=0x7f0b002c;
+ public static final int top_frame=0x7f0b001b;
+ public static final int txt_credits=0x7f0b0002;
+ public static final int txt_credits_title=0x7f0b0000;
+ public static final int txt_gateway=0x7f0b0015;
+ public static final int txt_insert_pass=0x7f0b0004;
+ public static final int txt_insert_ssid=0x7f0b000a;
+ public static final int txt_msg=0x7f0b001a;
+ public static final int txt_net_details=0x7f0b0023;
+ public static final int txt_netmask=0x7f0b0013;
+ public static final int txt_password=0x7f0b0005;
+ public static final int txt_selnets=0x7f0b0029;
+ public static final int txt_ssid=0x7f0b000b;
+ public static final int txt_static_ip=0x7f0b0011;
+ public static final int txt_status=0x7f0b001c;
}
public static final class layout {
public static final int activity_credits=0x7f030000;
@@ -116,149 +121,18 @@ public final class R {
public static final int activity_vpn_settings=0x7f03000a;
}
public static final class menu {
- public static final int activity_input_ssid=0x7f090000;
- public static final int activity_ipv4_settings=0x7f090001;
- public static final int activity_main=0x7f090002;
- public static final int activity_vpn_settings=0x7f090003;
+ public static final int activity_input_ssid=0x7f0a0000;
+ public static final int activity_ipv4_settings=0x7f0a0001;
+ public static final int activity_main=0x7f0a0002;
+ public static final int activity_vpn_settings=0x7f0a0003;
+ }
+ public static final class raw {
+ public static final int make_system_app=0x7f050000;
}
public static final class string {
/**
This file is part of RepWifiApp.
- RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
- French translation is Copyright (C) 2017 Nicola Spanti
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
- */
- public static final int app_name=0x7f070000;
- public static final int back_main=0x7f07000b;
- public static final int button_text_next=0x7f070006;
- public static final int confirm_exit_app=0x7f070025;
- public static final int confirm_kill_backend=0x7f070026;
- public static final int confirm_reset_settings=0x7f070024;
- public static final int connect_hidden=0x7f07001c;
- public static final int credit_text=0x7f070013;
- public static final int delete=0x7f070010;
- public static final int disconnect=0x7f07000c;
- public static final int dns1_default=0x7f070021;
- public static final int dns2_default=0x7f070022;
- public static final int force_disconnect=0x7f07000d;
- public static final int hello_world=0x7f070070;
- public static final int input_ssid=0x7f07001d;
- public static final int insert_nets_password=0x7f070007;
- public static final int manage_networks=0x7f070011;
- public static final int menu_closeapp=0x7f070002;
- public static final int menu_config=0x7f070014;
- public static final int menu_credits=0x7f070001;
- public static final int menu_settings=0x7f07001f;
- public static final int msg_autoconnect_error=0x7f070037;
- public static final int msg_checking_status=0x7f070030;
- public static final int msg_confirm_delete_network=0x7f070016;
- public static final int msg_connect_fail=0x7f070034;
- public static final int msg_connected_to=0x7f070041;
- public static final int msg_connecting_to=0x7f07002d;
- public static final int msg_disconnect_fail=0x7f070044;
- public static final int msg_disconnected=0x7f070043;
- public static final int msg_error_ip_format=0x7f070040;
- public static final int msg_interface_not_found=0x7f070015;
- public static final int msg_invalid_gateway=0x7f070066;
- public static final int msg_invalid_ip=0x7f070064;
- public static final int msg_invalid_netmask=0x7f070065;
- public static final int msg_log_save_fail=0x7f07003f;
- public static final int msg_log_saved=0x7f07003e;
- public static final int msg_netinfo_delete_fail=0x7f070036;
- public static final int msg_netinfo_deleted=0x7f070035;
- public static final int msg_network_list_fail=0x7f07003a;
- public static final int msg_network_name_empty=0x7f07002c;
- public static final int msg_network_save_fail=0x7f070033;
- public static final int msg_network_saved=0x7f070032;
- public static final int msg_no_network=0x7f07003b;
- public static final int msg_no_saved_network=0x7f070046;
- public static final int msg_os_unsupported=0x7f070048;
- public static final int msg_password_empty=0x7f07002a;
- public static final int msg_please_wait=0x7f070031;
- public static final int msg_root_denied=0x7f07001b;
- public static final int msg_root_disabled=0x7f07001a;
- public static final int msg_scanning_for_nets=0x7f07002f;
- public static final int msg_select_network_connect=0x7f07003c;
- public static final int msg_select_network_manage=0x7f07003d;
- public static final int msg_touch_open=0x7f070047;
- public static final int msg_vpn_connect_error=0x7f07006e;
- public static final int msg_vpn_disconnect=0x7f070068;
- public static final int msg_vpn_disconnect_error=0x7f070067;
- public static final int msg_vpn_launched=0x7f070069;
- public static final int msg_vpn_no_permission=0x7f07006d;
- public static final int msg_vpn_no_profile=0x7f070073;
- public static final int msg_vpn_wrong_profile=0x7f07006a;
- public static final int no=0x7f070018;
- public static final int receiver_description=0x7f070023;
- public static final int rescan=0x7f070005;
- public static final int retry=0x7f070019;
- public static final int scan_networks=0x7f070003;
- public static final int select_saved_net=0x7f070020;
- public static final int show_password=0x7f070008;
- public static final int summary_advanced_settings=0x7f07005a;
- public static final int summary_autoconnect=0x7f070051;
- public static final int summary_dns1=0x7f07004e;
- public static final int summary_dns2=0x7f07004f;
- public static final int summary_general_settings=0x7f07005b;
- public static final int summary_kill_backend=0x7f070027;
- public static final int summary_progbar=0x7f070053;
- public static final int summary_restore_default=0x7f070057;
- public static final int summary_start_at_boot=0x7f070055;
- public static final int summary_vpn_settings=0x7f070072;
- public static final int text_gateway=0x7f070060;
- public static final int text_ip_address=0x7f070042;
- public static final int text_ipv4_settings=0x7f07005d;
- public static final int text_netinfo_last_used=0x7f070038;
- public static final int text_password=0x7f070039;
- public static final int text_presented_by=0x7f070028;
- public static final int text_static_ip=0x7f07005e;
- public static final int text_status=0x7f070045;
- public static final int text_subnet_mask=0x7f07005f;
- public static final int text_use_dhcp=0x7f07005c;
- public static final int text_vpn_package_missing=0x7f07006c;
- public static final int title_activity_connect=0x7f070009;
- public static final int title_activity_credits=0x7f070012;
- /**
- This file is part of RepWifiApp.
- RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
- French translation is Copyright (C) 2017 Nicola Spanti
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
- */
- public static final int title_activity_input_password=0x7f070074;
- public static final int title_activity_input_ssid=0x7f07001e;
- public static final int title_activity_ipv4_settings=0x7f070061;
- public static final int title_activity_long_task=0x7f07000e;
- public static final int title_activity_manage_networks=0x7f07000f;
- public static final int title_activity_select_network=0x7f070004;
- /**
- This file is part of RepWifiApp.
- RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+ RepWifiApp is Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
French translation is Copyright (C) 2017 Nicola Spanti
This program is free software: you can redistribute it and/or modify
@@ -275,28 +149,139 @@ public final class R {
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
- public static final int title_activity_settings=0x7f070075;
- public static final int title_activity_show_status=0x7f07000a;
- public static final int title_activity_vpn_settings=0x7f07006f;
- public static final int title_advanced_settings=0x7f070058;
- public static final int title_autoconnect=0x7f070050;
- public static final int title_dns_1=0x7f07004c;
- public static final int title_dns_2=0x7f07004d;
- public static final int title_dump_logs=0x7f07004a;
- public static final int title_general_settings=0x7f070059;
- public static final int title_input_password=0x7f070029;
- public static final int title_input_ssid=0x7f07002b;
- public static final int title_log_prio=0x7f070049;
- public static final int title_progbar=0x7f070052;
- public static final int title_reset_backend=0x7f07004b;
- public static final int title_restore_default=0x7f070056;
- public static final int title_scanning=0x7f07002e;
- public static final int title_start_at_boot=0x7f070054;
- public static final int title_vpn_settings=0x7f07006b;
- public static final int txt_back=0x7f070063;
- public static final int txt_save=0x7f070071;
- public static final int txt_save_ip_settings=0x7f070062;
- public static final int yes=0x7f070017;
+ public static final int app_name=0x7f080000;
+ public static final int back_main=0x7f08000b;
+ public static final int button_text_next=0x7f080006;
+ public static final int confirm_exit_app=0x7f080023;
+ public static final int confirm_kill_backend=0x7f080024;
+ public static final int confirm_reset_settings=0x7f080022;
+ public static final int connect_hidden=0x7f08001c;
+ public static final int credit_text=0x7f080013;
+ public static final int delete=0x7f080010;
+ public static final int disconnect=0x7f08000c;
+ public static final int force_disconnect=0x7f08000d;
+ public static final int hello_world=0x7f08006e;
+ public static final int input_ssid=0x7f08001d;
+ public static final int insert_nets_password=0x7f080007;
+ public static final int manage_networks=0x7f080011;
+ public static final int menu_closeapp=0x7f080002;
+ public static final int menu_config=0x7f080014;
+ public static final int menu_credits=0x7f080001;
+ public static final int menu_settings=0x7f08001f;
+ public static final int msg_autoconnect_error=0x7f080035;
+ public static final int msg_checking_status=0x7f08002e;
+ public static final int msg_chose_no_system_app=0x7f08007e;
+ public static final int msg_confirm_delete_network=0x7f080016;
+ public static final int msg_confirm_make_system_app=0x7f08007d;
+ public static final int msg_confirm_stop_job=0x7f080075;
+ public static final int msg_connect_fail=0x7f080032;
+ public static final int msg_connected_to=0x7f08003f;
+ public static final int msg_connecting_to=0x7f08002b;
+ public static final int msg_connection_timeout=0x7f080074;
+ public static final int msg_connection_timeout_nopass=0x7f08007b;
+ public static final int msg_disconnect_fail=0x7f080042;
+ public static final int msg_disconnected=0x7f080041;
+ public static final int msg_dns_fail=0x7f080072;
+ public static final int msg_error_generic=0x7f08007f;
+ public static final int msg_error_ip_format=0x7f08003e;
+ public static final int msg_fail_connservice=0x7f080080;
+ public static final int msg_gw_failed=0x7f080073;
+ public static final int msg_interface_not_found=0x7f080015;
+ public static final int msg_invalid_gateway=0x7f080064;
+ public static final int msg_invalid_ip=0x7f080062;
+ public static final int msg_invalid_netmask=0x7f080063;
+ public static final int msg_log_save_fail=0x7f08003d;
+ public static final int msg_log_saved=0x7f08003c;
+ public static final int msg_make_system_app=0x7f08007c;
+ public static final int msg_netinfo_delete_fail=0x7f080034;
+ public static final int msg_netinfo_deleted=0x7f080033;
+ public static final int msg_network_list_fail=0x7f080038;
+ public static final int msg_network_name_empty=0x7f08002a;
+ public static final int msg_network_save_fail=0x7f080031;
+ public static final int msg_network_saved=0x7f080030;
+ public static final int msg_no_network=0x7f080039;
+ public static final int msg_no_saved_network=0x7f080044;
+ public static final int msg_os_unsupported=0x7f080046;
+ public static final int msg_password_empty=0x7f080028;
+ public static final int msg_please_wait=0x7f08002f;
+ public static final int msg_root_denied=0x7f08001b;
+ public static final int msg_root_disabled=0x7f08001a;
+ public static final int msg_scanning_for_nets=0x7f08002d;
+ public static final int msg_select_network_connect=0x7f08003a;
+ public static final int msg_select_network_manage=0x7f08003b;
+ public static final int msg_touch_open=0x7f080045;
+ public static final int msg_vpn_connect_error=0x7f08006c;
+ public static final int msg_vpn_disconnect=0x7f080066;
+ public static final int msg_vpn_disconnect_error=0x7f080065;
+ public static final int msg_vpn_error_manual_open=0x7f080077;
+ public static final int msg_vpn_launched=0x7f080067;
+ public static final int msg_vpn_no_permission=0x7f08006b;
+ public static final int msg_vpn_no_profile=0x7f080071;
+ public static final int msg_vpn_service_error=0x7f080076;
+ public static final int msg_vpn_wrong_profile=0x7f080068;
+ public static final int no=0x7f080018;
+ public static final int receiver_description=0x7f080021;
+ public static final int rescan=0x7f080005;
+ public static final int retry=0x7f080019;
+ public static final int scan_networks=0x7f080003;
+ public static final int select_saved_net=0x7f080020;
+ public static final int show_password=0x7f080008;
+ public static final int summary_advanced_settings=0x7f080058;
+ public static final int summary_autoconnect=0x7f08004f;
+ public static final int summary_dns1=0x7f08004c;
+ public static final int summary_dns2=0x7f08004d;
+ public static final int summary_general_settings=0x7f080059;
+ public static final int summary_kill_backend=0x7f080025;
+ public static final int summary_monitor_connection_state=0x7f080081;
+ public static final int summary_progbar=0x7f080051;
+ public static final int summary_restore_default=0x7f080055;
+ public static final int summary_start_at_boot=0x7f080053;
+ public static final int summary_vpn_settings=0x7f080070;
+ public static final int text_broadcast_address=0x7f080078;
+ public static final int text_connection_info=0x7f08007a;
+ public static final int text_gateway=0x7f08005e;
+ public static final int text_hardware_address=0x7f080079;
+ public static final int text_ip_address=0x7f080040;
+ public static final int text_ipv4_settings=0x7f08005b;
+ public static final int text_netinfo_last_used=0x7f080036;
+ public static final int text_password=0x7f080037;
+ public static final int text_presented_by=0x7f080026;
+ public static final int text_static_ip=0x7f08005c;
+ public static final int text_status=0x7f080043;
+ public static final int text_subnet_mask=0x7f08005d;
+ public static final int text_use_dhcp=0x7f08005a;
+ public static final int text_vpn_package_missing=0x7f08006a;
+ public static final int title_activity_connect=0x7f080009;
+ public static final int title_activity_credits=0x7f080012;
+ public static final int title_activity_input_password=0x7f080083;
+ public static final int title_activity_input_ssid=0x7f08001e;
+ public static final int title_activity_ipv4_settings=0x7f08005f;
+ public static final int title_activity_long_task=0x7f08000e;
+ public static final int title_activity_manage_networks=0x7f08000f;
+ public static final int title_activity_select_network=0x7f080004;
+ public static final int title_activity_settings=0x7f080084;
+ public static final int title_activity_show_status=0x7f08000a;
+ public static final int title_activity_vpn_settings=0x7f08006d;
+ public static final int title_advanced_settings=0x7f080056;
+ public static final int title_autoconnect=0x7f08004e;
+ public static final int title_dns_1=0x7f08004a;
+ public static final int title_dns_2=0x7f08004b;
+ public static final int title_dump_logs=0x7f080048;
+ public static final int title_general_settings=0x7f080057;
+ public static final int title_input_password=0x7f080027;
+ public static final int title_input_ssid=0x7f080029;
+ public static final int title_log_prio=0x7f080047;
+ public static final int title_monitor_connection_state=0x7f080082;
+ public static final int title_progbar=0x7f080050;
+ public static final int title_reset_backend=0x7f080049;
+ public static final int title_restore_default=0x7f080054;
+ public static final int title_scanning=0x7f08002c;
+ public static final int title_start_at_boot=0x7f080052;
+ public static final int title_vpn_settings=0x7f080069;
+ public static final int txt_back=0x7f080061;
+ public static final int txt_save=0x7f08006f;
+ public static final int txt_save_ip_settings=0x7f080060;
+ public static final int yes=0x7f080017;
}
public static final class style {
/**
@@ -320,19 +305,19 @@ public final class R {
API 14 theme customizations can go here.
*/
- public static final int AppBaseTheme=0x7f080000;
+ public static final int AppBaseTheme=0x7f090000;
/** Application theme.
*/
- public static final int AppTheme=0x7f080001;
- public static final int LoginFormContainer=0x7f080008;
- public static final int RepWifi_BorderlessButton=0x7f080005;
- public static final int RepWifi_ButtonBar_AlertDialog=0x7f080006;
- public static final int TextAppearanceMenu=0x7f080002;
+ public static final int AppTheme=0x7f090001;
+ public static final int LoginFormContainer=0x7f090008;
+ public static final int RepWifi_BorderlessButton=0x7f090005;
+ public static final int RepWifi_ButtonBar_AlertDialog=0x7f090006;
+ public static final int TextAppearanceMenu=0x7f090002;
/** dialog theme
*/
- public static final int Theme_RepWifiDialogTheme=0x7f080007;
- public static final int Theme_SettingsTheme=0x7f080003;
- public static final int listViewPrefs=0x7f080004;
+ public static final int Theme_RepWifiDialogTheme=0x7f090007;
+ public static final int Theme_SettingsTheme=0x7f090003;
+ public static final int listViewPrefs=0x7f090004;
}
public static final class xml {
public static final int debug_settings=0x7f040000;
diff --git a/app/lint.xml b/app/lint.xml
new file mode 100644
index 0000000..ee0eead
--- /dev/null
+++ b/app/lint.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<lint>
+</lint> \ No newline at end of file
diff --git a/app/res/drawable/top_frame.xml b/app/res/drawable/top_frame.xml
new file mode 100644
index 0000000..b4438e0
--- /dev/null
+++ b/app/res/drawable/top_frame.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle" >
+
+ <solid android:color="@color/black" />
+
+ <corners android:radius="3dp" />
+
+ <stroke
+ android:width="2dp"
+ android:color="@color/ThemeLight" />
+
+</shape> \ No newline at end of file
diff --git a/app/res/layout-land/activity_input_ssid.xml b/app/res/layout-land/activity_input_ssid.xml
new file mode 100644
index 0000000..9be39e6
--- /dev/null
+++ b/app/res/layout-land/activity_input_ssid.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/black"
+ android:baselineAligned="false"
+ android:padding="15dp" >
+
+ <RelativeLayout
+ android:id="@+id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".50"
+ android:layout_height="fill_parent"
+ android:background="@drawable/top_frame"
+ android:padding="5dp"
+ android:paddingRight="10dp" >
+
+ <Button
+ android:id="@+id/btn_select_hidden_ssid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:background="@drawable/repwifi_button"
+ android:onClick="onBtnSelectClick"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:text="@string/select_saved_net"
+ android:textColor="@color/ThemeLight" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/button_frame"
+ android:layout_toRightOf="@id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".50"
+ android:layout_height="fill_parent"
+ android:background="@drawable/top_frame"
+ android:padding="15dp" >
+
+ <EditText
+ android:id="@+id/txt_ssid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:layout_centerInParent="true"
+ android:background="@drawable/button_bg"
+ android:inputType="text"
+ android:maxLines="1"
+ android:padding="5dp"
+ android:singleLine="true"
+ android:textColor="@color/ThemeLight"
+ android:textCursorDrawable="@null"
+ android:textSize="10pt" />
+
+ <TextView
+ android:id="@+id/txt_insert_ssid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_above="@id/txt_ssid"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:background="@color/black"
+ android:maxLines="1"
+ android:text="@string/input_ssid"
+ android:textColor="@color/ThemeLight"
+ android:textSize="9pt" />
+
+ <LinearLayout
+ style="@style/LoginFormContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_ssid"
+ android:background="@color/black"
+ android:orientation="vertical" >
+
+ <Button
+ android:id="@+id/btn_next_hidden_ssid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:layout_marginTop="16dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="onBtnNextClick"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:text="@string/button_text_next"
+ android:textColor="@color/ThemeLight" />
+ </LinearLayout>
+ </RelativeLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/res/layout-land/activity_ipv4_settings.xml b/app/res/layout-land/activity_ipv4_settings.xml
new file mode 100644
index 0000000..7bdb38b
--- /dev/null
+++ b/app/res/layout-land/activity_ipv4_settings.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:baselineAligned="false"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/black"
+ android:padding="15dp" >
+
+
+ <RelativeLayout
+ android:id="@+id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".55"
+ android:layout_height="fill_parent"
+ android:background="@drawable/top_frame"
+ android:padding="5dp"
+ android:paddingRight="10dp" >
+
+ <CheckBox
+ android:id="@+id/chk_use_dhcp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="5dp"
+ android:text="@string/text_use_dhcp"
+ android:textColor="@color/ThemeLight"
+ android:textSize="8pt" />
+
+ <TextView
+ android:id="@+id/lbl_static_ip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/chk_use_dhcp"
+ android:layout_margin="5dp"
+ android:background="@color/black"
+ android:text="@string/text_ip_address"
+ android:textColor="@color/ThemeLight"
+ android:textSize="9pt" />
+
+ <EditText
+ android:id="@+id/txt_static_ip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/chk_use_dhcp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="5dp"
+ android:layout_toRightOf="@id/lbl_static_ip"
+ android:background="@drawable/button_bg"
+ android:inputType="text"
+ android:padding="3dp"
+ android:textColor="@color/ThemeLight"
+ android:textSize="8pt" />
+
+ <TextView
+ android:id="@+id/lbl_netmask"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_static_ip"
+ android:layout_margin="5dp"
+ android:background="@color/black"
+ android:text="@string/text_subnet_mask"
+ android:textColor="@color/ThemeLight"
+ android:textSize="9pt" />
+
+ <EditText
+ android:id="@+id/txt_netmask"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_static_ip"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="5dp"
+ android:layout_toRightOf="@id/lbl_netmask"
+ android:background="@drawable/button_bg"
+ android:inputType="text"
+ android:padding="3dp"
+ android:textColor="@color/ThemeLight"
+ android:textSize="8pt" />
+
+ <TextView
+ android:id="@+id/lbl_gateway"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_netmask"
+ android:layout_margin="5dp"
+ android:background="@color/black"
+ android:text="@string/text_gateway"
+ android:textColor="@color/ThemeLight"
+ android:textSize="9pt" />
+
+ <EditText
+ android:id="@+id/txt_gateway"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_netmask"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="5dp"
+ android:layout_toRightOf="@id/lbl_gateway"
+ android:background="@drawable/button_bg"
+ android:inputType="text"
+ android:padding="3dp"
+ android:textColor="@color/ThemeLight"
+ android:textSize="8pt" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/button_frame"
+ android:layout_toRightOf="@id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".45"
+ android:layout_height="wrap_content"
+ android:background="@color/black"
+ android:padding="5dp" >
+
+ <Button
+ android:id="@+id/btn_save_ip_settings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_gateway"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnSaveClick"
+ android:text="@string/txt_save_ip_settings"
+ android:textColor="@color/ThemeLight" />
+
+ <Button
+ android:id="@+id/btn_back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/btn_save_ip_settings"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnBackClick"
+ android:text="@string/txt_back"
+ android:textColor="@color/ThemeLight" />
+
+
+ </RelativeLayout>
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/res/layout-land/activity_main.xml b/app/res/layout-land/activity_main.xml
new file mode 100644
index 0000000..84461c0
--- /dev/null
+++ b/app/res/layout-land/activity_main.xml
@@ -0,0 +1,128 @@
+<!-- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/black"
+ android:padding="15dp" > -->
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:baselineAligned="false"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/black"
+ android:padding="15dp">
+
+
+ <RelativeLayout
+ android:id="@+id/top_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".55"
+ android:layout_height="fill_parent"
+ android:background="@drawable/top_frame"
+ android:padding="5dp"
+ android:paddingRight="10dp" >
+
+ <TextView
+ android:id="@+id/txt_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:background="#80000000"
+ android:textColor="@color/ThemeLight"
+ android:textIsSelectable="true"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp" />
+
+ <ImageView
+ android:id="@+id/img_logo"
+ android:layout_below="@id/txt_status"
+ android:layout_width="80dp"
+ android:layout_height="80dp"
+ android:layout_margin="5dp"
+ android:paddingRight="5dp"
+ android:contentDescription="repwifi_logo" >
+ </ImageView>
+
+ <Button
+ android:id="@+id/btn_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="10dp"
+ android:layout_marginRight="5dp"
+ android:layout_toRightOf="@id/img_logo"
+ android:layout_below="@id/txt_status"
+ android:background="@drawable/repwifi_button"
+ android:onClick="onBtnInfoClick"
+ android:text="@string/text_connection_info"
+ android:textColor="@color/ThemeLight" />
+
+ <Button
+ android:id="@+id/btn_disconnect"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="10dp"
+ android:layout_marginRight="5dp"
+ android:layout_below="@id/btn_info"
+ android:layout_toRightOf="@id/img_logo"
+ android:background="@drawable/repwifi_button"
+ android:onClick="onBtnDisconnectClick"
+ android:text="@string/disconnect"
+ android:textColor="@color/ThemeLight" />
+
+ </RelativeLayout>
+
+
+ <RelativeLayout
+ android:id="@+id/button_frame"
+ android:layout_toRightOf="@id/top_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".45"
+ android:layout_height="wrap_content"
+ android:background="@color/black"
+ android:padding="5dp" >
+
+ <Button
+ android:id="@+id/btn_scan"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnScanClick"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:text="@string/scan_networks"
+ android:textColor="@color/ThemeLight" />
+
+ <Button
+ android:id="@+id/btn_hidden_ssid"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/btn_scan"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnHiddenClick"
+ android:text="@string/connect_hidden"
+ android:textColor="@color/ThemeLight" />
+
+ <Button
+ android:id="@+id/btn_manage_nets"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/btn_hidden_ssid"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnManageClick"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:text="@string/manage_networks"
+ android:textColor="@color/ThemeLight" />
+
+ </RelativeLayout>
+
+ </LinearLayout> \ No newline at end of file
diff --git a/app/res/layout-land/activity_network_details.xml b/app/res/layout-land/activity_network_details.xml
new file mode 100644
index 0000000..1b70f79
--- /dev/null
+++ b/app/res/layout-land/activity_network_details.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:baselineAligned="false"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/black"
+ android:padding="15dp" >
+
+
+ <RelativeLayout
+ android:id="@+id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".55"
+ android:layout_height="fill_parent"
+ android:background="@drawable/top_frame"
+ android:padding="5dp"
+ android:paddingRight="10dp" >
+
+ <TextView
+ android:id="@+id/txt_net_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:background="@color/black"
+ android:textColor="@color/ThemeLight"
+ android:textIsSelectable="true"
+ android:textSize="7pt" />
+
+ <CheckBox
+ android:id="@+id/chk_show_pass_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txt_net_details"
+ android:text="@string/show_password"
+ android:textColor="@color/ThemeLight"
+ android:textSize="10pt" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/button_frame"
+ android:layout_toRightOf="@id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".45"
+ android:layout_height="wrap_content"
+ android:background="@color/black"
+ android:padding="5dp" >
+
+ <Button
+ android:id="@+id/btn_ip_settings"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/chk_show_pass_details"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnIpSettingsClick"
+ android:text="@string/text_ipv4_settings"
+ android:textColor="@color/ThemeLight"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp" />
+
+ <Button
+ android:id="@+id/btn_vpn_settings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/btn_ip_settings"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnVpnSettingsClick"
+ android:text="@string/title_activity_vpn_settings"
+ android:textColor="@color/ThemeLight" />
+
+ <Button
+ android:id="@+id/btn_delete"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/btn_vpn_settings"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="10dp"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnDeleteClick"
+ android:text="@string/delete"
+ android:textColor="@color/ThemeLight" />
+
+
+ </RelativeLayout>
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/res/layout-land/activity_vpn_settings.xml b/app/res/layout-land/activity_vpn_settings.xml
new file mode 100644
index 0000000..ce6b521
--- /dev/null
+++ b/app/res/layout-land/activity_vpn_settings.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:baselineAligned="false"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/black"
+ android:padding="15dp" >
+
+
+ <RelativeLayout
+ android:id="@+id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".55"
+ android:layout_height="fill_parent"
+ android:background="@drawable/top_frame"
+ android:padding="5dp"
+ android:paddingRight="10dp" >
+
+ <TextView
+ android:id="@+id/lbl_vpn_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:background="@color/black"
+ android:textColor="@color/ThemeLight"
+ android:textIsSelectable="false"
+ android:textSize="7pt" />
+
+
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/button_frame"
+ android:layout_toRightOf="@id/left_frame"
+ android:layout_width="0dip"
+ android:layout_weight=".45"
+ android:layout_height="wrap_content"
+ android:background="@color/black"
+ android:padding="5dp" >
+
+ <RelativeLayout
+ android:id="@+id/layout_vpn_profile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/lbl_vpn_settings"
+ android:layout_margin="10dp"
+ android:background="@drawable/repwifi_button">
+ android:textAlignment="center"
+
+ <Spinner
+ android:id="@+id/spin_vpn_profile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="text"
+ android:textAlignment="center"
+ android:gravity="center"
+ android:textSize="10pt"
+ android:popupBackground="@color/ThemeLight" />
+
+ </RelativeLayout>
+
+
+ <Button
+ android:id="@+id/btn_save_vpn_settings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/layout_vpn_profile"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="25dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnSaveClick"
+ android:text="@string/txt_save"
+ android:textColor="@color/ThemeLight" />
+
+ <Button
+ android:id="@+id/btn_back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/btn_save_vpn_settings"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="15dp"
+ android:background="@drawable/repwifi_button"
+ android:onClick="btnBackClick"
+ android:text="@string/txt_back"
+ android:textColor="@color/ThemeLight" />
+
+
+ </RelativeLayout>
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/res/layout/activity_input_ssid.xml b/app/res/layout/activity_input_ssid.xml
index aa7e8f3..c525692 100644
--- a/app/res/layout/activity_input_ssid.xml
+++ b/app/res/layout/activity_input_ssid.xml
@@ -6,7 +6,6 @@
android:padding="20dp"
tools:context=".InputSsidActivity" >
- <!-- -->
<Button
android:id="@+id/btn_select_hidden_ssid"
diff --git a/app/res/layout/activity_ipv4_settings.xml b/app/res/layout/activity_ipv4_settings.xml
index 5c0887c..dc30bc0 100644
--- a/app/res/layout/activity_ipv4_settings.xml
+++ b/app/res/layout/activity_ipv4_settings.xml
@@ -6,21 +6,10 @@
android:padding="15dp"
tools:context=".Ipv4SettingsActivity" >
- <TextView
- android:id="@+id/lbl_ip_settings"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:background="@color/black"
- android:text="@string/text_ipv4_settings"
- android:textColor="@color/ThemeLight"
- android:textSize="12pt" />
-
<CheckBox
android:id="@+id/chk_use_dhcp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@id/lbl_ip_settings"
android:layout_margin="10dp"
android:text="@string/text_use_dhcp"
android:textColor="@color/ThemeLight"
diff --git a/app/res/layout/activity_main.xml b/app/res/layout/activity_main.xml
index b9359ba..41f6367 100644
--- a/app/res/layout/activity_main.xml
+++ b/app/res/layout/activity_main.xml
@@ -4,25 +4,75 @@
android:background="@color/black"
android:padding="15dp" >
- <TextView
- android:id="@+id/txt_main"
- android:layout_width="fill_parent"
+ <RelativeLayout
+ android:id="@+id/top_frame"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
- android:layout_marginBottom="10dp"
- android:layout_marginTop="10dp"
- android:background="@color/black"
- android:maxLines="10"
- android:text=""
- android:textColor="@color/ThemeLight" />
+ android:background="@drawable/top_frame"
+ android:orientation="vertical"
+ android:padding="10dp" >
+
+ <TextView
+ android:id="@+id/txt_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:background="#80000000"
+ android:textColor="@color/ThemeLight"
+ android:textIsSelectable="true"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp" />
+
+ <ImageView
+ android:id="@+id/img_logo"
+ android:layout_below="@id/txt_status"
+ android:layout_width="90dp"
+ android:layout_height="90dp"
+ android:layout_margin="5dp"
+ android:paddingRight="5dp"
+ android:contentDescription="repwifi_logo" >
+ </ImageView>
+
+ <Button
+ android:id="@+id/btn_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="10dp"
+ android:layout_toRightOf="@id/img_logo"
+ android:layout_below="@id/txt_status"
+ android:background="@drawable/repwifi_button"
+ android:onClick="onBtnInfoClick"
+ android:text="@string/text_connection_info"
+ android:textColor="@color/ThemeLight"
+ android:paddingTop="0dp"
+ android:paddingBottom="0dp" />
+
+ <Button
+ android:id="@+id/btn_disconnect"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="10dp"
+ android:layout_below="@id/btn_info"
+ android:layout_toRightOf="@id/img_logo"
+ android:background="@drawable/repwifi_button"
+ android:onClick="onBtnDisconnectClick"
+ android:text="@string/disconnect"
+ android:textColor="@color/ThemeLight" />
+
+ </RelativeLayout>
+
<Button
+ android:layout_below="@id/top_frame"
android:id="@+id/btn_scan"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
- android:layout_marginBottom="20dp"
- android:layout_marginTop="15dp"
+ android:layout_marginBottom="15dp"
+ android:layout_marginTop="20dp"
android:background="@drawable/repwifi_button"
android:onClick="btnScanClick"
android:paddingLeft="5dp"
@@ -36,21 +86,21 @@
android:layout_height="wrap_content"
android:layout_below="@id/btn_scan"
android:layout_centerHorizontal="true"
- android:layout_marginBottom="20dp"
+ android:layout_marginBottom="15dp"
android:background="@drawable/repwifi_button"
android:onClick="btnHiddenClick"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/connect_hidden"
android:textColor="@color/ThemeLight" />
-
+
<Button
android:id="@+id/btn_manage_nets"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/btn_hidden_ssid"
android:layout_centerHorizontal="true"
- android:layout_marginBottom="20dp"
+ android:layout_marginBottom="15dp"
android:background="@drawable/repwifi_button"
android:onClick="btnManageClick"
android:paddingLeft="5dp"
@@ -58,13 +108,4 @@
android:text="@string/manage_networks"
android:textColor="@color/ThemeLight" />
- <ImageView
- android:id="@+id/img_logo"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/btn_manage_nets"
- android:layout_centerHorizontal="true"
- android:layout_margin="20dp" >
- </ImageView>
-
</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
index 5afc596..1491015 100644
--- a/app/res/layout/activity_show_status.xml
+++ b/app/res/layout/activity_show_status.xml
@@ -12,32 +12,7 @@
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="@color/black"
+ android:textIsSelectable="true"
android:textColor="@color/ThemeLight" />
-
- <Button
- android:id="@+id/btn_disconnect"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/txt_status"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:layout_marginTop="10dp"
- android:background="@drawable/repwifi_button"
- android:onClick="onBtnDisconnectClick"
- android:text="@string/disconnect"
- android:textColor="@color/ThemeLight" />
-
- <Button
- android:id="@+id/btn_back"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/txt_status"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:layout_marginTop="10dp"
- android:background="@drawable/repwifi_button"
- android:onClick="onBtnMainClick"
- android:text="@string/back_main"
- android:textColor="@color/ThemeLight" />
-
+
</RelativeLayout> \ No newline at end of file
diff --git a/app/res/layout/activity_vpn_settings.xml b/app/res/layout/activity_vpn_settings.xml
index 4378baa..e90f611 100644
--- a/app/res/layout/activity_vpn_settings.xml
+++ b/app/res/layout/activity_vpn_settings.xml
@@ -14,25 +14,34 @@
android:background="@color/black"
android:textColor="@color/ThemeLight"
android:textIsSelectable="false"
- android:textSize="9pt" />
+ android:textSize="7pt" />
- <Spinner
- android:id="@+id/spin_vpn_profile"
+ <RelativeLayout
+ android:id="@+id/layout_vpn_profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/lbl_vpn_settings"
android:layout_margin="10dp"
- android:background="@drawable/button_bg"
- android:inputType="text"
- android:padding="1pt"
- android:textColor="@color/ThemeLight"
- android:textSize="10pt" />
+ android:background="@drawable/repwifi_button">
+ android:textAlignment="center"
+
+ <Spinner
+ android:id="@+id/spin_vpn_profile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="text"
+ android:textAlignment="center"
+ android:gravity="center"
+ android:textSize="10pt"
+ android:popupBackground="@color/ThemeLight" />
+
+ </RelativeLayout>
<Button
android:id="@+id/btn_save_vpn_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/spin_vpn_profile"
+ android:layout_below="@id/layout_vpn_profile"
android:layout_centerHorizontal="true"
android:layout_marginTop="25dp"
android:background="@drawable/repwifi_button"
diff --git a/app/res/raw/make_system_app.sh b/app/res/raw/make_system_app.sh
new file mode 100644
index 0000000..ce79a2c
--- /dev/null
+++ b/app/res/raw/make_system_app.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+#
+# Copyright 2017-2018 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/>.
+#
+# ********************************************************************
+
+# ----------------------------------------------------------------------------
+# This script copies the input APK into the /system/priv-app folder
+# this makes the target App a system app, having system internal permissions.
+#
+# Input args: $1 = [destination-dir], $2=[source-file], $3=[system-partition]
+#
+# ----------------------------------------------------------------------------
+
+LOG_TAG="RepWifi"
+DESTDIR=$1
+SRCAPK=$2
+SYSPART=$3
+
+
+function logE(){
+ log -p e -t $LOG_TAG $1
+}
+
+function logD(){
+ log -p d -t $LOG_TAG $1
+}
+
+# remounts /system readonly and restarts android's environment
+# exits the script with the provided exit code $1
+function finalize(){
+
+ mount -o ro,remount "$SYSPART"
+ start
+ exit $1
+
+}
+
+logD "Starting attempt to make myself a system app:"
+logD "Source apk: $SRCAPK"
+logD "Destination dir: $DESTDIR"
+
+# stop android's user shell to prevent userspace actions
+# while the system partition is writeable:
+stop
+
+# mount /system partition read-write:
+mount -o rw,remount $SYSPART
+
+if [[ -e $DESTDIR ]]; then
+ logD "Destination dir already exists."
+else
+ logD "Destination dir doesn't exist; creating it.."
+ mkdir "$DESTDIR"
+
+ if [[ $? != 0 ]]; then
+ logE "FAILED to create destination dir"
+ finalize 1
+ fi
+fi
+
+# copy the source APK into the system apps' directory
+logD "Copying apk.."
+cp "$SRCAPK" "$DESTDIR"
+
+if [[ $? == 0 ]]; then
+ logD "Succeeded in making myself a system app!"
+ finalize 0
+else
+ logE "Failed to make myself a system app!"
+ finalize 2
+fi
+
+# just in case:
+mount -o ro,remount "$SYSPART"
+start
+
diff --git a/app/res/values-fr/strings.xml b/app/res/values-fr/strings.xml
index 0c97583..fd0eb10 100644
--- a/app/res/values-fr/strings.xml
+++ b/app/res/values-fr/strings.xml
@@ -3,7 +3,7 @@
<!--
This file is part of RepWifiApp.
- RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+ RepWifiApp is Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
French translation is Copyright (C) 2017 Nicola Spanti
This program is free software: you can redistribute it and/or modify
@@ -24,10 +24,10 @@
<string name="menu_credits">Info et crédits</string>
<string name="menu_closeapp">Tuer RepWifi</string>
<string name="scan_networks">Scan des réseaux</string>
- <string name="title_activity_select_network">Sélectionner un réseau</string>
+ <string name="title_activity_select_network">Selectionner un réseau</string>
<string name="rescan">Répéter le scan</string>
<string name="button_text_next">Prochain &gt;</string>
- <string name="insert_nets_password">Entrer un mot de passe pour se connecter à :</string>
+ <string name="insert_nets_password">Fournisser un mot de passe pour se connecter à :</string>
<string name="show_password">Montrer le mot de passe</string>
<string name="title_activity_connect">ActivitéDeConnexion</string>
<string name="title_activity_show_status">Statut de connexion</string>
@@ -39,30 +39,30 @@
<string name="delete">Supprimer les informations sur le réseau</string>
<string name="manage_networks">Gérer les réseaux</string>
<string name="title_activity_credits">Crédits</string>
- <string name="credit_text">Copyright 2017 Filippo \&quot;Fil\&quot; Bergamo&lt;br/&gt;&lt;br/&gt;Cette app est un logiciel libre.&lt;br/&gt;Elle est sous licence &lt;a href=&quot;https://www.gnu.org/licenses/gpl.txt&quot;&gt;GPL v3&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Cette app est développée en tant que contribution au &lt;br/&gt;&lt;a href=&quot;https://www.replicant.us&quot;&gt;projet Replicant&lt;/a&gt;&lt;br/&gt;Pour signaler des bogues, demander des fonctionnalités, ou n\'importe quelle autre demande d\'aide, veuillez vous référer à :&lt;br/&gt;&lt;a href=&quot;https://redmine.replicant.us/projects/replicant/boards&quot;&gt;Forum de Replicant&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Le code source est hébergé sur : &lt;br/&gt;&lt;a href=&quot;https://git.replicant.us/contrib/Fil/RepWifiApp/&quot;&gt;https://git.replicant.us/contrib/Fil/RepWifiApp/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;u&gt;&lt;big&gt;Merci GNUs:&lt;/big&gt;&lt;/u&gt;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Tiberiu - Technoethical&lt;/b&gt;&lt;br/&gt;pour avoir fait le travail initial de porter le Wi-Fi sur Replicant 4.2.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Wolfgang Wiedmeyer&lt;/b&gt;&lt;br/&gt;pour le portage du Wi-Fi libre sur Replicant 6.0 et pour l\'aide sur les scripts.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Nicola Spanti&lt;/b&gt;&lt;br/&gt;pour la traduction en français.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Nichlas Severinsen&lt;/b&gt;&lt;br/&gt;pour la publication de cette app sur F-Droid.&lt;br/&gt;&lt;br/&gt;</string>
+ <string name="credit_text">Copyright 2017, 2018 Filippo \&quot;Fil\&quot; Bergamo&lt;br/&gt;&lt;br/&gt;Cette app est du logiciel libre.&lt;br/&gt;Elle est sous licence &lt;a href=&quot;https://www.gnu.org/licenses/gpl.txt&quot;&gt;GPL v3&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Cette app est développé en tant que contribution au &lt;br/&gt;&lt;a href=&quot;https://www.replicant.us&quot;&gt;projet Replicant&lt;/a&gt;&lt;br/&gt;Pour signaler des bogues, demander des fonctionnalités, ou n\'importe quelle autre demande d\'aide, veuillez vous référer à :&lt;br/&gt;&lt;a href=&quot;https://redmine.replicant.us/projects/replicant/boards&quot;&gt;Forum de Replicant&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Le code source est hébergé sur : &lt;br/&gt;&lt;a href=&quot;https://git.replicant.us/contrib/Fil/RepWifiApp/&quot;&gt;https://git.replicant.us/contrib/Fil/RepWifiApp/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;u&gt;&lt;big&gt;Merci GNUs:&lt;/big&gt;&lt;/u&gt;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Tiberiu - Technoethical&lt;/b&gt;&lt;br/&gt;pour avoir fait le travail initial de porter le Wi-Fi sur Replicant 4.2.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Wolfgang Wiedmeyer&lt;/b&gt;&lt;br/&gt;pour le portage du Wi-Fi libre sur Replicant 6.0 et pour l\'aide sur les scripts.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Nicola Spanti&lt;/b&gt;&lt;br/&gt;pour la traduction en français.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Nichlas Severinsen&lt;/b&gt;&lt;br/&gt;pour la publication de cette app sur F-Droid.&lt;br/&gt;&lt;br/&gt;</string>
<string name="menu_config">Paramètres</string>
- <string name="msg_interface_not_found">Pas d\'adaptateur Wi-Fi trouvé !\nVeuillez connecter un adaptateur Wi-Fi géré et réessayer.</string>
- <string name="msg_confirm_delete_network">Êtes-vous sûr de vouloir supprimer ce réseau ?</string>
+ <string name="msg_interface_not_found">Pas d\'adaptateur Wi-Fi trouvé !\nVeuillez connecter un adaptateur Wi-Fi géréet réessayer.</string>
+ <string name="msg_confirm_delete_network">Êtes vous sûr de vouloir supprimer ce réseau ?</string>
<string name="yes">Oui</string>
<string name="no">Non</string>
<string name="retry">Réessayer</string>
<string name="msg_root_disabled">Les droits root sont désactivés.\n\nIl semble que les droits root soient désactivés sur cette appareil.\nRepWifi a besoin des droits root pour fonctionner.\nVeuillez activer les droits root pour les applications dans :\nParamètres > Options pour développeur > Droits roots > "Applications seulement"\nQuand ce sera fait, redémarrer RepWifi et donner la permission d\'utiliser les droits, si c\'est demandé.</string>
- <string name="msg_root_denied">Droits root refusés.\nIl semble que vous avez refusé les droits root à RepWifi.\nRepWifi a besoin des droits root pour fonctionner.\nVeuillez redémarrer l\'application, puis accorder les droits root à RepWifi, quand cela est demandé.</string>
+ <string name="msg_root_denied">Droits root refusés.\nIl semble que vous avez refusé les droits root à RepWifi.\nRepWifi a besoin des drots root pour fonctionner.\nVeuillez redémarrer l\'application, puis accorder les droits root à RepWifi, quand cela est demandé.</string>
<string name="connect_hidden">Se connecter aux réseaux cachés</string>
- <string name="input_ssid">Ou.. Entrer le nom du réseau (SSID)</string>
- <string name="title_activity_input_ssid">Entrer le nom du réseau</string>
+ <string name="input_ssid">Ou.. Fournisser le nom du réseau (SSID)</string>
+ <string name="title_activity_input_ssid">Fournisser le nom du réseau</string>
<string name="menu_settings">Paramètres</string>
<string name="select_saved_net">Utiliser le réseau enregistré</string>
<string name="receiver_description">RepWifi est attentif à l\'événement de démarrage. Cela lui permet d\'avoir une fonctionnalité de démarrage automatique et une autre lié aux notifications.</string>
- <string name="confirm_reset_settings">Êtes-vous sûr de vouloir remettre tous les paramètres aux valeurs par défaut ?</string>
- <string name="confirm_exit_app">Êtes-vous sûr de vouloir tuer RepWifi ? Cela vous déconnectera du Wi-Fi.</string>
- <string name="confirm_kill_backend">Êtes-vous sûr de vouloir tuer les processus d\'arrière-plan ?</string>
- <string name="summary_kill_backend">Des fois les programmes d\'arrière-plan restent coincés dans des états incohérents.\nCliquer sur le bouton restaure le comportement normal en tuant les instances en cours de wpa_supplicant et dhcpcd.</string>
+ <string name="confirm_reset_settings">Êtes vous sûr de vouloir de remettre tous les paramètres aux valeurs par défaut ?</string>
+ <string name="confirm_exit_app">Êtes vous sûr de vouloir tuer RepWifi ? Cela vous déconnectera du Wi-Fi.</string>
+ <string name="confirm_kill_backend">Êtes vous sûr de vouloir tuer les processus d\'arrière-plan ?</string>
+ <string name="summary_kill_backend">Des fois les programmes d\'arrière-plan restent coincés dans des états incohérents.\nCliquer sur le boutton restaure le comportement normal en tuant les instances en cours de wpa_supplicant et dhcpcd.</string>
<string name="text_presented_by">Fait par :</string>
<string name="title_input_password">Saisir le mot de passe</string>
- <string name="msg_password_empty">Le mot de passe ne peut pas être vide !</string>
+ <string name="msg_password_empty">Le mot de passe ne peut pas être nul !</string>
<string name="title_input_ssid">Saisir les paramètres du réseau</string>
- <string name="msg_network_name_empty">Le nom du réseau ne peut pas être vide !</string>
+ <string name="msg_network_name_empty">Le nom du réseau ne peut pas être nul !</string>
<string name="msg_connecting_to">Connexion à </string>
<string name="title_scanning">Scan...</string>
<string name="msg_scanning_for_nets">Scan pour trouver des réseaux...</string>
@@ -99,7 +99,7 @@
<string name="summary_dns1">Définir l\'adresse IPv4 du serveur DNS primaire.\nSi c\'est laissé vide, RepWifi va essayer d\'utiliser la passerelle par défaut comme résolveur DNS.</string>
<string name="summary_dns2">Définir l\'adresse IPv4 du serveur DNS secondaire.\nSi la première adresse est vide, la valeur de ce champ va être ignorée.</string>
<string name="title_autoconnect">Activer l\'auto-connexion</string>
- <string name="summary_autoconnect">Quand l\'adaptateur Wi-Fi est connecté, RepWifi se connecte automatiquement aux réseaux connus atteignables.\n(Expérimental).</string>
+ <string name="summary_autoconnect">Quand l\'adaptateur Wi-Fi est connecté, RepWifi se connecte automatiquement aux réseaux connus atteignables.\n(Fonctionnalité expérimental)</string>
<string name="title_progbar">Barre de progression animée</string>
<string name="summary_progbar">Affiche une barre de progression animée pendant que des tâches de fond sont réalisées.\nGarder la désactivée pour (à priori) économiser de l\'énergie pour l\'adaptateur Wi-Fi.</string>
<string name="title_start_at_boot">Activer le démarrage automatique au démarrage du système</string>
@@ -108,6 +108,8 @@
<string name="summary_restore_default">cliquer pour rétablir les paramètres par défaut\n(ensuite revenez à l\'écran principal pour appliquer la réinitialisation)</string>
<string name="title_advanced_settings">Avancé &amp; Débogage</string>
<string name="title_general_settings">Options</string>
+ <string name="title_activity_input_password">Entrer le mot de passe pour le réseau</string>
+ <string name="title_activity_settings">Paramètres</string>
<string name="summary_advanced_settings">définir les options avancées et variables de débogage</string>
<string name="summary_general_settings">définir les options générales</string>
<string name="text_use_dhcp">Utiliser DHCP</string>
diff --git a/app/res/values-fr/strings_activity_input_password.xml b/app/res/values-fr/strings_activity_input_password.xml
deleted file mode 100644
index c27ca7a..0000000
--- a/app/res/values-fr/strings_activity_input_password.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <!--
- This file is part of RepWifiApp.
- RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
- French translation is Copyright (C) 2017 Nicola Spanti
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- -->
-
- <string name="title_activity_input_password">Entrer le mot de passe pour le réseau</string>
-
-</resources>
diff --git a/app/res/values-fr/strings_activity_settings.xml b/app/res/values-fr/strings_activity_settings.xml
deleted file mode 100644
index 260bcb0..0000000
--- a/app/res/values-fr/strings_activity_settings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <!--
- This file is part of RepWifiApp.
- RepWifiApp is Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
- French translation is Copyright (C) 2017 Nicola Spanti
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- -->
-
- <string name="title_activity_settings">Paramètres</string>
-
-</resources>
diff --git a/app/res/values/strings.xml b/app/res/values/strings.xml
index 8e8cd36..1073697 100644
--- a/app/res/values/strings.xml
+++ b/app/res/values/strings.xml
@@ -1,4 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+-->
<resources>
<string name="app_name">RepWifi</string>
@@ -20,7 +41,7 @@
<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;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;&lt;br/&gt;Source code is hosted at: &lt;br/&gt;&lt;a href=&quot;https://git.replicant.us/contrib/Fil/RepWifiApp/&quot;&gt;https://git.replicant.us/contrib/Fil/RepWifiApp/&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;Tiberiu - Technoethical&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;&lt;b&gt;Nicola Spanti&lt;/b&gt;&lt;br/&gt;for the French translation.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Nichlas Severinsen&lt;/b&gt;&lt;br/&gt;for publishing this app on F-Droid.&lt;br/&gt;&lt;br/&gt;</string>
+ <string name="credit_text">Copyright 2017, 2018 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;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;&lt;br/&gt;Source code is hosted at: &lt;br/&gt;&lt;a href=&quot;https://git.replicant.us/contrib/Fil/RepWifiApp/&quot;&gt;https://git.replicant.us/contrib/Fil/RepWifiApp/&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;Tiberiu - Technoethical&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;&lt;b&gt;Nicola Spanti&lt;/b&gt;&lt;br/&gt;for the French translation.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Nichlas Severinsen&lt;/b&gt;&lt;br/&gt;for publishing this app on F-Droid.&lt;br/&gt;&lt;br/&gt;</string>
<string name="menu_config">Settings</string>
<string name="msg_interface_not_found">WiFi adapter not found!\nPlease plug in a supported WiFi adapter and retry.</string>
<string name="msg_confirm_delete_network">Are you sure you want to delete this network?</string>
@@ -34,13 +55,11 @@
<string name="title_activity_input_ssid">Insert Network\'s Name</string>
<string name="menu_settings">Settings</string>
<string name="select_saved_net">Use Saved Network</string>
- <string name="dns1_default">185.121.177.177</string>
- <string name="dns2_default">169.239.202.202</string>
<string name="receiver_description">RepWifi\'s listener for startup event. Provides auto-start and notification features to RepWifi.</string>
<string name="confirm_reset_settings">Are you sure you want to reset all settings to default?</string>
<string name="confirm_exit_app">Are you sure you want to kill RepWifi? This will disconnect you from WiFi.</string>
<string name="confirm_kill_backend">Are you sure you want to kill the back-end processes?</string>
- <string name="summary_kill_backend">Sometimes back-end programs get stuck in inconsistent states.\nClicking this button restores normal behaviour by killing running instances of wpa_supplicant and dhcpcd."</string>
+ <string name="summary_kill_backend">Sometimes back-end programs get stuck in inconsistent states.\nClicking this button restores normal behaviour by killing running instances of wpa_supplicant and dhcpcd.</string>
<string name="text_presented_by">Brought to you by:</string>
<string name="title_input_password">Input Password</string>
<string name="msg_password_empty">Password can\'t be empty!</string>
@@ -82,7 +101,7 @@
<string name="summary_dns1">Set the IPv4 address of the primary DNS server.\nIf left blank, RepWifi will try to use the default gateway as a DNS resolver.</string>
<string name="summary_dns2">Set the IPv4 address of the secondary DNS server.\nIf the primary address is blank, this will be ignored.</string>
<string name="title_autoconnect">Enable Autoconnect</string>
- <string name="summary_autoconnect">When the WiFi dongle is attached, RepWifi connects automatically to reachable known networks.\n(Experimental).</string>
+ <string name="summary_autoconnect">When the WiFi dongle is attached, RepWifi connects automatically to reachable known networks.\n(Experimental Feature)</string>
<string name="title_progbar">Animated progress bar</string>
<string name="summary_progbar">Show an animated progress bar while doing long background tasks.\nKeep it disabled to (hopefully) save some extra power for the WiFi dongle.</string>
<string name="title_start_at_boot">Enable Start at Boot</string>
@@ -117,5 +136,22 @@
<string name="txt_save">Save</string>
<string name="summary_vpn_settings">Select the name of a VPN profile that you want to be launched automatically when you connect to this network.\nLeave blank to disable automatic VPN connection.\nTo use VPN capability, &quot;[VPN_EXT_APP]&quot; must be installed in the system.</string>
<string name="msg_vpn_no_profile">No profile found.\nPlease add a VPN profile inside [VPN_EXT_APP] before using this feature.</string>
+ <string name="msg_dns_fail">FAILED setting DNS!</string>
+ <string name="msg_gw_failed">FAILED to get gateway!</string>
+ <string name="msg_connection_timeout">Timeout exceeded while trying to connect.\nThis could be due to a wrong password.\nPlease re-enter the correct password and retry.</string>
+ <string name="msg_confirm_stop_job">Do you really want to stop current activity?</string>
+ <string name="msg_vpn_service_error">ERROR while binding to VPN service!</string>
+ <string name="msg_vpn_error_manual_open">ERROR while binding to VPN service.\nYou need to manually launch &quot;[VPN_EXT_APP]&quot; the first time, before using it with RepWifi.\nPlease launch the vpn app, then retry, and allow RepWifi permission to use the vpn app, when asked.</string>
+ <string name="text_broadcast_address">Broadcast address</string>
+ <string name="text_hardware_address">Hardware address</string>
+ <string name="text_connection_info">Connection Info</string>
+ <string name="msg_connection_timeout_nopass">Timeout exceeded while trying to connect.\n</string>
+ <string name="msg_make_system_app">RepWifi is installed as a regular app.\nRepWifi needs to be a \"System app\" to work properly.\nTo make repwifi a system app just confirm this dialog.\n\n*** The device will be rebooted ***\nPlease save any opened job before proceeding.\n\nDo you want to proceed making RepWifi a system app?</string>
+ <string name="msg_confirm_make_system_app">Are you sure you want to proceed?\nThe device will reboot!</string>
+ <string name="msg_chose_no_system_app">You chose not to make RepWifi a system app, so RepWifi won\'t work properly.\nTo make RepWifi a system app, close and re-open it, then just confirm when asked about making it a system app.</string>
+ <string name="msg_error_generic">ERROR!</string>
+ <string name="msg_fail_connservice">FATAL ERROR! Failed to bind to inner connection service. Try restarting the application.</string>
+ <string name="summary_monitor_connection_state">If checked, the background service keeps on monitoring the state of the connection, once every [CHK_STS_INTERVAL] seconds, reporting any state change in the status bar notification.(Experimental feature)</string>
+ <string name="title_monitor_connection_state">Monitor connection state</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
deleted file mode 100644
index 31b8865..0000000
--- a/app/res/values/strings_activity_input_password.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<resources>
-
- <string name="title_activity_input_password">Insert passwrod for network</string>
-
- <!-- Strings related to login -->
-
-
-</resources> \ No newline at end of file
diff --git a/app/res/values/strings_activity_settings.xml b/app/res/values/strings_activity_settings.xml
deleted file mode 100644
index dfc25ca..0000000
--- a/app/res/values/strings_activity_settings.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<resources>
-
- <string name="title_activity_settings">Settings</string>
-
- <!-- Strings related to Settings -->
-
-
- <!-- Example General settings -->
-
- <!-- Example settings for Data & Sync -->
-
- <!-- Example settings for Notifications -->
-
-</resources> \ No newline at end of file
diff --git a/app/res/xml/general_settings.xml b/app/res/xml/general_settings.xml
index bd9fdf9..5d7d6c0 100644
--- a/app/res/xml/general_settings.xml
+++ b/app/res/xml/general_settings.xml
@@ -3,7 +3,7 @@
<EditTextPreference
android:id="@+id/pref_dns1"
- android:defaultValue="@string/dns1_default"
+ android:defaultValue=""
android:key="dns1"
android:summary="@string/summary_dns1"
android:title="@string/title_dns_1"
@@ -14,7 +14,7 @@
<EditTextPreference
android:id="@+id/pref_dns2"
- android:defaultValue="@string/dns2_default"
+ android:defaultValue=""
android:key="dns2"
android:summary="@string/summary_dns2"
android:title="@string/title_dns_2"
@@ -30,6 +30,13 @@
android:title="@string/title_autoconnect" />
<CheckBoxPreference
+ android:id="@+id/pref_monitor_connection"
+ android:defaultValue="false"
+ android:key="monitor_connection"
+ android:summary="@string/summary_monitor_connection_state"
+ android:title="@string/title_monitor_connection_state" />
+
+ <CheckBoxPreference
android:id="@+id/pref_progbar"
android:defaultValue="true"
android:key="enable_progbar"
diff --git a/app/src/fil/libre/repwifiapp/ActivityLauncher.java b/app/src/fil/libre/repwifiapp/ActivityLauncher.java
index 5e9c31d..d5d2b15 100644
--- a/app/src/fil/libre/repwifiapp/ActivityLauncher.java
+++ b/app/src/fil/libre/repwifiapp/ActivityLauncher.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -31,9 +31,9 @@ import fil.libre.repwifiapp.activities.NetworkDetailsActivity;
import fil.libre.repwifiapp.activities.SelectNetworkActivity;
import fil.libre.repwifiapp.activities.ShowStatusActivity;
import fil.libre.repwifiapp.activities.VpnSettingsActivity;
-import fil.libre.repwifiapp.helpers.AccessPointInfo;
-import fil.libre.repwifiapp.helpers.ConnectionStatus;
-import fil.libre.repwifiapp.helpers.NetworkManager;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.ConnectionStatus;
+import fil.libre.repwifiapp.network.NetworkManager;
public class ActivityLauncher {
@@ -42,9 +42,12 @@ public class ActivityLauncher {
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_INTEGER = "ExInt";
public static final String EXTRA_REQCODE = "ExReqCode";
public static final String EXTRA_RESCAN = "ExRescan";
public static final String EXTRA_DELETE = "ExDelete";
+ public static final String EXTRA_MESSAGE = "ExMsg";
+ public static final String EXTRA_CONNRES = "ExConnRes";
public class RequestCode {
@@ -61,7 +64,8 @@ public class ActivityLauncher {
public static final int CONNECT_HIDDEN = 10;
public static final int USB_ATTACHED = 11;
public static final int USB_DETACHED = 12;
- public static final int VPN_PERMISSION = 13;
+ public static final int VPN_PERMISSION_CONN = 13;
+ public static final int VPN_PERMISSION_LIST = 14;
}
@@ -82,7 +86,7 @@ public class ActivityLauncher {
}
public void launchLongTaskActivityConnect(AccessPointInfo info) {
-
+
Intent intent = new Intent(currentContext, LongTaskActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.putExtra(ActivityLauncher.EXTRA_REQCODE, RequestCode.CONNECT);
@@ -99,11 +103,20 @@ public class ActivityLauncher {
}
public void launchPasswordActivity(AccessPointInfo info) {
+ launchPasswordActivity(info, null);
+ }
+
+ public void launchPasswordActivity(AccessPointInfo info, String message) {
Intent intent = new Intent();
// intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.setClass(currentContext, InputPasswordActivity.class);
intent.putExtra(EXTRA_APINFO, info);
+
+ if (message != null) {
+ intent.putExtra(EXTRA_MESSAGE, message);
+ }
+
currentContext.startActivityForResult(intent, RequestCode.PASS_INPUT);
}
@@ -121,11 +134,12 @@ public class ActivityLauncher {
boolean fromStorage) {
if (fromStorage) {
- NetworkManager manager = new NetworkManager(Commons.getNetworkStorageFile());
- nets = manager.getKnownNetworks();
+
+ nets = NetworkManager.getKnownNetworks();
if (nets == null || nets.length == 0) {
- Toast toast = Toast.makeText(currentContext, Commons.msgNoSavedNetwork, Toast.LENGTH_LONG);
+ Toast toast = Toast.makeText(currentContext, currentContext.getResources()
+ .getString(R.string.msg_no_saved_network), Toast.LENGTH_LONG);
toast.show();
return;
}
@@ -153,7 +167,7 @@ public class ActivityLauncher {
currentContext.startActivityForResult(intent, RequestCode.DETAILS_SHOW);
}
-
+
public void launchIpSettingsActivity(AccessPointInfo info) {
Intent intent = new Intent(currentContext, Ipv4SettingsActivity.class);
@@ -162,14 +176,14 @@ public class ActivityLauncher {
currentContext.startActivity(intent);
}
-
+
public void launchVpnSettingsActivity(AccessPointInfo info) {
-
+
Intent intent = new Intent(currentContext, VpnSettingsActivity.class);
// intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.putExtra(EXTRA_APINFO, info);
currentContext.startActivity(intent);
-
+
}
public void launchInputSsidActivity() {
@@ -180,6 +194,5 @@ public class ActivityLauncher {
currentContext.startActivityForResult(intent, RequestCode.CONNECT_HIDDEN);
}
-
}
diff --git a/app/src/fil/libre/repwifiapp/Commons.java b/app/src/fil/libre/repwifiapp/Commons.java
index 1603a76..0347982 100644
--- a/app/src/fil/libre/repwifiapp/Commons.java
+++ b/app/src/fil/libre/repwifiapp/Commons.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,64 +20,26 @@
package fil.libre.repwifiapp;
-import java.io.File;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Locale;
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.os.Environment;
-import android.preference.PreferenceManager;
-import fil.libre.repwifiapp.activities.MainActivity;
-import fil.libre.repwifiapp.helpers.ConnectionStatus;
-import fil.libre.repwifiapp.helpers.Engine;
-import fil.libre.repwifiapp.helpers.Engine6p0;
-import fil.libre.repwifiapp.helpers.IEngine;
-import fil.libre.repwifiapp.helpers.NetworkManager;
-import fil.libre.repwifiapp.helpers.Utils;
-import fil.libre.repwifiapp.helpers.WpaCli;
-import fil.libre.repwifiapp.helpers.WpaSupplicant;
+import fil.libre.repwifiapp.network.NetworkManager;
public abstract class Commons {
- private static Context currentContext;
-
- public static Context getContext() {
- return currentContext;
- }
-
// ------------- Environment Constants -----------------
public static final int EXCOD_ROOT_DISABLED = 255;
public static final int EXCOD_ROOT_DENIED = 1;
public static final int WAIT_ON_USB_ATTACHED = 1500;
public static final int WAIT_FOR_GATEWAY = 4000;
+ public static final int WAIT_FOR_DHCPCD = 30;
public static final String BSSID_NOT_AVAILABLE = "[BSSID-NOT-AVAILABLE]";
public static final String v6p0 = "6.0";
// ---------------------------------------------
- // ------------- 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;
- public static String dns1Default = "";
- public static String dns2Default = "";
private static String APP_DATA_FOLDER;
- public static String msgNoSavedNetwork;
+ public static void init(Context context) {
+ APP_DATA_FOLDER = context.getExternalFilesDir(null).getAbsolutePath();
+ NetworkManager.init(getNetworkStorageFile());
+ }
public static String getNetworkStorageFile() {
if (APP_DATA_FOLDER == null) {
@@ -86,249 +48,14 @@ public abstract class Commons {
return APP_DATA_FOLDER + "/repwifi_storage.conf";
}
}
-
- @SuppressLint("SimpleDateFormat")
- public static String getLogDumpFile() {
- File f = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
- if (f == null || !f.exists()) {
- return null;
- }
-
- String basefolder;
- try {
- basefolder = f.getCanonicalPath();
- } catch (Exception e) {
- Utils.logError("Exception while resolving canonical path for log dump file.", e);
+ public static String getExitCodeTempFile() {
+ if (APP_DATA_FOLDER == null) {
return null;
- }
-
- DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss", Locale.getDefault());
- String ts = dateFormat.format(Calendar.getInstance().getTime());
- return basefolder + "/repwifi_log_dump." + ts + ".log";
- }
-
- // --------------------------------------------------------
-
- private static final int NOTIFICATION_ID = 1;
-
- public static void updateNotification(Context context) {
-
- ConnectionStatus status = WpaCli.getConnectionStatus();
-
- Notification.Builder builder = new Notification.Builder(context);
-
- Intent intent = new Intent(context, MainActivity.class);
- PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
- builder.setContentIntent(pendingIntent);
-
- int iconId = R.drawable.ic_stat_discon;
- String msg = "RepWifi";
- if (status != null) {
- if (status.isConnected()) {
- iconId = R.drawable.ic_stat_repwifi;
- msg += " - " + status.SSID;
- } else {
- msg += " - " + status.status;
- }
-
- }
-
- builder.setSmallIcon(iconId);
-
- builder.setContentTitle(msg);
- builder.setContentText(currentContext.getString(R.string.msg_touch_open));
-
- Notification n = builder.build();
- n.flags |= Notification.FLAG_NO_CLEAR;
-
- NotificationManager notificationManager = (NotificationManager) context
- .getSystemService(Service.NOTIFICATION_SERVICE);
- notificationManager.notify(NOTIFICATION_ID, n);
-
- }
-
- public static void showMessage(String msg) {
- showMessage(msg, currentContext);
- }
-
- public static void showMessage(String msg, Context context) {
-
- AlertDialog.Builder dlgAlert = new AlertDialog.Builder(context,
- R.style.Theme_RepWifiDialogTheme);
- dlgAlert.setMessage(msg);
- dlgAlert.setPositiveButton(currentContext.getString(android.R.string.ok),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- return;
- }
- });
-
- dlgAlert.setCancelable(false);
- AlertDialog diag = dlgAlert.create();
-
- diag.show();
-
- }
-
- public static void resetSettingsDefault(Context context, boolean silent) {
-
- if (silent) {
- Editor e = getSettings().edit();
- e.clear();
- e.commit();
- } else {
-
- String msg = context.getString(R.string.confirm_reset_settings);
- AlertDialog.Builder dlgAlert = new AlertDialog.Builder(context,
- R.style.Theme_RepWifiDialogTheme);
- dlgAlert.setMessage(msg);
- dlgAlert.setPositiveButton(context.getString(android.R.string.ok),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- resetSettingsDefault(null, true);
- return;
- }
- });
- dlgAlert.setNegativeButton(context.getString(android.R.string.cancel),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- return;
- }
- });
-
- dlgAlert.setCancelable(false);
- AlertDialog diag = dlgAlert.create();
-
- diag.show();
-
- return;
- }
-
- }
-
- public static void killBackEnd(Context context, boolean silent) {
-
- if (silent) {
-
- Engine.killDhcpcd();
- WpaSupplicant.kill();
-
} else {
-
- String msg = context.getString(R.string.confirm_kill_backend);
- AlertDialog.Builder dlgAlert = new AlertDialog.Builder(context,
- R.style.Theme_RepWifiDialogTheme);
- dlgAlert.setMessage(msg);
- dlgAlert.setPositiveButton(context.getString(android.R.string.ok),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- killBackEnd(null, true);
- return;
- }
- });
- dlgAlert.setNegativeButton(context.getString(android.R.string.cancel),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- return;
- }
- });
-
- dlgAlert.setCancelable(false);
- AlertDialog diag = dlgAlert.create();
-
- diag.show();
- return;
-
- }
-
- }
-
- public static int getLogPriority() {
-
- SharedPreferences sets = getSettings();
- return Integer.parseInt(sets.getString("debug_priority", "3"));
-
- }
-
- public static boolean isProgbarEnabled() {
- return getSettings().getBoolean("enable_progbar", true);
- }
-
- public static boolean isAutoConnectEnabled() {
- return getSettings().getBoolean("enable_autoconnect", false);
- }
-
- public static String[] getDnss() {
-
- String dns1 = getSettings().getString("dns1", dns1Default);
- String dns2 = getSettings().getString("dns2", dns2Default);
-
- if (dns1 == null || dns1.isEmpty()) {
- return null;
- }
-
- return new String[] { dns1, dns2 };
-
- }
-
- public static SharedPreferences getSettings() {
-
- return PreferenceManager.getDefaultSharedPreferences(currentContext);
-
- }
-
- // ----------------------------------------------------
-
- // ----------- Initialization methods ---------------------------
- public static boolean init(Context context) {
-
- currentContext = context;
-
- try {
-
- colorThemeDark = currentContext.getResources().getColor(R.color.ThemeDark);
- colorThemeLight = currentContext.getResources().getColor(R.color.ThemeLight);
- msgNoSavedNetwork = currentContext.getResources().getString(
- R.string.msg_no_saved_network);
- colorBlack = currentContext.getResources().getColor(R.color.black);
- APP_DATA_FOLDER = currentContext.getExternalFilesDir(null).getAbsolutePath();
- dns1Default = currentContext.getResources().getString(R.string.dns1_default);
- dns2Default = currentContext.getResources().getString(R.string.dns2_default);
-
- initEngine();
- initNetworkStorage();
-
- return true;
-
- } catch (Exception e) {
- Utils.logError("Error initializing common resources.", e);
- return false;
+ return APP_DATA_FOLDER + "/tmp_excode";
}
}
- private static void initEngine() throws Exception {
-
- connectionEngine = new Engine6p0();
-
- String vers = android.os.Build.VERSION.RELEASE;
-
- if (!vers.startsWith(Commons.v6p0)) {
- showMessage(currentContext.getString(R.string.msg_os_unsupported));
- }
-
- }
-
- private static void initNetworkStorage() throws Exception {
-
- Commons.storage = new NetworkManager(getNetworkStorageFile());
-
- }
- // --------------------------------------------------------------
-
+
}
diff --git a/app/src/fil/libre/repwifiapp/Prefs.java b/app/src/fil/libre/repwifiapp/Prefs.java
new file mode 100644
index 0000000..ef13d5a
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/Prefs.java
@@ -0,0 +1,67 @@
+//
+// Copyright 2018 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 android.content.Context;
+import android.content.SharedPreferences;
+
+public class Prefs {
+
+ public static final String PREF_MONITOR_NET_STATE = "monitor_connection";
+ public static final String PREF_LOG_LEVEL = "debug_priority";
+ public static final String PREF_DNS_1 = "dns1";
+ public static final String PREF_DNS_2 = "dns2";
+ public static final String PREF_AUTOSTART = "enable_autostart";
+ public static final String PREF_PROGBAR = "enable_progbar";
+ public static final String PREF_AUTOCONNECT = "enable_autoconnect";
+
+ private static final String PREFS_FILENAME = "fil.libre.repwifiapp_preferences";
+
+ public static int getLogPriority(Context c) {
+ return Integer.parseInt(getPrefs(c).getString(PREF_LOG_LEVEL, "3"));
+ }
+
+ public static boolean isNetworkStateMonitoringEnabled(Context c) {
+ return getPrefs(c).getBoolean(PREF_MONITOR_NET_STATE, false);
+ }
+
+ public static int getInt(Context c, String key, int defaultVal) {
+ return getPrefs(c).getInt(key, defaultVal);
+ }
+
+ public static boolean getBoolean(Context c, String key, boolean defaultVal) {
+ return getPrefs(c).getBoolean(key, defaultVal);
+ }
+
+ public static String getString(Context c, String key, String defaultVal) {
+ return getPrefs(c).getString(key, defaultVal);
+ }
+
+ public static void commit(Context c) {
+ getPrefs(c).edit().commit();
+ }
+
+ private static SharedPreferences getPrefs(Context c) {
+ SharedPreferences prefs = c
+ .getSharedPreferences(PREFS_FILENAME, Context.MODE_MULTI_PROCESS);
+ return prefs;
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java b/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java
index ba26bb3..6ee419a 100644
--- a/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java
+++ b/app/src/fil/libre/repwifiapp/RepWifiIntentReceiver.java
@@ -1,26 +1,46 @@
+//
+// Copyright 2017, 2018 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 fil.libre.repwifiapp.ActivityLauncher.RequestCode;
-import fil.libre.repwifiapp.activities.MainActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
+import fil.libre.repwifiapp.activities.MainActivity;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.service.ConnectionManagementService;
public class RepWifiIntentReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context
- .getApplicationContext());
- if (!prefs.getBoolean("enable_autostart", false)) {
+ if (!Prefs.getBoolean(context, Prefs.PREF_AUTOSTART, false)) {
return;
}
String a = intent.getAction();
if (a.equals(Intent.ACTION_BOOT_COMPLETED) || a.equals(Intent.ACTION_REBOOT)) {
+ Logger.logDebug("Starting on boot.", 100);
+ startConnectionManagementService(context);
launchRepWifiMainActivity(context, RequestCode.NONE);
}
@@ -37,4 +57,11 @@ public class RepWifiIntentReceiver extends BroadcastReceiver {
context.startActivity(intent);
}
+
+ private void startConnectionManagementService(Context context) {
+ Intent startIntent = new Intent(context, ConnectionManagementService.class);
+ startIntent.setAction(ConnectionManagementService.ACTION_VOID);
+ context.startService(startIntent);
+ }
+
}
diff --git a/app/src/fil/libre/repwifiapp/helpers/Utils.java b/app/src/fil/libre/repwifiapp/Utils.java
index ad10c1a..28db6a8 100644
--- a/app/src/fil/libre/repwifiapp/helpers/Utils.java
+++ b/app/src/fil/libre/repwifiapp/Utils.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,51 +18,34 @@
//
// ********************************************************************
-package fil.libre.repwifiapp.helpers;
+package fil.libre.repwifiapp;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.Engine;
+import fil.libre.repwifiapp.network.WpaSupplicant;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
-import fil.libre.repwifiapp.Commons;
-import android.util.Log;
+import java.util.Scanner;
public class Utils {
private static final long MILLIS_IN_DAY = 86400000;
- 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 < Commons.getLogPriority()) {
- return;
- }
-
- Log.d(APP_NAME, msg);
- }
-
+
public static boolean writeFileLines(String filePath, String[] lines, boolean overwrite) {
if (lines == null) {
@@ -113,7 +96,7 @@ public class Utils {
try {
writer.close();
} catch (IOException e) {
- logError("error while closing filewriter", e);
+ Logger.logError("error while closing filewriter", e);
}
}
@@ -129,7 +112,7 @@ public class Utils {
File f = new File(filePath);
if (!f.exists()) {
- logError("File doesn't exist: " + filePath);
+ Logger.logError("File doesn't exist: " + filePath);
return null;
}
@@ -153,7 +136,7 @@ public class Utils {
return lines.toArray(ar);
} catch (Exception e) {
- logError("Error while reading file " + filePath, e);
+ Logger.logError("Error while reading file " + filePath, e);
return null;
} finally {
@@ -162,28 +145,28 @@ public class Utils {
bufr.close();
}
} catch (IOException ex) {
- logError("error while closing filereader", ex);
+ Logger.logError("error while closing filereader", ex);
}
try {
if (fr != null) {
fr.close();
}
} catch (IOException exc) {
- logError("error while closing filereader", exc);
+ Logger.logError("error while closing filereader", exc);
}
}
}
- public static String readFile(String filePath){
-
+ public static String readFile(String filePath) {
+
if (filePath == null) {
return null;
}
File f = new File(filePath);
if (!f.exists()) {
- logError("File doesn't exist: " + filePath);
+ Logger.logError("File doesn't exist: " + filePath);
return null;
}
@@ -206,7 +189,7 @@ public class Utils {
return sb.toString();
} catch (Exception e) {
- logError("Error while reading file " + filePath, e);
+ Logger.logError("Error while reading file " + filePath, e);
return null;
} finally {
@@ -215,66 +198,56 @@ public class Utils {
bufr.close();
}
} catch (IOException ex) {
- logError("error while closing filereader", ex);
+ Logger.logError("error while closing filereader", ex);
}
try {
if (fr != null) {
fr.close();
}
} catch (IOException exc) {
- logError("error while closing filereader", exc);
+ Logger.logError("error while closing filereader", exc);
}
}
-
- }
-
- public static long daysToMilliseconds(int days) {
- return (days * MILLIS_IN_DAY);
- }
- public static long millisecondsToDays(long milliseconds) {
- return (milliseconds / MILLIS_IN_DAY);
}
- public static boolean dumpLogcatToFile(String filePath) {
-
- if (filePath == null) {
- return false;
+ /* private static String flagExists = "EXISTS";
+ private static String flagNotExists = "NOT-EXISTS";
+ public static boolean fileExistsRoot(String filePath) throws Exception{
+
+ String cmd = "if [ -e \""+ filePath +"\" ]; then echo \"" + flagExists + "\"; else echo \""+ flagNotExists + "\";fi";
+
+ RootCommand su = new RootCommand(cmd);
+ if (su.execute() !=0){
+ throw new Exception("RepWifi.Utils Failed to check for file existence!");
}
-
- try {
-
- String cmd1 = "logcat -d | grep " + APP_NAME + ">" + filePath;
- String cmd2 = "logcat -d | grep " + Commons.getContext().getPackageName() + ">>"
- + filePath;
- String SEP_LOG = "\n\n---------- [REPWIFI_LOG_SEPARATOR] ----------\n\n";
-
- RootCommand c1 = new RootCommand(cmd1);
- RootCommand c2 = new RootCommand(cmd2);
-
- if (c1.execute() != 0) {
- return false;
- }
-
- if (!writeFile(filePath, SEP_LOG, false)) {
- return false;
- }
-
- if (c2.execute() != 0) {
- return false;
- }
-
+
+ if (su._cmdOut.trim().equals(flagExists)){
return true;
-
- } catch (Exception e) {
- logError("Exception during log dump.", e);
+ } else if (su._cmdOut.trim().equals(flagNotExists)){
return false;
+ } else {
+ throw new Exception("RepWifi.Utils received unknown flag while checking for file existence!");
}
+ }*/
+
+ /* public static boolean createDirectoryRoot(String dirPath){
+
+ String cmd = "mkdir " + dirPath;
+ return RootCommand.executeRootCmd(cmd);
+
+ }
+ */
+ public static long daysToMilliseconds(int days) {
+ return (days * MILLIS_IN_DAY);
+ }
+ public static long millisecondsToDays(long milliseconds) {
+ return (milliseconds / MILLIS_IN_DAY);
}
public static String netmaskIntToString(int mask) {
-
+
if (mask < 8 || mask > 32) {
return null;
}
@@ -307,11 +280,15 @@ public class Utils {
public static int netmaskStringToInt(String mask) {
if (mask == null) {
+ Logger.logError("netmaskStringToInt received null mask");
return -1;
}
+ mask = mask.trim();
+
String[] octs = mask.split("\\.");
if (octs.length != 4) {
+ Logger.logError("netmaskStringToInt invalid input string: " + mask);
return -1;
}
@@ -320,16 +297,18 @@ public class Utils {
for (String o : octs) {
int intval = 0;
-
+
try {
intval = Integer.parseInt(o, 10);
} catch (NumberFormatException e) {
+ Logger.logError("netmaskStringToInt", e);
return -1;
- }
+ }
String b = Integer.toBinaryString(intval);
if (b.length() != 8 && b.contains("1")) {
- //invalid mask! has ones after a zero
+ // invalid mask! has ones after a zero
+ Logger.logError("netmaskStringToInt invalid mask! has ones after a zero");
return -1;
}
for (int i = 0; i < b.length(); i++) {
@@ -338,18 +317,114 @@ public class Utils {
} else if (prevIsZero) {
// invalid mask
+ Logger.logError("netmaskStringToInt invalid mask");
return -1;
-
+
} else {
intmask += 1;
}
-
+
}
-
+
}
-
+
return intmask;
}
+ public static String rawResourceAsString(Context context, int resId) {
+
+ InputStream s = null;
+ Scanner scan = null;
+
+ try {
+
+ s = context.getResources().openRawResource(resId);
+ scan = new Scanner(s, "UTF-8").useDelimiter("\\A");
+ return scan.next();
+
+ } catch (Exception e) {
+ Logger.logError("Exception while reading raw resource as string", e);
+ return null;
+
+ } finally {
+
+ try {
+ if (scan != null) {
+ scan.close();
+ }
+ } catch (Exception e2) {
+ }
+
+ try {
+ if (s != null) {
+ s.close();
+ }
+ } catch (Exception e2) {
+ }
+
+ }
+
+ }
+
+ public static void showMessage(String msg, Context context) {
+
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(context,
+ R.style.Theme_RepWifiDialogTheme);
+ dlgAlert.setMessage(msg);
+ dlgAlert.setPositiveButton(context.getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ return;
+ }
+ });
+
+ dlgAlert.setCancelable(false);
+ AlertDialog diag = dlgAlert.create();
+
+ diag.show();
+
+ }
+
+ public static void killBackEnd(Context context, boolean silent) {
+
+ if (silent) {
+
+ Engine.killDhcpcd();
+ WpaSupplicant.kill();
+
+ } else {
+
+ String msg = context.getString(R.string.confirm_kill_backend);
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(context,
+ R.style.Theme_RepWifiDialogTheme);
+ dlgAlert.setMessage(msg);
+ dlgAlert.setPositiveButton(context.getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ killBackEnd(null, true);
+ return;
+ }
+ });
+ dlgAlert.setNegativeButton(context.getString(android.R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ return;
+ }
+ });
+
+ dlgAlert.setCancelable(false);
+ AlertDialog diag = dlgAlert.create();
+
+ diag.show();
+ return;
+
+ }
+
+ }
+
+
}
diff --git a/app/src/fil/libre/repwifiapp/activities/ConnectionBoundActivity.java b/app/src/fil/libre/repwifiapp/activities/ConnectionBoundActivity.java
new file mode 100644
index 0000000..4996024
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/ConnectionBoundActivity.java
@@ -0,0 +1,282 @@
+//
+// Copyright 2017, 2018 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 android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.preference.PreferenceManager;
+import fil.libre.repwifiapp.Prefs;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.ConnectionResult;
+import fil.libre.repwifiapp.network.ConnectionStatus;
+import fil.libre.repwifiapp.service.Channel;
+import fil.libre.repwifiapp.service.ConnectionManagementService;
+
+/**
+ * Provides a base class for all activities that need to bind to the
+ * ConnectionManagementService.
+ */
+public class ConnectionBoundActivity extends MenuEnabledActivity implements
+ OnSharedPreferenceChangeListener {
+
+ private IBinder svcBinder = null;
+ private Channel channel = null;
+ private ServiceConnection svcConn = null;
+
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ startConnectionService();
+ registerPreferenceChangeListener();
+ }
+
+ protected boolean isServiceBound() {
+ return (channel != null);
+ }
+
+ private void startConnectionService() {
+
+ Intent startIntent = new Intent(this, ConnectionManagementService.class);
+ startIntent.setAction(ConnectionManagementService.ACTION_VOID);
+ startService(startIntent);
+
+ if (channel != null) {
+ Logger.logDebug("ConnectionManagementService already bound");
+ return;
+ }
+
+ try {
+
+ if (svcConn == null) {
+
+ svcConn = new ServiceConnection() {
+
+ public void onServiceConnected(ComponentName className,
+ android.os.IBinder service) {
+ ConnectionBoundActivity.this.initChannel(service);
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ ConnectionBoundActivity.this.channel = null;
+ ConnectionBoundActivity.this.svcBinder = null;
+ }
+
+ };
+
+ }
+
+ Intent intentGetService = new Intent(this, ConnectionManagementService.class);
+ if (!this.bindService(intentGetService, svcConn, Context.BIND_AUTO_CREATE)) {
+ Logger.logError("Failed to bind to ConnectionManagementService (bindService returned false)");
+ return;
+ }
+
+ } catch (Exception ex) {
+ Logger.logError("Exception while bounding to inner connectivity management service.",
+ ex);
+ }
+
+ }
+
+ private void initChannel(IBinder service) {
+ ConnectionBoundActivity.this.svcBinder = service;
+ ConnectionBoundActivity.this.channel = new Channel(this, new Messenger(service),
+ new Messenger(new ResponseHandler()));
+ ConnectionBoundActivity.this.onManagementServiceConnected();
+ }
+
+ protected void onManagementServiceConnected() {
+ sendCmdPrefChanged(Prefs.PREF_MONITOR_NET_STATE);
+ }
+
+ protected boolean sendCmdStartConnect(AccessPointInfo network) {
+ if (channel == null) {
+ return false;
+ }
+ return channel.sendMsg(ConnectionManagementService.CMD_START_CONNECT, network,
+ Channel.PAYLOAD_APINFO);
+ }
+
+ protected boolean sendCmdAbortConnection() {
+ return sendMsgIfChannelConnected(ConnectionManagementService.CMD_ABORT_CONNECTION);
+ }
+
+ protected boolean sendCmdDisconnect() {
+ return sendMsgIfChannelConnected(ConnectionManagementService.CMD_DISCONNECT);
+ }
+
+ protected boolean sendCmdGetAvailableNetworks() {
+ return sendMsgIfChannelConnected(ConnectionManagementService.CMD_GET_AVAILABLE_NETWORKS);
+ }
+
+ protected boolean sendCmdStartMonitoringConnectionStatus() {
+ return sendMsgIfChannelConnected(ConnectionManagementService.CMD_START_MONITOR_CONNECTION_STATUS);
+ }
+
+ protected boolean sendCmdStopMonitoringConnectionStatus() {
+ return sendMsgIfChannelConnected(ConnectionManagementService.CMD_STOP_MONITOR_CONNECTION_STATUS);
+ }
+
+ protected boolean requestStatusUpdate() {
+ return sendMsgIfChannelConnected(ConnectionManagementService.CMD_STATUS_UPDATE);
+ }
+
+ protected boolean sendCmdAutoconnect() {
+ return sendMsgIfChannelConnected(ConnectionManagementService.CMD_AUTOCONNECT);
+ }
+
+ private boolean sendCmdPrefChanged(String prefname){
+ if (channel == null){
+ return false;
+ }
+ Bundle b = new Bundle();
+ b.putString(Channel.PAYLOAD_PREFKEY, prefname);
+ return channel.sendMsg(ConnectionManagementService.CMD_PREF_CHANGED, b, 0);
+ }
+
+ private void sendCmdUnbind() {
+ sendMsgIfChannelConnected(ConnectionManagementService.CMD_CLIENT_UNBINDING);
+ }
+
+ private boolean sendMsgIfChannelConnected(int what) {
+ return sendMsgIfChannelConnected(what, 0);
+ }
+
+ private boolean sendMsgIfChannelConnected(int what, int arg1) {
+ if (channel == null) {
+ return false;
+ }
+ return channel.sendMsg(what, null, arg1);
+ }
+
+ protected void onMsgStatusChange(ConnectionStatus status) {
+ }
+
+ protected void onMsgConnectionResult(ConnectionResult connres) {
+ }
+
+ protected void onMsgAvailableNetworks(AccessPointInfo[] infos) {
+ }
+
+ protected void onMsgAutoconnectReport(AccessPointInfo[] infos) {
+ }
+
+ protected void onMsgDisconnectReport(ConnectionStatus status) {
+ }
+
+ private class ResponseHandler extends Handler {
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+
+ case ConnectionManagementService.MSG_STATUS_CHANGE:
+ Logger.logDebug("Received status update from the management service");
+ ConnectionStatus c = channel.getConnectionStatusPayload(msg);
+ onMsgStatusChange(c);
+ break;
+
+ case ConnectionManagementService.MSG_CONNECTION_RESULT:
+ Logger.logDebug("Received connection result from management service");
+ ConnectionResult r = channel.getConnectionResultPayload(msg);
+ onMsgConnectionResult(r);
+ break;
+
+ case ConnectionManagementService.MSG_AVAILABLE_NETWORKS:
+ Logger.logDebug("Received available networks from management service");
+ onMsgAvailableNetworks(channel.getApinfoArrayPayload(msg));
+ break;
+
+ case ConnectionManagementService.MSG_AUTOCONNECT_REPORT:
+ Logger.logDebug("Received autoconnect report from management service");
+ onMsgAutoconnectReport(channel.getApinfoArrayPayload(msg));
+ break;
+
+ case ConnectionManagementService.MSG_DISCONNECT_REPORT:
+ Logger.logDebug("Received disconnect report from management service");
+ onMsgDisconnectReport(channel.getConnectionStatusPayload(msg));
+ break;
+
+ default:
+ Logger.logError("Received response from connection management service with unknown what: "
+ + msg.what);
+ }
+ }
+
+ }
+
+ private void registerPreferenceChangeListener() {
+
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext());
+ prefs.registerOnSharedPreferenceChangeListener(this);
+
+ }
+
+ private void unregisterPreferenceChangeListener() {
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext());
+ prefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+
+ if (sharedPreferences == null) {
+ return;
+ }
+
+ sharedPreferences.edit().commit();
+ Prefs.commit(getApplicationContext());
+ sendCmdPrefChanged(key);
+
+ }
+
+ protected void unbindFromService() {
+ sendCmdUnbind();
+ if (svcBinder != null && svcConn != null && channel != null) {
+ unbindService(svcConn);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ }
+
+ @Override
+ public void onDestroy() {
+ unregisterPreferenceChangeListener();
+ unbindFromService();
+ super.onDestroy();
+ }
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/CreditsActivity.java b/app/src/fil/libre/repwifiapp/activities/CreditsActivity.java
index 80c15e6..cc520a9 100644
--- a/app/src/fil/libre/repwifiapp/activities/CreditsActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/CreditsActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,14 +20,14 @@
package fil.libre.repwifiapp.activities;
-import fil.libre.repwifiapp.R;
-import android.os.Bundle;
import android.app.Activity;
+import android.os.Bundle;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.view.Menu;
import android.widget.TextView;
+import fil.libre.repwifiapp.R;
public class CreditsActivity extends Activity {
diff --git a/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java b/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java
index 32922c6..7578ec3 100644
--- a/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/InputPasswordActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -17,13 +17,11 @@
// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
//
// ********************************************************************
+//
+// ********************************************************************
package fil.libre.repwifiapp.activities;
-import fil.libre.repwifiapp.ActivityLauncher;
-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;
@@ -35,10 +33,15 @@ import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.network.AccessPointInfo;
public class InputPasswordActivity extends Activity implements OnCheckedChangeListener {
AccessPointInfo apinfo = null;
+ String message = null;
@Override
public void onCreate(Bundle icicle) {
@@ -54,11 +57,27 @@ public class InputPasswordActivity extends Activity implements OnCheckedChangeLi
TextView v = (TextView) findViewById(R.id.txt_insert_pass);
// get the network to set password to:
- this.apinfo = (AccessPointInfo) getIntent().getSerializableExtra(
+ this.apinfo = (AccessPointInfo) getIntent().getParcelableExtra(
ActivityLauncher.EXTRA_APINFO);
+
+ if (getIntent().hasExtra(ActivityLauncher.EXTRA_MESSAGE)){
+ this.message = getIntent().getStringExtra(ActivityLauncher.EXTRA_MESSAGE);
+ }
+
v.append(" " + apinfo.getSsid());
}
+
+ @Override
+ public void onStart(){
+ super.onStart();
+
+ if (this.message != null){
+ Utils.showMessage(message, this);
+ this.message = null;
+ }
+
+ }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@@ -81,7 +100,7 @@ public class InputPasswordActivity extends Activity implements OnCheckedChangeLi
String pass = txpass.getText().toString();
if (pass.length() == 0) {
- Commons.showMessage(getString(R.string.msg_password_empty), this);
+ Utils.showMessage(getString(R.string.msg_password_empty), this);
}
this.apinfo.setPassword(pass);
diff --git a/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java b/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java
index 8b7c60c..8ff1100 100644
--- a/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/InputSsidActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -17,20 +17,20 @@
// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
//
// ********************************************************************
-
package fil.libre.repwifiapp.activities;
-import fil.libre.repwifiapp.ActivityLauncher;
-import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
-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.view.Menu;
import android.view.View;
import android.widget.EditText;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.network.AccessPointInfo;
public class InputSsidActivity extends Activity {
@@ -66,8 +66,7 @@ public class InputSsidActivity extends Activity {
if (intent.hasExtra(ActivityLauncher.EXTRA_APINFO)) {
Bundle xtras = intent.getExtras();
- AccessPointInfo i = (AccessPointInfo) xtras
- .getSerializable(ActivityLauncher.EXTRA_APINFO);
+ AccessPointInfo i = (AccessPointInfo) xtras.getParcelable(ActivityLauncher.EXTRA_APINFO);
returnAccessPointInfo(i);
}
@@ -85,7 +84,7 @@ public class InputSsidActivity extends Activity {
String ssid = txssid.getText().toString();
if (ssid.length() == 0) {
- Commons.showMessage(getString(R.string.msg_network_name_empty), this);
+ Utils.showMessage(getString(R.string.msg_network_name_empty), this);
return;
}
diff --git a/app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java b/app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java
index 1f15252..eba62ac 100644
--- a/app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/Ipv4SettingsActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,21 +20,22 @@
package fil.libre.repwifiapp.activities;
-import fil.libre.repwifiapp.ActivityLauncher;
-import fil.libre.repwifiapp.Commons;
-import fil.libre.repwifiapp.R;
-import fil.libre.repwifiapp.helpers.AccessPointInfo;
-import fil.libre.repwifiapp.helpers.DhcpSettings;
-import android.nfc.FormatException;
-import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
+import android.nfc.FormatException;
+import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
-import android.widget.EditText;
import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.EditText;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.DhcpSettings;
+import fil.libre.repwifiapp.network.NetworkManager;
public class Ipv4SettingsActivity extends Activity implements OnCheckedChangeListener {
@@ -65,15 +66,14 @@ public class Ipv4SettingsActivity extends Activity implements OnCheckedChangeLis
return;
}
- this.currentNetwork = (AccessPointInfo) intent.getExtras().getSerializable(
- ActivityLauncher.EXTRA_APINFO);
+ this.currentNetwork = (AccessPointInfo) intent.getExtras().getParcelable(ActivityLauncher.EXTRA_APINFO);
if (this.currentNetwork == null) {
this.setResult(RESULT_CANCELED);
this.finish();
return;
}
- this.currentNetwork = Commons.storage.getSavedNetwork(currentNetwork);
+ this.currentNetwork = NetworkManager.getSavedNetwork(currentNetwork);
loadNetwork();
@@ -88,7 +88,7 @@ public class Ipv4SettingsActivity extends Activity implements OnCheckedChangeLis
private void loadNetwork() {
- setTitle(this.currentNetwork.getSsid());
+ setTitle(getString(R.string.text_ipv4_settings) + " " + this.currentNetwork.getSsid());
currentSettings = this.currentNetwork.getDhcpConfiguration();
loadSettings();
@@ -147,17 +147,17 @@ public class Ipv4SettingsActivity extends Activity implements OnCheckedChangeLis
String gw = txtGw.getText().toString();
if (!DhcpSettings.isValidAddress(ip)) {
- Commons.showMessage(getString(R.string.msg_invalid_ip),this);
+ Utils.showMessage(getString(R.string.msg_invalid_ip),this);
return;
}
if (!DhcpSettings.isValidMaks(mask)) {
- Commons.showMessage(getString(R.string.msg_invalid_netmask),this);
+ Utils.showMessage(getString(R.string.msg_invalid_netmask),this);
return;
}
if (!DhcpSettings.isValidAddress(gw)) {
- Commons.showMessage(getString(R.string.msg_invalid_gateway),this);
+ Utils.showMessage(getString(R.string.msg_invalid_gateway),this);
return;
}
@@ -166,10 +166,10 @@ public class Ipv4SettingsActivity extends Activity implements OnCheckedChangeLis
}
currentNetwork.setDhcpConfiguration(currentSettings);
- if (Commons.storage.save(currentNetwork)) {
- Commons.showMessage(getString(R.string.msg_network_saved),this);
+ if (NetworkManager.save(currentNetwork)) {
+ Utils.showMessage(getString(R.string.msg_network_saved),this);
} else {
- Commons.showMessage(getString(R.string.msg_network_save_fail),this);
+ Utils.showMessage(getString(R.string.msg_network_save_fail),this);
}
}
diff --git a/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java b/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java
index a5292d2..940d547 100644
--- a/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/LongTaskActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,83 +18,47 @@
//
// ********************************************************************
-
package fil.libre.repwifiapp.activities;
-import fil.libre.repwifiapp.ActivityLauncher;
-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.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.ProgressBar;
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 ActivityLauncher.RequestCode.CONNECT:
-
- ret = Commons.connectionEngine.connect((AccessPointInfo) params[0]);
- break;
-
- case ActivityLauncher.RequestCode.NETWORKS_GET:
-
- ret = Commons.connectionEngine.getAvailableNetworks();
- break;
-
- case ActivityLauncher.RequestCode.STATUS_GET:
-
- ret = Commons.connectionEngine.getConnectionStatus();
- break;
-
- default:
-
- break;
-
- }
-
- return ret;
-
- }
-
- @Override
- protected void onPostExecute(Object result) {
- taskCompleted(result, this.REQ_CODE);
- }
+import android.widget.Toast;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
+import fil.libre.repwifiapp.Prefs;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.ConnectionResult;
- }
+public class LongTaskActivity extends ConnectionBoundActivity {
private AccessPointInfo currentNetwork = null;
+ // private Task currentTask = null;
+
+ private int currentReqCode = -1;
+ private boolean isCancelled = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_long_task);
-
- toggleProgbar(Commons.isProgbarEnabled());
- startTask();
-
+ toggleProgbar(isProgbarEnabled());
+
+ }
+
+ @Override
+ public void onStart(){
+ super.onStart();
+ if (isServiceBound()){
+ startTask();
+ }
}
@Override
@@ -102,6 +66,21 @@ public class LongTaskActivity extends Activity {
return true;
}
+ @Override
+ protected void onManagementServiceConnected() {
+ startTask();
+ }
+
+ @Override
+ protected void onMsgConnectionResult(ConnectionResult connres) {
+ taskCompleted(connres, currentReqCode);
+ }
+
+ @Override
+ protected void onMsgAvailableNetworks(AccessPointInfo[] infos) {
+ taskCompleted(infos, currentReqCode);
+ }
+
private void startTask() {
// retrieve the request code:
@@ -112,40 +91,56 @@ public class LongTaskActivity extends Activity {
}
Object input = null;
- int reqCode = intent.getExtras().getInt(ActivityLauncher.EXTRA_REQCODE);
-
- switch (reqCode) {
+ currentReqCode = intent.getExtras().getInt(ActivityLauncher.EXTRA_REQCODE);
+
+ switch (currentReqCode) {
case ActivityLauncher.RequestCode.CONNECT:
// Extract AccessPointInfo
- input = intent.getExtras().getSerializable(ActivityLauncher.EXTRA_APINFO);
+ input = intent.getExtras().getParcelable(ActivityLauncher.EXTRA_APINFO);
currentNetwork = (AccessPointInfo) input;
setTitle(getString(R.string.msg_connecting_to) + " " + currentNetwork.getSsid() + "...");
- setMessage(getString(R.string.msg_connecting_to) + " " + currentNetwork.getSsid() + "...");
+ setMessage(getString(R.string.msg_connecting_to) + " " + currentNetwork.getSsid()
+ + "...");
+
+ sendCmdStartConnect(currentNetwork);
+
break;
case ActivityLauncher.RequestCode.NETWORKS_GET:
setTitle(getString(R.string.title_scanning));
setMessage(getString(R.string.msg_scanning_for_nets));
-
- case ActivityLauncher.RequestCode.STATUS_GET:
+
+ sendCmdGetAvailableNetworks();
+
+ break;
+
+/* case ActivityLauncher.RequestCode.STATUS_GET:
setTitle(getString(R.string.msg_checking_status));
setMessage(getString(R.string.msg_checking_status));
-
+ break;*/
+
default:
setTitle(getString(R.string.msg_please_wait));
setMessage(getString(R.string.msg_please_wait));
break;
}
- Task task = new Task(reqCode, input);
- task.execute(input);
+
+/* currentTask = new Task(reqCode, input);
+ currentTask.execute(input);*/
}
private void taskCompleted(Object result, int reqCode) {
- Utils.logDebug("Finished long task reqCode: " + reqCode, 1);
+ Logger.logDebug("Finished long task reqCode: " + reqCode);
+
+ if (isCancelled){
+ Logger.logDebug("Received result but activity has been canceled");
+ this.setResult(RESULT_CANCELED);
+ finish();
+ }
// Return to caller:
Intent intent = this.getIntent();
@@ -154,7 +149,7 @@ public class LongTaskActivity extends Activity {
case ActivityLauncher.RequestCode.CONNECT:
- intent.putExtra(ActivityLauncher.EXTRA_BOOLEAN, (Boolean) result);
+ intent.putExtra(ActivityLauncher.EXTRA_CONNRES, (ConnectionResult)result);
intent.putExtra(ActivityLauncher.EXTRA_APINFO, this.currentNetwork);
break;
@@ -162,15 +157,15 @@ public class LongTaskActivity extends Activity {
intent.putExtra(ActivityLauncher.EXTRA_APINFO_ARR, (AccessPointInfo[]) result);
break;
-
+/*
case ActivityLauncher.RequestCode.STATUS_GET:
intent.putExtra(ActivityLauncher.EXTRA_CONSTATUS, (ConnectionStatus) result);
- break;
+ break;*/
default:
- Utils.logDebug("Task terminating in null: ", 1);
+ Logger.logDebug("Task terminating in null: ", 1);
break;
}
@@ -199,7 +194,71 @@ public class LongTaskActivity extends Activity {
@Override
public void onBackPressed() {
- // suppress back button
+ promtpCancelJob();
+ }
+
+ private void promtpCancelJob() {
+
+ String msg = getString(R.string.msg_confirm_stop_job);
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this,
+ R.style.Theme_RepWifiDialogTheme);
+ dlgAlert.setMessage(msg);
+ dlgAlert.setPositiveButton(getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ confirmCancelJob();
+ return;
+ }
+ });
+ dlgAlert.setNegativeButton(getString(android.R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ return;
+ }
+ });
+
+ dlgAlert.setCancelable(false);
+ AlertDialog diag = dlgAlert.create();
+
+ diag.show();
+
+ }
+
+ private boolean cancelConnection() {
+ return sendCmdAbortConnection();
+ }
+
+ private void confirmCancelJob() {
+ /*
+ * if (currentTask != null){
+ * if (currentReqCode == RequestCode.CONNECT){
+ * Commons.connectionEngine.abortConnection();
+ * }
+ *
+ * currentTask.cancel(true);
+ * }
+ */
+
+ if (currentReqCode == RequestCode.CONNECT) {
+ if (cancelConnection()){
+
+ super.onBackPressed();
+ } else {
+ Toast.makeText(getApplicationContext(), getString(R.string.msg_error_generic), Toast.LENGTH_LONG).show();
+ }
+
+ } else {
+ isCancelled = true;
+ super.onBackPressed();
+ }
+
+
+ }
+
+ private boolean isProgbarEnabled() {
+ return Prefs.getBoolean(getApplicationContext(), Prefs.PREF_PROGBAR, true);
}
}
diff --git a/app/src/fil/libre/repwifiapp/activities/MainActivity.java b/app/src/fil/libre/repwifiapp/activities/MainActivity.java
index 7a22416..14f33e9 100644
--- a/app/src/fil/libre/repwifiapp/activities/MainActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/MainActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,64 +20,80 @@
package fil.libre.repwifiapp.activities;
-import java.net.SocketException;
-import fil.libre.repwifiapp.ActivityLauncher;
-import fil.libre.repwifiapp.Commons;
-import fil.libre.repwifiapp.R;
-import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
-import fil.libre.repwifiapp.helpers.AccessPointInfo;
-import fil.libre.repwifiapp.helpers.ConnectionStatus;
-import fil.libre.repwifiapp.helpers.NetworkManager;
-import fil.libre.repwifiapp.helpers.OpenVpnManager;
-import fil.libre.repwifiapp.helpers.RootCommand;
-import fil.libre.repwifiapp.helpers.Utils;
-import fil.libre.repwifiapp.helpers.WpaSupplicant;
-import android.os.Bundle;
+import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetManager;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.Parcelable;
import android.util.Log;
import android.view.View;
+import android.widget.Button;
import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.RelativeLayout.LayoutParams;
+import android.widget.TextView;
import android.widget.Toast;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.Prefs;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.helpers.RootCommand;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.ConnectionResult;
+import fil.libre.repwifiapp.network.ConnectionStatus;
+import fil.libre.repwifiapp.network.Engine;
+import fil.libre.repwifiapp.network.NetworkManager;
+import fil.libre.repwifiapp.network.WpaCli;
+import fil.libre.repwifiapp.network.WpaSupplicant;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketException;
-public class MainActivity extends MenuEnabledActivity {
+public class MainActivity extends VpnAndConnectionBoundActivity{
private ActivityLauncher launcher = new ActivityLauncher(this);
private BroadcastReceiver detachReceiver;
-
+ private ConnectionStatus status = null;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- if (!Commons.init(this)) {
- Utils.logDebug("Failed to initialize Commons. Aborting.");
- finish();
- return;
- }
+ Commons.init(getApplicationContext());
- if (! Commons.storage.updateStorageVersion()){
- Utils.logError("Failed to convert storage file to new version!");
+ if (!NetworkManager.updateStorageVersion()) {
+ Logger.logError("Failed to convert storage file to new version!");
}
-
- setImage();
+
+ toggleStatusAppearance(false);
setUsbDeviceMonitor();
setVersionOnTitle();
-
- OpenVpnManager.initialize(this);
+
+ if (isSystemApp()) {
+ setTitle(getTitle() + " (sysapp)");
+ }
}
@Override
public void onStart() {
super.onStart();
- Utils.logDebug("Main onStart()");
-
- Commons.updateNotification(this);
+ Logger.logDebug("Main onStart()");
if (handleIntent()) {
// app called for a specific intent.
@@ -88,14 +104,17 @@ public class MainActivity extends MenuEnabledActivity {
checkConditions();
- ConnectionStatus status = Commons.connectionEngine.getConnectionStatus();
- if (status != null && status.isConnected()) {
- Utils.logDebug("Main about to launch status activity...");
- launcher.launchStatusActivity(status);
+ if (isServiceBound()) {
+ requestStatusUpdate();
}
- Utils.logDebug("Main onStart() returning.");
+ Logger.logDebug("Main onStart() returning.");
+
+ }
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ super.onSaveInstanceState(savedInstanceState);
}
private boolean handleIntent() {
@@ -126,53 +145,62 @@ public class MainActivity extends MenuEnabledActivity {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- Utils.logDebug("Main onActivityResult(): ", 1);
+ Logger.logDebug("Main onActivityResult(): ");
if (intent == null) {
return;
}
- if (resultCode != RESULT_OK) {
+ if (resultCode != RESULT_OK && requestCode != RequestCode.VPN_PERMISSION_CONN) {
return;
}
AccessPointInfo i = null;
if (intent.hasExtra(ActivityLauncher.EXTRA_APINFO)) {
Bundle xtras = intent.getExtras();
- i = (AccessPointInfo) xtras.getSerializable(ActivityLauncher.EXTRA_APINFO);
+ i = (AccessPointInfo) xtras.getParcelable(ActivityLauncher.EXTRA_APINFO);
}
switch (requestCode) {
case RequestCode.PASS_INPUT:
+ Logger.logDebug("ReqCode: PASS_INPUT");
handleResultSetPass(i);
break;
case RequestCode.SELECT_CONN:
+ Logger.logDebug("ReqCode: SELECT_CONN");
boolean rescan = intent.getExtras().getBoolean(ActivityLauncher.EXTRA_RESCAN);
handleResultSelect(i, rescan);
break;
case RequestCode.CONNECT:
- boolean conres = intent.getExtras().getBoolean(ActivityLauncher.EXTRA_BOOLEAN);
+ Logger.logDebug("ReqCode: CONNECT");
+ ConnectionResult conres = (ConnectionResult) intent.getExtras().getParcelable(
+ ActivityLauncher.EXTRA_CONNRES);
handleFinishedConnecting(conres, i);
break;
-
case RequestCode.NETWORKS_GET:
- AccessPointInfo[] nets = (AccessPointInfo[]) intent.getExtras().getSerializable(
+ Logger.logDebug("ReqCode: NETWORKS_GET");
+ Parcelable[] p = intent.getExtras().getParcelableArray(
ActivityLauncher.EXTRA_APINFO_ARR);
+ AccessPointInfo[] nets = AccessPointInfo.fromParcellableArray(p);
launcher.launchSelectActivity(nets, true, false);
+ break;
case RequestCode.STATUS_SHOW:
+ Logger.logDebug("ReqCode: STATUS_SHOW");
// do nothing
break;
case RequestCode.SELECT_DETAILS:
+ Logger.logDebug("ReqCode: SELECT_DETAILS");
launcher.launchDetailsActivity(i);
break;
case RequestCode.DETAILS_SHOW:
+ Logger.logDebug("ReqCode: DETAILS_SHOW");
boolean del = intent.getExtras().getBoolean(ActivityLauncher.EXTRA_DELETE);
if (del) {
deleteNetwork(i);
@@ -180,13 +208,14 @@ public class MainActivity extends MenuEnabledActivity {
break;
case RequestCode.CONNECT_HIDDEN:
+ Logger.logDebug("ReqCode: CONNECT_HIDDEN");
if (i != null) {
+ Logger.logDebug("NetworkInfo NOT null, handling result");
handleResultSelect(i, false);
}
break;
-
default:
break;
@@ -207,22 +236,118 @@ public class MainActivity extends MenuEnabledActivity {
setTitle(getTitle() + " - v." + vers);
} catch (Exception e) {
- Utils.logError("Error while setting version on MainActivity's title.", e);
+ Logger.logError("Error while setting version on MainActivity's title.", e);
}
}
- private void setImage() {
+ private void showStatus(ConnectionStatus status) {
+
+ Logger.logDebug("MainActivity.showStatus()");
- ImageView img = (ImageView) findViewById(R.id.img_logo);
+ String msg = "";
+ this.status = status;
try {
- Drawable d = Drawable.createFromStream(getAssets().open("repwifi-logo-0.png"), null);
- img.setImageDrawable(d);
+
+ if (status == null) {
+ msg = getString(R.string.text_status) + ": [NULL]";
+ toggleStatusAppearance(false);
+
+ } else if (this.status.isConnected()) {
+ Logger.logDebug("showStatus isConnected,showing buttons");
+ msg = getString(R.string.msg_connected_to) + " " + status.SSID;
+ toggleStatusAppearance(true);
+
+ } else {
+ Logger.logDebug("showStatus status Else");
+ msg = getString(R.string.msg_disconnected);
+ toggleStatusAppearance(false);
+ }
+
} catch (Exception e) {
- Utils.logError("Error while loading logo image", e);
+ Logger.logError("Exception on showStatus", e);
+ msg = "[ERORR]";
}
+ TextView view = (TextView) findViewById(R.id.txt_status);
+ view.setText(msg);
+
+ }
+
+ private void toggleStatusAppearance(boolean connected) {
+
+ try {
+ Button b = (Button) findViewById(R.id.btn_disconnect);
+ Button i = (Button) findViewById(R.id.btn_info);
+ ImageView img = (ImageView) findViewById(R.id.img_logo);
+
+ LayoutParams lp = (LayoutParams) img.getLayoutParams();
+
+ b.setEnabled(connected);
+ i.setEnabled(connected);
+
+ if (connected) {
+ b.setVisibility(View.VISIBLE);
+ i.setVisibility(View.VISIBLE);
+ lp.removeRule(RelativeLayout.CENTER_HORIZONTAL);
+
+ } else {
+ b.setVisibility(View.INVISIBLE);
+ i.setVisibility(View.INVISIBLE);
+ lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
+ }
+
+ setLogoDrawable(img, connected);
+ img.setLayoutParams(lp);
+
+ } catch (Exception e) {
+ Logger.logError("Error while setting status appearance", e);
+
+ }
+
+ }
+
+ BitmapDrawable logoConn;
+ BitmapDrawable logoDisc;
+
+ public void setLogoDrawable(ImageView img, boolean connected) {
+
+ img.setImageDrawable(null);
+ System.gc();
+
+ try {
+
+ String res = "repwifi-logo-0-small.png";
+ BitmapDrawable logo = logoConn;
+ if (!connected) {
+ logo = logoDisc;
+ res = "repwifi-logo-1-small.png";
+ }
+
+ AssetManager am = getAssets();
+ InputStream s = am.open(res);
+
+ if (logo == null) {
+ logo = (BitmapDrawable) Drawable.createFromStream(s, res);
+ }
+ img.setImageDrawable(logo);
+
+ s.close();
+ } catch (IOException e) {
+ }
+
+ }
+
+ public void onBtnDisconnectClick(View v) {
+
+ disconnectVpn();
+ sendCmdDisconnect();
+
+ }
+
+ public void onBtnInfoClick(View v) {
+ launcher.launchStatusActivity(this.status);
}
private void setUsbDeviceMonitor() {
@@ -245,9 +370,17 @@ public class MainActivity extends MenuEnabledActivity {
registerReceiver(detachReceiver, filt2);
}
- private boolean checkConditions() {
+ private boolean checkConditions(boolean serviceStarted) {
+ // second chance to have the service bound:
+ boolean conds = (checkRootEnabled() && checkIsSystemApp() && checkInterface(true));
+ if (serviceStarted) {
+ conds = conds && isServiceBound();
+ }
+ return conds;
+ }
- return (checkRootEnabled() && checkInterface(true));
+ private boolean checkConditions() {
+ return checkConditions(false);
}
private boolean checkInterface(boolean alert) {
@@ -256,16 +389,16 @@ public class MainActivity extends MenuEnabledActivity {
String msg = "";
try {
- res = Commons.connectionEngine.isInterfaceAvailable(WpaSupplicant.INTERFACE_NAME);
+ res = Engine.isInterfaceAvailable(WpaSupplicant.INTERFACE_NAME);
} catch (SocketException e) {
- Utils.logError("SocketException during isInterfaceAvailable()", e);
+ Logger.logError("SocketException during isInterfaceAvailable()", e);
msg = "Error while retrieving interface list!";
res = false;
}
if (res == false && alert) {
msg = getResources().getString(R.string.msg_interface_not_found);
- Commons.showMessage(msg, this);
+ Utils.showMessage(msg, this);
}
return res;
@@ -283,7 +416,7 @@ public class MainActivity extends MenuEnabledActivity {
try {
excode = su.testRootAccess();
} catch (Exception e) {
- Utils.logError("Error while trying to get first Super User access.", e);
+ Logger.logError("Error while trying to get first Super User access.", e);
excode = -1;
result = false;
}
@@ -310,7 +443,7 @@ public class MainActivity extends MenuEnabledActivity {
}
if (!result) {
- Commons.showMessage(msg, this);
+ Utils.showMessage(msg, this);
}
return result;
@@ -328,7 +461,7 @@ public class MainActivity extends MenuEnabledActivity {
if (i.needsPassword()) {
// try to fetch network's configuration from storage
- AccessPointInfo fromStorage = Commons.storage.getSavedNetwork(i);
+ AccessPointInfo fromStorage = NetworkManager.getSavedNetwork(i);
if (fromStorage == null) {
launcher.launchPasswordActivity(i);
@@ -341,6 +474,8 @@ public class MainActivity extends MenuEnabledActivity {
}
+ // disconnect any vpn before connecting to a new network
+ disconnectVpn();
launcher.launchLongTaskActivityConnect(i);
}
@@ -350,44 +485,70 @@ public class MainActivity extends MenuEnabledActivity {
launcher.launchLongTaskActivityConnect(i);
}
- private void handleFinishedConnecting(boolean connectionResult, AccessPointInfo info) {
+ private void handleFinishedConnecting(ConnectionResult connectionResult, AccessPointInfo info) {
- if (connectionResult && info.needsPassword()) {
+ Logger.logDebug("handleFinishedConnecting");
- ConnectionStatus status = Commons.connectionEngine.getConnectionStatus();
- if (status != null) {
- // update APinfo with the right BSSID
- info.setBssid(status.BSSID);
- }
+ String toastText = null;
+ int res = connectionResult.getResult();
+ ConnectionStatus status = connectionResult.getStatus();
- // Save network
- if (Commons.storage.save(info)) {
- Toast toast2 = Toast.makeText(getApplicationContext(),
- getString(R.string.msg_network_saved), Toast.LENGTH_LONG);
- toast2.show();
+ switch (res) {
- } else {
- Toast toast2 = Toast.makeText(getApplicationContext(),
- getString(R.string.msg_network_save_fail), Toast.LENGTH_LONG);
- toast2.show();
- }
+ case ConnectionResult.CONN_OK:
- // show status
- launcher.launchStatusActivity(status);
+ Logger.logDebug("About to launch VPN on successful connection result.");
+ beginConnectVpn(status.getNetworkDetails());
+
+
+ break;
- } else {
- // alert that connection failed
- Toast toast = Toast.makeText(getApplicationContext(),
- getString(R.string.msg_connect_fail), Toast.LENGTH_LONG);
+ case ConnectionResult.CONN_GW_FAIL:
+ Logger.logDebug("Result code CONN_GW_FAIL");
+ toastText = getString(R.string.msg_gw_failed);
+ break;
+
+ case ConnectionResult.CONN_TIMEOUT:
+ // probable wrong password:
+ handleConnectionTimeout(info);
+ break;
+
+ default:
+ Logger.logDebug("Result code: " + res);
+ toastText = getString(R.string.msg_connect_fail);
+ break;
+
+ }
+
+ if (toastText != null) {
+ Toast toast = Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_LONG);
toast.show();
}
+
+ showStatus(status);
+
+ }
+
+ private void handleConnectionTimeout(AccessPointInfo info) {
+ // reset wpa_supplicant's state
+ WpaCli.disconnect();
+ if (!WpaCli.terminateSupplicant()) {
+ WpaSupplicant.kill();
+ }
+
+ if (info.needsPassword()) {
+ // prompt user for password retry:
+ launcher.launchPasswordActivity(info, getString(R.string.msg_connection_timeout));
+ } else {
+ Utils.showMessage(getString(R.string.msg_connection_timeout_nopass), this);
+ }
+
}
private void deleteNetwork(AccessPointInfo info) {
- NetworkManager manager = new NetworkManager(Commons.getNetworkStorageFile());
String msg = "";
- if (manager.remove(info)) {
+ if (NetworkManager.remove(info)) {
msg = getString(R.string.msg_netinfo_deleted);
} else {
msg = getString(R.string.msg_netinfo_delete_fail);
@@ -401,10 +562,11 @@ public class MainActivity extends MenuEnabledActivity {
private void handleUsbEvent(boolean detached) {
if (detached && !checkInterface(false)) {
- // device disconnected, update the status bar:
- Commons.updateNotification(this);
+ // device disconnected:
+ // clear back-end state and update status.
+ disconnectVpn();
- } else if (Commons.isAutoConnectEnabled()) {
+ } else if (isAutoConnectEnabled()) {
try {
@@ -417,7 +579,7 @@ public class MainActivity extends MenuEnabledActivity {
msWaited += 100;
if (checkInterface(false)) {
- autoConnect();
+ sendCmdAutoconnect();
return;
}
}
@@ -429,56 +591,213 @@ public class MainActivity extends MenuEnabledActivity {
}
- }
+ requestStatusUpdate();
- private void autoConnect() {
+ }
- try {
+ private boolean isAutoConnectEnabled() {
+ return Prefs.getBoolean(getApplicationContext(), Prefs.PREF_AUTOCONNECT, false);
+ }
- AccessPointInfo[] nets = Commons.connectionEngine.getAvailableNetworks();
- if (nets == null || nets.length == 0) {
- return;
- }
+ private void doScan() {
+ if (checkConditions(true)) {
+ launcher.launchLongTaskActivityScan();
+ }
+ }
- for (AccessPointInfo i : nets) {
+ public void btnScanClick(View v) {
+ doScan();
+ }
- if (Commons.storage.isKnown(i)) {
- launcher.launchLongTaskActivityConnect(i);
- return;
- }
+ public void btnHiddenClick(View v) {
+ if (checkConditions(true)) {
+ launcher.launchInputSsidActivity();
+ }
+ }
- }
+ public void btnManageClick(View v) {
+ launcher.launchSelectActivity(null, false, true);
+ }
- // if no network is known, shows available networks to the user.
- launcher.launchSelectActivity(nets, true, false);
+ private boolean checkIsSystemApp() {
- } catch (Exception e) {
- Utils.logError("Error while autoconnecting", e);
- Commons.showMessage(getString(R.string.msg_autoconnect_error), this);
+ if (isSystemApp()) {
+ return true;
+ } else {
+ promtpMakeSystemApp();
+ return false;
}
+ }
+
+ private void promtpMakeSystemApp() {
+
+ String msg = getString(R.string.msg_make_system_app);
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this,
+ R.style.Theme_RepWifiDialogTheme);
+ dlgAlert.setMessage(msg);
+ dlgAlert.setPositiveButton(getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ confirmMakeSystemApp();
+ return;
+ }
+ });
+ dlgAlert.setNegativeButton(getString(android.R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ return;
+ }
+ });
+
+ dlgAlert.setCancelable(false);
+ AlertDialog diag = dlgAlert.create();
+
+ diag.show();
}
- private void doScan() {
- if (checkConditions()) {
- launcher.launchLongTaskActivityScan();
+ private void confirmMakeSystemApp() {
+ String msg = getString(R.string.msg_confirm_make_system_app);
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this,
+ R.style.Theme_RepWifiDialogTheme);
+ dlgAlert.setMessage(msg);
+ dlgAlert.setPositiveButton(getString(android.R.string.yes),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ makeSystemApp();
+ return;
+ }
+ });
+ dlgAlert.setNegativeButton(getString(android.R.string.no),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ return;
+ }
+ });
+
+ dlgAlert.setCancelable(false);
+ AlertDialog diag = dlgAlert.create();
+
+ diag.show();
+ }
+
+ private boolean isSystemApp() {
+
+ PackageManager pm = getPackageManager();
+ boolean isSystem = false;
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(getPackageName(), 0);
+
+ isSystem = ((ai.flags & ApplicationInfo.FLAG_SYSTEM) == 1);
+
+ } catch (NameNotFoundException e) {
+ // always succeeds, as we use our own package
}
+ return isSystem;
+
}
- public void btnScanClick(View v) {
- doScan();
+ public static final String SYS_FOLDER = "/system";
+ public static final String SYS_APP_FOLDER = "/system/priv-app";
+ private static final String SYSAPP_SCRIPT_FNAME = "make-system-app.sh";
+
+ private boolean makeSystemApp() {
+
+ PackageManager pm = getPackageManager();
+ String pkgName = getPackageName();
+ File currentSourceDir = null;
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(pkgName, 0);
+ currentSourceDir = new File(ai.sourceDir);
+
+ } catch (NameNotFoundException e) {
+ }// always succeeds, as we use our own package
+
+ String parentFolder = currentSourceDir.getParentFile().getName();
+ if (!parentFolder.contains(pkgName)) {
+ // use the plain package name as a parent folder for the apk
+ parentFolder = pkgName;
+ }
+
+ String targetDir = SYS_APP_FOLDER + "/" + parentFolder;
+
+ // get own data directory:
+ File ownDir = getFilesDir();
+ File scriptFile = new File(ownDir, SYSAPP_SCRIPT_FNAME);
+ String conts = Utils.rawResourceAsString(getApplicationContext(), R.raw.make_system_app);
+
+ if (conts == null) {
+ Logger.logError("Error while opening script from raw resources.");
+ return false;
+ }
+
+ if (!Utils.writeFile(scriptFile.getAbsolutePath(), conts, true)) {
+ Logger.logError("Failed to write script contents to file.");
+ return false;
+ }
+
+ Logger.logDebug("Starting script to make myself a system app...");
+
+ String cmd = "bash \"" + scriptFile.getAbsolutePath() + "\"" + " \"" + targetDir + "\""
+ + " \"" + currentSourceDir.getAbsolutePath() + "\"" + " \"" + SYS_FOLDER
+ + "\"";
+
+ return RootCommand.executeRootCmd(cmd);
+
}
+
+
+ @Override
+ protected void onMsgDisconnectReport(ConnectionStatus status) {
+ String msg = "";
- public void btnHiddenClick(View v) {
+ if (status != null && !status.isConnected()) {
+ msg = getString(R.string.msg_disconnected);
+ } else {
+ msg = getString(R.string.msg_disconnect_fail);
+ }
- if (checkConditions()) {
- launcher.launchInputSsidActivity();
+ Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
+ showStatus(status);
+
+ }
+
+ @Override
+ protected void onMsgAutoconnectReport(AccessPointInfo[] infos) {
+ if (infos != null && infos.length > 0) {
+ launcher.launchSelectActivity(infos, true, false);
}
+ }
+ @Override
+ protected void onMsgStatusChange(ConnectionStatus status) {
+ Logger.logDebug("Received status update from service.");
+ showStatus(status);
}
- public void btnManageClick(View v) {
- launcher.launchSelectActivity(null, false, true);
+ @Override
+ protected void onManagementServiceConnected() {
+ super.onManagementServiceConnected();
+ requestStatusUpdate();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ }
+
+ @Override
+ public void onDestroy() {
+
+ if (detachReceiver != null) {
+ unregisterReceiver(detachReceiver);
+ }
+
+ super.onDestroy();
}
}
diff --git a/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java b/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java
index f5c8516..55afd5a 100644
--- a/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/MenuEnabledActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,10 +20,6 @@
package fil.libre.repwifiapp.activities;
-import java.lang.reflect.Field;
-import fil.libre.repwifiapp.Commons;
-import fil.libre.repwifiapp.R;
-import fil.libre.repwifiapp.helpers.RootCommand;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
@@ -31,6 +27,10 @@ import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewConfiguration;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.RootCommand;
+import java.lang.reflect.Field;
public class MenuEnabledActivity extends Activity {
@@ -95,8 +95,7 @@ public class MenuEnabledActivity extends Activity {
if (silent) {
- Commons.connectionEngine.disconnect();
- Commons.killBackEnd(this, true);
+ Utils.killBackEnd(this, true);
super.onDestroy();
RootCommand.executeRootCmd("am force-stop " + getPackageName());
diff --git a/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java b/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java
index f2a8944..7b12efc 100644
--- a/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/NetworkDetailsActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,23 +20,23 @@
package fil.libre.repwifiapp.activities;
-import java.util.Date;
-import fil.libre.repwifiapp.ActivityLauncher;
-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.os.Bundle;
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;
+import android.widget.TextView;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.NetworkManager;
+import java.util.Date;
public class NetworkDetailsActivity extends Activity implements OnCheckedChangeListener {
@@ -57,7 +57,7 @@ public class NetworkDetailsActivity extends Activity implements OnCheckedChangeL
return;
}
- this.currentNetwork = (AccessPointInfo) intent.getExtras().getSerializable(
+ this.currentNetwork = (AccessPointInfo) intent.getExtras().getParcelable(
ActivityLauncher.EXTRA_APINFO);
if (this.currentNetwork == null) {
this.setResult(RESULT_CANCELED);
@@ -72,9 +72,9 @@ public class NetworkDetailsActivity extends Activity implements OnCheckedChangeL
@Override
protected void onStart() {
super.onStart();
- currentNetwork = Commons.storage.getSavedNetwork(currentNetwork);
+ currentNetwork = NetworkManager.getSavedNetwork(currentNetwork);
};
-
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
@@ -100,21 +100,22 @@ public class NetworkDetailsActivity extends Activity implements OnCheckedChangeL
}
if (showPassword) {
- v.append("\n\n" + getString(R.string.text_password) + ":\n" + this.currentNetwork.getPassword());
+ v.append("\n\n" + getString(R.string.text_password) + ":\n"
+ + this.currentNetwork.getPassword());
} else {
v.append("\n\n\n");
}
}
- public void btnIpSettingsClick(View v){
+ public void btnIpSettingsClick(View v) {
new ActivityLauncher(this).launchIpSettingsActivity(currentNetwork);
}
-
- public void btnVpnSettingsClick(View v){
+
+ public void btnVpnSettingsClick(View v) {
new ActivityLauncher(this).launchVpnSettingsActivity(currentNetwork);
}
-
+
public void btnDeleteClick(View v) {
String msg = getResources().getString(R.string.msg_confirm_delete_network);
diff --git a/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java b/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java
index 51baed8..f1e1a96 100644
--- a/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/SelectNetworkActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,15 +20,9 @@
package fil.libre.repwifiapp.activities;
-import fil.libre.repwifiapp.ActivityLauncher;
-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.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
@@ -38,6 +32,11 @@ import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.NetworkButton;
public class SelectNetworkActivity extends Activity implements OnClickListener {
@@ -75,8 +74,8 @@ public class SelectNetworkActivity extends Activity implements OnClickListener {
finish();
return;
}
- AccessPointInfo[] nets = (AccessPointInfo[]) intent.getExtras().getSerializable(
- ActivityLauncher.EXTRA_APINFO_ARR);
+ AccessPointInfo[] nets = AccessPointInfo.fromParcellableArray(intent.getExtras().getParcelableArray(
+ ActivityLauncher.EXTRA_APINFO_ARR));
if (nets == null) {
this.setResult(RESULT_CANCELED);
finish();
@@ -134,7 +133,7 @@ public class SelectNetworkActivity extends Activity implements OnClickListener {
private void showNetworksForConnection(AccessPointInfo[] info) {
if (info == null) {
- Utils.logError("Unable to retrieve network list!");
+ Logger.logError("Unable to retrieve network list!");
writeOut(getString(R.string.msg_network_list_fail));
return;
}
@@ -203,7 +202,7 @@ public class SelectNetworkActivity extends Activity implements OnClickListener {
LayoutParams.WRAP_CONTENT);
button.setLayoutParams(params);
button.setBackground(getResources().getDrawable(R.drawable.repwifi_button));
- button.setTextColor(Commons.colorThemeLight);
+ button.setTextColor(getResources().getColor(R.color.ThemeLight));
button.setTextSize(20);
button.setPadding(25, 10, 25, 10);
button.setGravity(Gravity.CENTER_HORIZONTAL);
diff --git a/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java b/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java
index 36e0e1f..c50524a 100644
--- a/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/SettingsActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,19 +18,28 @@
//
// ********************************************************************
-
package fil.libre.repwifiapp.activities;
-import org.apache.http.conn.util.InetAddressUtils;
-import java.util.List;
-import fil.libre.repwifiapp.Commons;
-import fil.libre.repwifiapp.R;
-import fil.libre.repwifiapp.helpers.Utils;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences.Editor;
import android.os.Bundle;
+import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import fil.libre.repwifiapp.Prefs;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.R.string;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.service.ConnectionManagementService;
+import org.apache.http.conn.util.InetAddressUtils;
+import java.util.List;
public class SettingsActivity extends PreferenceActivity {
@@ -38,6 +47,7 @@ public class SettingsActivity extends PreferenceActivity {
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.Theme_SettingsTheme);
super.onCreate(savedInstanceState);
+
}
@Override
@@ -54,7 +64,7 @@ public class SettingsActivity extends PreferenceActivity {
setConfirmKillBackend();
setDumpFileClick();
-
+ setDebugPriorityChangeListener();
}
private void setConfirmKillBackend() {
@@ -64,7 +74,7 @@ public class SettingsActivity extends PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference p) {
- Commons.killBackEnd(getActivity(), false);
+ Utils.killBackEnd(getActivity(), false);
return true;
}
});
@@ -77,18 +87,38 @@ public class SettingsActivity extends PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference p) {
- if (Utils.dumpLogcatToFile(Commons.getLogDumpFile())) {
- Commons.showMessage(getString(R.string.msg_log_saved) + ": \n" + Commons.getLogDumpFile(),
- getActivity());
+ if (Logger.dumpLogcatToFile(getActivity())) {
+ Utils.showMessage(
+ getString(R.string.msg_log_saved) + ": \n"
+ + Logger.getLogDumpFile(), getActivity());
} else {
- Commons.showMessage(getString(R.string.msg_log_save_fail), getActivity());
+ Utils.showMessage(getString(R.string.msg_log_save_fail), getActivity());
}
return true;
}
});
}
+ /**
+ * Monitors changes in the "log priority" setting, and reflects them
+ * onto the Logger class.
+ */
+ private void setDebugPriorityChangeListener() {
+
+ ListPreference logPrioPref = (ListPreference) getPreferenceScreen().findPreference(
+ "debug_priority");
+
+ logPrioPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Logger.setLogPriority(Integer.parseInt((String) newValue));
+ return true;
+ }
+ });
+ }
+
}
public static class GeneralSettingFragment extends PreferenceFragment {
@@ -98,26 +128,37 @@ public class SettingsActivity extends PreferenceActivity {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.general_settings);
- setValidationListener("dns1");
- setValidationListener("dns2");
+ setIpFormatValidationListener(Prefs.PREF_DNS_1);
+ setIpFormatValidationListener(Prefs.PREF_DNS_2);
setConfirmRestore();
+
+ formatSummaryMonitoryConnection();
+
+ }
+
+ private void formatSummaryMonitoryConnection() {
+
+ CheckBoxPreference chkMonitor = (CheckBoxPreference) findPreference("monitor_connection");
+ chkMonitor.setSummary(getString(string.summary_monitor_connection_state).replace(
+ ConnectionManagementService.PLACEHOLDER_CHECK_STATUS_INTERVAL,
+ String.valueOf(ConnectionManagementService.CHECK_STATUS_INTERVAL_SECS)));
}
- private void setValidationListener(String prefName) {
- EditTextPreference edit_Pref = (EditTextPreference) getPreferenceScreen()
+ private void setIpFormatValidationListener(String prefName) {
+ EditTextPreference editPref = (EditTextPreference) getPreferenceScreen()
.findPreference(prefName);
- edit_Pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ editPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- // put validation here..
+
if (((String) newValue).isEmpty()
|| InetAddressUtils.isIPv4Address((String) newValue)) {
return true;
} else {
- Commons.showMessage(getString(R.string.msg_error_ip_format), getActivity());
+ Utils.showMessage(getString(R.string.msg_error_ip_format), getActivity());
return false;
}
}
@@ -131,12 +172,55 @@ public class SettingsActivity extends PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference p) {
- Commons.resetSettingsDefault(getActivity(), false);
+ resetSettingsDefault(false);
return true;
}
});
}
+
+ public void resetSettingsDefault(boolean silent) {
+
+ Context context = getActivity();
+
+ if (silent) {
+
+ Editor e = PreferenceManager.getDefaultSharedPreferences(context).edit();
+ e.clear();
+ e.commit();
+
+ } else {
+
+ String msg = context.getString(R.string.confirm_reset_settings);
+ AlertDialog.Builder dlgAlert = new AlertDialog.Builder(context,
+ R.style.Theme_RepWifiDialogTheme);
+ dlgAlert.setMessage(msg);
+ dlgAlert.setPositiveButton(context.getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ resetSettingsDefault(true);
+ return;
+ }
+ });
+ dlgAlert.setNegativeButton(context.getString(android.R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ return;
+ }
+ });
+
+ dlgAlert.setCancelable(false);
+ AlertDialog diag = dlgAlert.create();
+
+ diag.show();
+
+ return;
+ }
+
+ }
+
}
}
diff --git a/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java b/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java
index 21bfc4c..7076556 100644
--- a/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/ShowStatusActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,274 +20,67 @@
package fil.libre.repwifiapp.activities;
-import fil.libre.repwifiapp.ActivityLauncher;
-import fil.libre.repwifiapp.Commons;
-import fil.libre.repwifiapp.R;
-import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
-import fil.libre.repwifiapp.helpers.AccessPointInfo;
-import fil.libre.repwifiapp.helpers.ConnectionStatus;
-import fil.libre.repwifiapp.helpers.OpenVpnManager;
-import fil.libre.repwifiapp.helpers.Utils;
-import android.content.Intent;
import android.os.Bundle;
-import android.os.RemoteException;
import android.view.View;
-import android.widget.Button;
import android.widget.TextView;
-import android.widget.Toast;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.ConnectionStatus;
public class ShowStatusActivity extends MenuEnabledActivity {
private ConnectionStatus status;
- // private AccessPointInfo info;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_status);
if (getIntent().hasExtra(ActivityLauncher.EXTRA_CONSTATUS)) {
- this.status = (ConnectionStatus) getIntent().getSerializableExtra(
+ this.status = (ConnectionStatus) getIntent().getParcelableExtra(
ActivityLauncher.EXTRA_CONSTATUS);
}
try {
- showStatus(false);
+ showStatus();
} catch (Exception e) {
- Utils.logError("Exception on showStatus", e);
+ Logger.logError("Exception on showStatus", e);
}
}
- @Override
- public void onRestart() {
- super.onRestart();
- try {
- showStatus(true);
- } catch (Exception e) {
- Utils.logError("Exception on showStatus", e);
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent intent) {
-
- switch (requestCode) {
+ private void showStatus() {
- case RequestCode.VPN_PERMISSION:
-
- if (resultCode == RESULT_OK) {
- endLaunchVpn(true);
- } else {
- endLaunchVpn(false);
- }
+ if (this.status != null) {
- break;
+ String txt = getPrintableConnectionStatus(status);
- default:
-
- break;
+ TextView t = (TextView) findViewById(R.id.txt_status);
+ t.setText(txt);
}
}
- private void setMessage(String msg) {
- TextView view = (TextView) findViewById(R.id.txt_status);
- view.setText(msg);
+ public void onBtnMainClick(View v) {
+ finish();
}
- private void showStatus(boolean refresh) throws Exception {
-
- if (refresh || status == null) {
- this.status = Commons.connectionEngine.getConnectionStatus();
- }
+ public String getPrintableConnectionStatus(ConnectionStatus status) {
if (status == null) {
- this.finish();
-
- } else if (this.status.isConnected()) {
- Utils.logDebug("StatusActivity isConnected,showing buttons");
- setMessage(getString(R.string.msg_connected_to) + " " + status.SSID + "\n\n"
- + getString(R.string.text_ip_address) + ": " + status.IP + "\n");
- toggleBtnDisconnect(true);
- beginLauncVpn();
-
- } else {
- Utils.logDebug("StatusActivity status Else");
- setMessage(getString(R.string.text_status) + ":\n" + status.status);
- toggleBtnDisconnect(false);
+ return "[NULL]";
}
- Commons.updateNotification(this);
+ String fmat = "%s: %s\n%s: %s\n%s: %s\n%s: %s\n%s: %s\n";
- }
-
- 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);
- }
+ return String.format(fmat, getString(R.string.text_ip_address), status.IP,
+ getString(R.string.text_subnet_mask), status.subnetMask,
+ getString(R.string.text_gateway), status.gateway,
+ getString(R.string.text_broadcast_address), status.broadcastAddress,
+ getString(R.string.text_hardware_address), status.hwAddress);
}
- public void onBtnDisconnectClick(View v) {
-
- disconnectVpn();
-
- boolean res = Commons.connectionEngine.disconnect();
- String msg = "";
- if (res) {
- msg = getString(R.string.msg_disconnected);
- } else {
- msg = getString(R.string.msg_disconnect_fail);
- }
-
- Toast toast = Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT);
- toast.show();
-
- try {
- showStatus(true);
- } catch (Exception e) {
- Utils.logError("Exception on showStatus", e);
- }
-
- }
-
- private void disconnectVpn() {
-
- if (! OpenVpnManager.isVpnConnected()){
- return;
- }
-
- if (OpenVpnManager.disconnect()) {
- Toast t = Toast.makeText(this, getString(R.string.msg_vpn_disconnect),
- Toast.LENGTH_LONG);
- t.show();
-
- } else {
- Commons.showMessage(getString(R.string.msg_vpn_disconnect_error), this);
- }
-
- }
-
- private void beginLauncVpn() throws Exception {
-
- if (OpenVpnManager.isVpnConnected()){
- // already connected;
- return;
- }
-
- if (!OpenVpnManager.isExternalAppInstalled(this)) {
- Utils.logDebug("External VPN app not installed.");
- return;
- }
-
- if (getVpnNameIfAny() == null){
- Utils.logDebug("No vpn profile set. Exiting beginLaunchVpn()");
- return;
- }
-
- // first, we make sure we have permission to use the vpn service.
- Intent pi;
-
- try {
- pi = OpenVpnManager.askApiPermissionsGetIntent();
- } catch (RemoteException e) {
- Utils.logError("Exception while asking for VPN permission", e);
- Toast t = Toast.makeText(getApplicationContext(), getString(R.string.msg_vpn_connect_error), Toast.LENGTH_LONG);
- t.show();
- return;
-
- }
-
- if (pi == null){
- // no need to ask for permission
- Utils.logDebug("No need for vpn permission: going to endLaunchVpn.");
- endLaunchVpn(true);
-
- } else{
- // launch the intent to ask permission
- Utils.logDebug("Need to ask for vpn permission. Starting intent..");
- startActivityForResult(pi, ActivityLauncher.RequestCode.VPN_PERMISSION);
- }
-
- }
-
- private void endLaunchVpn(boolean permissionGranted) {
-
- try {
-
- if (!permissionGranted) {
- // warn user that permission must be granted
- Utils.logDebug("User rejected vpn permission.");
- String msg = getString(R.string.msg_vpn_no_permission).replace(
- OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME);
- Commons.showMessage(msg, this);
- return;
- }
-
- String profname = getVpnNameIfAny();
-
- // check if profile exists
- String profUuid = OpenVpnManager.getUuidFromName(profname);
- if (profUuid == null){
- // warn user that selected profile doesn't exist
- Commons.showMessage(getString(R.string.msg_vpn_wrong_profile), this);
- return;
- }
-
- if (OpenVpnManager.startVpn(profUuid)){
- Toast t = Toast.makeText(this, getString(R.string.msg_vpn_launched), Toast.LENGTH_LONG);
- t.show();
- } else {
- Commons.showMessage(getString(R.string.msg_vpn_connect_error),this);
- }
-
- } catch (Exception e) {
- Utils.logError("Exception while endLaunchVpn", e);
-
- }
-
- }
-
- private String getVpnNameIfAny(){
-
- if (status == null) {
- return null;
- }
-
- AccessPointInfo i = status.getNetworkDetails();
- if (i == null) {
- return null;
- }
-
- String profname = i.getVpnProfileName();
- if (profname == null || profname.isEmpty()) {
- return null;
- } else {
- return profname;
- }
-
- }
-
- public void onBtnMainClick(View v) {
- finish();
- }
-
- @Override
- public void onBackPressed() {
- moveTaskToBack(true);
- }
-
}
diff --git a/app/src/fil/libre/repwifiapp/activities/VpnAndConnectionBoundActivity.java b/app/src/fil/libre/repwifiapp/activities/VpnAndConnectionBoundActivity.java
new file mode 100644
index 0000000..4acf28a
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/activities/VpnAndConnectionBoundActivity.java
@@ -0,0 +1,435 @@
+//
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+// This file is based upon the example file included in
+// de.blinkt.openvpn package by Arne Schwabe.
+//
+// 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 android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.widget.Toast;
+import de.blinkt.openvpn.api.APIVpnProfile;
+import de.blinkt.openvpn.api.IOpenVPNAPIService;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class VpnAndConnectionBoundActivity extends ConnectionBoundActivity {
+
+ public static final String SERVICE_PACKAGE_NAME = "de.blinkt.openvpn";
+ public static final String APP_COMMON_NAME = "OpenVPN for Android";
+ public static final String PLACEHOLDER_APPNAME = "[VPN_EXT_APP]";
+
+ private static final int ACTION_NONE = 0;
+ private static final int ACTION_GET_PROFILES = 1;
+ private static final int ACTION_CONNECT = 2;
+
+ protected IOpenVPNAPIService _vpnSvc;
+
+ private AccessPointInfo _lastInfo;
+ private int _lastAction = ACTION_NONE;
+
+ private int lastRequestCode = ActivityLauncher.RequestCode.NONE;
+ private boolean permissionAsked = false;
+
+ private ServiceConnection _svcConnection;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ bindVpnService(ACTION_NONE);
+ }
+
+ private void bindVpnService(int action) {
+
+ if (!isExternalAppInstalled()) {
+ Logger.logDebug("External VPN app is not installed. Skipping vpn service binding.");
+ return;
+ }
+
+ _lastAction = action;
+
+ this._svcConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ _vpnSvc = IOpenVPNAPIService.Stub.asInterface(service);
+ onVpnServiceConnected();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ _vpnSvc = null;
+ onVpnServiceDisconnected();
+ }
+ };
+
+ Intent intentGetService = new Intent(IOpenVPNAPIService.class.getName());
+ intentGetService.setPackage(SERVICE_PACKAGE_NAME);
+ if (!bindService(intentGetService, _svcConnection, Context.BIND_AUTO_CREATE)) {
+ Logger.logError("FAILED to bind to OpenVPN service!");
+ }
+
+ }
+
+ private void unbindVpnService() {
+ if (_svcConnection != null && _vpnSvc != null) {
+ unbindService(_svcConnection);
+ }
+ }
+
+ protected void onVpnServiceConnected() {
+
+ switch (_lastAction) {
+ case ACTION_NONE:
+ return;
+
+ case ACTION_GET_PROFILES:
+ beginGetExistingVpnProfiles();
+ break;
+
+ case ACTION_CONNECT:
+ beginConnectVpn(_lastInfo);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ protected void onVpnServiceDisconnected() {
+ }
+
+ protected void onVpnProfilesAvailable(List<String> vpnProfiles) {
+ }
+
+ protected void onVpnPermissionDenied(){
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+
+ if (requestCode != ActivityLauncher.RequestCode.VPN_PERMISSION_CONN
+ && requestCode != ActivityLauncher.RequestCode.VPN_PERMISSION_LIST) {
+ // activity result is unrelated to our code.
+ return;
+
+ } else if (resultCode != Activity.RESULT_OK) {
+ // warn user that permission is needed to manage VPN
+
+ Logger.logDebug("User rejected vpn permission.");
+
+ String msg = getString(R.string.msg_vpn_no_permission).replace(
+ VpnAndConnectionBoundActivity.PLACEHOLDER_APPNAME,
+ VpnAndConnectionBoundActivity.APP_COMMON_NAME);
+ Utils.showMessage(msg, this);
+
+ onVpnPermissionDenied();
+ return;
+ }
+
+ switch (lastRequestCode) {
+
+ case ActivityLauncher.RequestCode.VPN_PERMISSION_CONN:
+
+ endConnectVpn();
+ break;
+
+ case ActivityLauncher.RequestCode.VPN_PERMISSION_LIST:
+
+ endGetExistingVpnProfiles();
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ protected void close() {
+ unbindVpnService();
+ }
+
+ protected boolean isExternalAppInstalled() {
+
+ try {
+
+ ApplicationInfo i;
+ i = getPackageManager().getApplicationInfo(SERVICE_PACKAGE_NAME, 0);
+ return (i != null);
+
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+
+ }
+
+ private boolean doStartVpn(String profileUuid) {
+
+ if (profileUuid == null) {
+ Logger.logError("Invoked startVpn with null uuid");
+ return false;
+ }
+
+ if (_vpnSvc == null) {
+ Logger.logError("Invoked startVpn but inner service is null.");
+ return false;
+ }
+
+ try {
+
+ _vpnSvc.startProfile(profileUuid);
+ return true;
+
+ } catch (RemoteException e) {
+ Logger.logError("Exception while starting vpn.", e);
+ return false;
+ }
+
+ }
+
+ private String getUuidFromName(String profileName) {
+ if (_vpnSvc == null) {
+ Logger.logError("Called getUuidFromName but inner service is null!");
+ return null;
+ }
+
+ try {
+ List<APIVpnProfile> list = _vpnSvc.getProfiles();
+
+ for (APIVpnProfile vp : list) {
+ if (vp.mName.equals(profileName)) {
+ return vp.mUUID;
+ }
+ }
+
+ return null;
+
+ } catch (RemoteException e) {
+ Logger.logError("Exception while retrieving profiles from vpn service.", e);
+ return null;
+ }
+ }
+
+ /***
+ *
+ * @return Returns 0 if no permission is needed,
+ * 1 if permission is needed and it was asked successfully,
+ * a negative number on error.
+ */
+ private int askPermissionIfNeeded(int requestCode) {
+
+ Logger.logDebug("Called OpenVpnManager.askPermissionIfNeeded()");
+
+ if (_vpnSvc == null) {
+ Logger.logError("Internal vpn service is null, but not supposed to be. Aborting.");
+ return -1;
+ }
+
+ Intent pi;
+
+ try {
+ pi = _vpnSvc.prepare(getPackageName());
+ } catch (RemoteException e) {
+ Logger.logError("Exception while asking for VPN permission", e);
+ Toast t = Toast.makeText(getApplicationContext(),
+ getString(R.string.msg_vpn_service_error), Toast.LENGTH_LONG);
+
+ t.show();
+
+ String msgerr = getString(R.string.msg_vpn_error_manual_open).replace(
+ PLACEHOLDER_APPNAME, APP_COMMON_NAME);
+ Utils.showMessage(msgerr, getApplicationContext());
+
+ return -1;
+
+ }
+
+ if (pi == null) {
+ // no need to ask for permission
+ Logger.logDebug("No need for vpn permission.");
+ return 0;
+
+ } else if (!permissionAsked) {
+ // launch the intent to ask permission
+ Logger.logDebug("Need to ask for vpn permission. Starting intent..");
+ permissionAsked = true;
+ startActivityForResult(pi, requestCode);
+ return 1;
+
+ } else {
+ return 1;
+
+ }
+
+ }
+
+ private String getVpnNameIfAny(AccessPointInfo i) {
+
+ if (i == null) {
+ return null;
+ }
+
+ String profname = i.getVpnProfileName();
+ if (profname == null || profname.isEmpty()) {
+ return null;
+ } else {
+ return profname;
+ }
+
+ }
+
+ protected void beginConnectVpn(AccessPointInfo info) {
+
+ if (!isExternalAppInstalled()) {
+ return;
+ }
+
+ if (getVpnNameIfAny(info) == null) {
+ Logger.logDebug("No vpn profile set. Exiting beginConnectVpn()");
+ return;
+ }
+
+ _lastInfo = info;
+
+ if (_vpnSvc == null) {
+ bindVpnService(ACTION_CONNECT);
+ return;
+ }
+
+ // make sure we have permission to use the vpn service.
+ if (askPermissionIfNeeded(ActivityLauncher.RequestCode.VPN_PERMISSION_CONN) == 0) {
+ // no need for permission
+ Logger.logDebug("Going to endConnectVpn.");
+ endConnectVpn();
+ }
+
+ }
+
+ private void endConnectVpn() {
+
+ try {
+
+ if (_lastInfo == null) {
+ Logger.logError("Called endConnectVpn, but last AccessPointInfo is null.");
+ return;
+ }
+
+ String profname = getVpnNameIfAny(_lastInfo);
+
+ // check if profile exists
+ String profUuid = getUuidFromName(profname);
+ if (profUuid == null) {
+ // warn user that selected profile doesn't exist
+ Utils.showMessage(getString(R.string.msg_vpn_wrong_profile),
+ getApplicationContext());
+ return;
+ }
+
+ if (doStartVpn(profUuid)) {
+ Toast t = Toast.makeText(getApplicationContext(),
+ getString(R.string.msg_vpn_launched), Toast.LENGTH_LONG);
+ t.show();
+ } else {
+ Utils.showMessage(getString(R.string.msg_vpn_connect_error),
+ getApplicationContext());
+ }
+
+ } catch (Exception e) {
+ Logger.logError("Exception while endConnectVpn", e);
+
+ }
+
+ }
+
+ protected void beginGetExistingVpnProfiles() {
+
+ if (!isExternalAppInstalled()) {
+ return;
+ }
+
+ if (_vpnSvc == null) {
+ bindVpnService(ACTION_GET_PROFILES);
+ return;
+ }
+
+ // we make sure we have permission to use the vpn service.
+ if (askPermissionIfNeeded(ActivityLauncher.RequestCode.VPN_PERMISSION_LIST) == 0) {
+ // no need for permission
+ endGetExistingVpnProfiles();
+ }
+
+ }
+
+ private void endGetExistingVpnProfiles() {
+
+ try {
+ List<APIVpnProfile> list = _vpnSvc.getProfiles();
+
+ List<String> ret = new ArrayList<String>();
+ for (APIVpnProfile vp : list) {
+ ret.add(vp.mName);
+ }
+
+ onVpnProfilesAvailable(ret);
+
+ } catch (RemoteException e) {
+ Logger.logError("Exception while retrieving profiles from vpn service.", e);
+ }
+
+ }
+
+
+
+ protected boolean disconnectVpn() {
+
+ if (_vpnSvc == null) {
+ Logger.logDebug("Attempted to disconnect from VPN, but inner service is null");
+ return true;
+ }
+
+ try {
+ _vpnSvc.disconnect();
+ return true;
+ } catch (Exception e) {
+ Logger.logError("Exception while disconnecting from vpn.", e);
+ return false;
+ }
+
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ this.close();
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java b/app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java
index b9dab93..3c134d7 100644
--- a/app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java
+++ b/app/src/fil/libre/repwifiapp/activities/VpnSettingsActivity.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,37 +20,35 @@
package fil.libre.repwifiapp.activities;
-import java.util.List;
-import fil.libre.repwifiapp.ActivityLauncher;
-import fil.libre.repwifiapp.Commons;
-import fil.libre.repwifiapp.R;
-import fil.libre.repwifiapp.ActivityLauncher.RequestCode;
-import fil.libre.repwifiapp.helpers.AccessPointInfo;
-import fil.libre.repwifiapp.helpers.OpenVpnManager;
-import fil.libre.repwifiapp.helpers.Utils;
-import android.os.Bundle;
-import android.app.Activity;
import android.content.Intent;
+import android.os.Bundle;
+import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.NetworkManager;
+import java.util.List;
-public class VpnSettingsActivity extends Activity {
+public class VpnSettingsActivity extends VpnAndConnectionBoundActivity {
private AccessPointInfo currentNetwork;
private Spinner spinProfile;
private TextView summaryView;
-
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vpn_settings);
-
+
String title = getString(R.string.title_activity_vpn_settings);
-
+
Intent intent = getIntent();
if (!intent.hasExtra(ActivityLauncher.EXTRA_APINFO)) {
this.setResult(RESULT_CANCELED);
@@ -58,144 +56,129 @@ public class VpnSettingsActivity extends Activity {
return;
}
- this.currentNetwork = (AccessPointInfo) intent.getExtras().getSerializable(
- ActivityLauncher.EXTRA_APINFO);
- if (this.currentNetwork == null) {
- this.setResult(RESULT_CANCELED);
- this.finish();
- return;
- }
-
- this.currentNetwork = Commons.storage.getSavedNetwork(currentNetwork);
- this.spinProfile = (Spinner)findViewById(R.id.spin_vpn_profile);
- this.summaryView = (TextView)findViewById(R.id.lbl_vpn_settings);
- String summary = getString(R.string.summary_vpn_settings).replace(OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME);
+ this.spinProfile = (Spinner) findViewById(R.id.spin_vpn_profile);
+ this.summaryView = (TextView) findViewById(R.id.lbl_vpn_settings);
+ String summary = getString(R.string.summary_vpn_settings).replace(PLACEHOLDER_APPNAME,
+ APP_COMMON_NAME);
summaryView.setText(summary);
- title += " " + currentNetwork.getSsid();
- this.setTitle(title);
-
- if (!checkExternalApp()){
- toggleSettingsEnabled(false);
- } else {
- initVpnManager();
- }
+ this.currentNetwork = (AccessPointInfo) intent.getExtras().getParcelable(
+ ActivityLauncher.EXTRA_APINFO);
+
+ this.currentNetwork = NetworkManager.getSavedNetwork(currentNetwork);
+ if (this.currentNetwork != null) {
+ title += " " + this.currentNetwork.getSsid();
+ this.setTitle(title);
+ toggleSettingsEnabled(true);
+ }
}
-
@Override
- public void onActivityResult(int requestCode, int resultCode, Intent intent) {
-
- switch (requestCode) {
-
- case RequestCode.VPN_PERMISSION:
-
- if (resultCode != RESULT_OK) {
- toggleSettingsEnabled(false);
- Utils.logDebug("User rejected vpn permission.");
- String msg = getString(R.string.msg_vpn_no_permission).replace(
- OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME);
- Commons.showMessage(msg, this);
- return;
- }
-
- break;
-
- default:
-
- break;
-
+ public void onStart() {
+
+ super.onStart();
+ if (!checkExternalApp() || currentNetwork == null) {
+ toggleSettingsEnabled(false);
+ } else {
+ beginGetExistingVpnProfiles();
}
}
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
- private void initVpnManager(){
-
- try {
-
- Intent intentAllow = OpenVpnManager.askApiPermissionsGetIntent();
- if (intentAllow != null){
- startActivityForResult(intentAllow, ActivityLauncher.RequestCode.VPN_PERMISSION);
- }
-
- List<String> profiles = OpenVpnManager.getExistingProfiles();
- if (profiles.size() == 0){
- String msg = getString(R.string.msg_vpn_no_profile).replace(OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME);
- Commons.showMessage(msg, this);
- toggleSettingsEnabled(false);
- return;
- }
- Spinner spin = (Spinner)findViewById(R.id.spin_vpn_profile);
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_dropdown_item,profiles);
- adapter.insert("",0);
- spin.setAdapter(adapter);
- spin.setSelection(adapter.getPosition(currentNetwork.getVpnProfileName()));
-
- } catch (Exception e) {
- Utils.logError("Exception while creating openvpnmanager",e);
- Commons.showMessage(getString(R.string.msg_vpn_connect_error));
- toggleSettingsEnabled(false);
- }
-
- }
-
- private boolean checkExternalApp(){
-
- if (! OpenVpnManager.isExternalAppInstalled(this)){
- String msg = getString(R.string.text_vpn_package_missing).replace(OpenVpnManager.PLACEHOLDER_APPNAME, OpenVpnManager.APP_COMMON_NAME);
- Commons.showMessage(msg, this);
+ private boolean checkExternalApp() {
+
+ if (!isExternalAppInstalled()) {
+ String msg = getString(R.string.text_vpn_package_missing).replace(PLACEHOLDER_APPNAME,
+ APP_COMMON_NAME);
+ Utils.showMessage(msg, this);
toggleSettingsEnabled(false);
return false;
} else {
return true;
}
-
+
}
-
- private void toggleSettingsEnabled(boolean enabled){
-
+
+ private void toggleSettingsEnabled(boolean enabled) {
+
spinProfile.setEnabled(enabled);
-
- Button b = (Button)findViewById(R.id.btn_save_vpn_settings);
+
+ Button b = (Button) findViewById(R.id.btn_save_vpn_settings);
b.setEnabled(enabled);
-
+
}
-
- public void btnSaveClick(View v){
-
- String vpnProf = (String)spinProfile.getSelectedItem();
-
- /*if (! vpnProf.isEmpty()){
- // check if profile name exists
- if( OpenVpnManager.getUuidFromName(vpnProf) == null){
- Commons.showMessage(getString(R.string.msg_vpn_wrong_profile), this);
- return;
- }
-
- }*/
-
+
+ public void btnSaveClick(View v) {
+
+ String vpnProf = (String) spinProfile.getSelectedItem();
+
// save profile
currentNetwork.setVpnProfileName(vpnProf);
- Commons.storage.save(currentNetwork);
-
+ NetworkManager.save(currentNetwork);
+
terminate();
-
+
}
-
- public void btnBackClick(View v){
+
+ public void btnBackClick(View v) {
terminate();
}
-
- private void terminate(){
+
+ private void terminate() {
finish();
}
+
+ @Override
+ protected void onVpnProfilesAvailable(List<String> profiles) {
+
+ if (profiles.size() == 0) {
+ String msg = getString(R.string.msg_vpn_no_profile).replace(PLACEHOLDER_APPNAME,
+ APP_COMMON_NAME);
+ Utils.showMessage(msg, this);
+ toggleSettingsEnabled(false);
+ return;
+ }
+ Spinner spin = (Spinner) findViewById(R.id.spin_vpn_profile);
+
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_spinner_dropdown_item, profiles){
+ @Override
+ public View getView(int position, View convertView, android.view.ViewGroup parent)
+ {
+ return getStyledView(super.getView(position, convertView,parent));
+ }
+
+ private View getStyledView(View view)
+ {
+ TextView textView = (TextView)view.findViewById(android.R.id.text1);
+ textView.setGravity(Gravity.CENTER);
+ textView.setTextColor(R.color.ThemeLight);
+ return view;
+ }
+
+ };
+ adapter.insert(AccessPointInfo.DUMMY_VPN_PROFILE, 0);
+ spin.setAdapter(adapter);
+
+ String pn = currentNetwork.getVpnProfileName();
+ int pos = adapter.getPosition(pn);
+ if (pos < 0) {
+ spin.setSelection(adapter.getPosition(AccessPointInfo.DUMMY_VPN_PROFILE));
+ } else {
+ spin.setSelection(pos);
+ }
+
+ }
+ @Override
+ protected void onVpnPermissionDenied(){
+ }
+
+
}
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/ConnectivityManagerProxy.java b/app/src/fil/libre/repwifiapp/fwproxies/ConnectivityManagerProxy.java
new file mode 100644
index 0000000..f2e7de7
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/ConnectivityManagerProxy.java
@@ -0,0 +1,98 @@
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+//
+// This file is derivative work, inspired by the original class definition:
+// "android.net.ConnectivityManager.java" as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package fil.libre.repwifiapp.fwproxies;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Messenger;
+
+public class ConnectivityManagerProxy extends FrameworkProxy {
+
+ private Context currentContext;
+
+ public ConnectivityManagerProxy(Context context) {
+ currentContext = context;
+ init();
+ }
+
+ @Override
+ protected String getInnerClassName() {
+ return ConnectivityManager.class.getCanonicalName();
+ }
+
+
+ public int registerNetworkAgent(Messenger msgr, NetworkInfoProxy ni,
+ LinkPropertiesProxy lp, NetworkCapabilitiesProxy nc, int score){
+
+ Class<?>[] types = getTypesArray(Messenger.class,
+ NetworkInfo.class,
+ getClassFromName(LinkPropertiesProxy.getStaticInnerClassName()),
+ getClassFromName(NetworkCapabilitiesProxy.getStaticInnerClassName()),
+ int.class,
+ getClassFromName("android.net.NetworkMisc"));
+
+ return (Integer)invokeMethodGetResult("registerNetworkAgent",types, msgr, ni.getNetworkInfo(), lp, nc, score, null);
+
+ }
+
+/* public boolean isWifiConnected(){
+
+ init();
+ ConnectivityManager cm = (ConnectivityManager)inner;
+
+ NetworkInfo i = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ if (i == null){
+ return false;
+ } else {
+ return i.isConnected();
+ }
+
+ }*/
+
+ private void init(){
+
+ if (this.inner == null){
+ this.inner = currentContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ }
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/FrameworkProxy.java b/app/src/fil/libre/repwifiapp/fwproxies/FrameworkProxy.java
new file mode 100644
index 0000000..a468a1c
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/FrameworkProxy.java
@@ -0,0 +1,126 @@
+//
+// Copyright 2017, 2018 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.fwproxies;
+
+import fil.libre.repwifiapp.helpers.Logger;
+import java.lang.reflect.Constructor;
+
+/**
+ * Provides a base class for creating "proxy" classes that wrap up classes from
+ * the Android Application Framework via reflection, exposing them outside the
+ * framework itself.
+ */
+public abstract class FrameworkProxy {
+
+ protected Object inner;
+
+ protected abstract String getInnerClassName();
+
+ protected static String getStaticInnerClassName() {
+ return "Object";
+ }
+
+ protected static Class<?> getClassFromName(String className) {
+
+ try {
+ return Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ Logger.logError(null, e);
+ return null;
+ }
+
+ }
+
+ protected Class<?> getInnerClass() {
+ return getClassFromName(getInnerClassName());
+ }
+
+ protected Class<?>[] getTypesArray(Class<?>... args) {
+ Class<?>[] types = new Class<?>[args.length];
+ for (int i = 0; i < args.length; i++) {
+ types[i] = args[i];
+ }
+ return types;
+ }
+
+ protected Object createInnerObject(Class<?> argType, Object arg) {
+ return createInnerObject(getTypesArray(argType), arg);
+ }
+
+ protected Object createInnerObject(Class<?>[] argumentTypes, Object... args) {
+ try {
+ Class<?> cls = getClassFromName(getInnerClassName());
+ Constructor<?> c = cls.getConstructor(argumentTypes);
+ this.inner = c.newInstance(getRealArgs(args));
+ return this.inner;
+ } catch (Exception e) {
+ Logger.logError("Exception while creating inner object via reflection.", e);
+ return null;
+ }
+ }
+
+ protected Object invokeMethodGetResult(String methodName, Class<?> argumentType, Object arg) {
+ return invokeMethodGetResult(methodName, getTypesArray(argumentType), arg);
+ }
+
+ protected Object invokeMethodGetResult(String methodName, Class<?>[] argumentTypes,
+ Object... args) {
+ try {
+ return getClassFromName(getInnerClassName()).getMethod(methodName, argumentTypes)
+ .invoke(inner, getRealArgs(args));
+ } catch (Exception e) {
+ Logger.logError("Exception while invoking method via reflection.", e);
+ return null;
+ }
+ }
+
+ protected void invokeMethod(String methodName, Class<?> argumentType, Object arg) {
+ invokeMethod(methodName, getTypesArray(argumentType), arg);
+ }
+
+ protected void invokeMethod(String methodName, Class<?>[] argumentTypes, Object... args) {
+ try {
+ getClassFromName(getInnerClassName()).getMethod(methodName, argumentTypes).invoke(
+ inner, getRealArgs(args));
+ } catch (Exception e) {
+ Logger.logError("Exception while invoking method via reflection.", e);
+ }
+ }
+
+ private Object[] getRealArgs(Object[] args) {
+
+ if (args == null || args.length == 0) {
+ return new Object[] {};
+ }
+
+ // if the object is just a proxy, use the inner object as an argument to
+ // the call.
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] instanceof FrameworkProxy) {
+ args[i] = ((FrameworkProxy) args[i]).inner;
+ }
+ }
+
+ return args;
+
+ }
+
+} \ No newline at end of file
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/LinkAddressProxy.java b/app/src/fil/libre/repwifiapp/fwproxies/LinkAddressProxy.java
new file mode 100644
index 0000000..5fcd211
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/LinkAddressProxy.java
@@ -0,0 +1,61 @@
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+//
+// This file is derivative work, inspired by the original class definition:
+// "android.net.LinkAddress.java" as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fil.libre.repwifiapp.fwproxies;
+
+import java.net.InetAddress;
+
+
+public class LinkAddressProxy extends FrameworkProxy {
+
+ @Override
+ protected String getInnerClassName() {
+ return "android.net.LinkAddress";
+ }
+
+ public LinkAddressProxy(String ipAndMask){
+ createInnerObject(String.class, ipAndMask);
+ }
+
+ public LinkAddressProxy(InetAddress address, int mask){
+ createInnerObject(getTypesArray(InetAddress.class, int.class), address, mask);
+ }
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/LinkPropertiesProxy.java b/app/src/fil/libre/repwifiapp/fwproxies/LinkPropertiesProxy.java
new file mode 100644
index 0000000..4bfeeaa
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/LinkPropertiesProxy.java
@@ -0,0 +1,90 @@
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+//
+// This file is derivative work, inspired by the original class definition:
+// "android.net.LinkProperties.java" as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fil.libre.repwifiapp.fwproxies;
+
+import java.net.InetAddress;
+
+
+public class LinkPropertiesProxy extends FrameworkProxy{
+
+ @Override
+ protected String getInnerClassName(){
+ return "android.net.LinkProperties";
+ }
+
+ public LinkPropertiesProxy(){
+ createInnerObject(null);
+ }
+
+ public LinkPropertiesProxy(LinkPropertiesProxy lp){
+ createInnerObject(getInnerClass(), lp.inner);
+ }
+
+ public void setInterfaceName(String iface) {
+ invokeMethod("setInterfaceName", String.class , iface);
+ }
+
+ public boolean addRoute(RouteInfoProxy route) {
+ if (route == null){
+ return false;
+ }
+ return (Boolean)invokeMethodGetResult("addRoute", route.getInnerClass(), route);
+ }
+
+ public boolean addLinkAddress(LinkAddressProxy address) {
+ if (address == null){
+ return false;
+ }
+ return (Boolean)invokeMethodGetResult("addLinkAddress",address.getInnerClass(), address);
+ }
+
+ public boolean addDnsServer(InetAddress dnsServer) {
+ if (dnsServer == null){
+ return false;
+ }
+ return (Boolean)invokeMethodGetResult("addDnsServer", InetAddress.class, dnsServer);
+ }
+
+ protected static String getStaticInnerClassName(){
+ return "android.net.LinkProperties";
+ }
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/NetworkCapabilitiesProxy.java b/app/src/fil/libre/repwifiapp/fwproxies/NetworkCapabilitiesProxy.java
new file mode 100644
index 0000000..f66bebd
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/NetworkCapabilitiesProxy.java
@@ -0,0 +1,90 @@
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+//
+// This file is derivative work, inspired by the original class definition:
+// "android.net.NetworkCapabilities.java" as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fil.libre.repwifiapp.fwproxies;
+
+
+public class NetworkCapabilitiesProxy extends FrameworkProxy{
+
+ public static final int NET_CAPABILITY_MMS = 0;
+ public static final int NET_CAPABILITY_SUPL = 1;
+ public static final int NET_CAPABILITY_DUN = 2;
+ public static final int NET_CAPABILITY_FOTA = 3;
+ public static final int NET_CAPABILITY_IMS = 4;
+ public static final int NET_CAPABILITY_CBS = 5;
+ public static final int NET_CAPABILITY_WIFI_P2P = 6;
+ public static final int NET_CAPABILITY_IA = 7;
+ public static final int NET_CAPABILITY_RCS = 8;
+ public static final int NET_CAPABILITY_XCAP = 9;
+ public static final int NET_CAPABILITY_EIMS = 10;
+ public static final int NET_CAPABILITY_NOT_METERED = 11;
+ public static final int NET_CAPABILITY_INTERNET = 12;
+ public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
+ public static final int NET_CAPABILITY_TRUSTED = 14;
+ public static final int NET_CAPABILITY_NOT_VPN = 15;
+ public static final int NET_CAPABILITY_VALIDATED = 16;
+ public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
+
+ public NetworkCapabilitiesProxy(){
+ createInnerObject(null);
+ }
+
+ public NetworkCapabilitiesProxy(NetworkCapabilitiesProxy nc){
+ createInnerObject(getInnerClass(), nc.inner);
+ }
+
+ public void addCapability(int capability) {
+ invokeMethod("addCapability", new Class<?>[]{int.class}, capability);
+ }
+
+ public void removeCapability(int capability) {
+ invokeMethod("removeCapability", new Class<?>[]{int.class}, capability);
+ }
+
+ @Override
+ protected String getInnerClassName() {
+ return "android.net.NetworkCapabilities";
+ }
+
+ protected static String getStaticInnerClassName(){
+ return "android.net.NetworkCapabilities";
+ }
+
+}
+
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/NetworkInfoProxy.java b/app/src/fil/libre/repwifiapp/fwproxies/NetworkInfoProxy.java
new file mode 100644
index 0000000..0537451
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/NetworkInfoProxy.java
@@ -0,0 +1,102 @@
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+//
+// This file is derivative work of the original class definition:
+// "android.net.NetworkInfo" as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fil.libre.repwifiapp.fwproxies;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+
+public class NetworkInfoProxy extends FrameworkProxy {
+
+ @Override
+ protected String getInnerClassName() {
+ return "android.net.NetworkInfo";
+ }
+
+ public NetworkInfoProxy(int type, int subtype, String typeName, String subtypeName){
+ createInnerObject(new Class<?>[]{int.class, int.class, String.class, String.class}, type, subtype, typeName, subtypeName);
+ }
+
+ public NetworkInfoProxy(NetworkInfo source){
+ createInnerObject(new Class<?>[]{NetworkInfo.class}, source);
+ }
+
+ public static NetworkInfoProxy getForWifi(){
+ return new NetworkInfoProxy(ConnectivityManager.TYPE_WIFI,0, "WIFI", "");
+ }
+
+ public NetworkInfo getNetworkInfo(){
+ if (inner == null){
+ return null;
+ }
+ return (NetworkInfo)inner;
+ }
+
+ public void setType(int type) {
+ invokeMethod("setType", new Class<?>[]{int.class}, type);
+ }
+
+ public void setSubtype(int subtype, String subtypeName) {
+ invokeMethod("setSubType", new Class<?>[]{int.class, String.class}, subtype, subtypeName);
+ }
+
+ public void setIsAvailable(boolean isAvailable) {
+ invokeMethod("setIsAvailable", new Class<?>[]{boolean.class}, isAvailable);
+ }
+
+ public void setFailover(boolean isFailover) {
+ invokeMethod("setFailover", new Class<?>[]{boolean.class}, isFailover);
+ }
+
+
+ public void setRoaming(boolean isRoaming) {
+ invokeMethod("setRoaming", new Class<?>[]{boolean.class}, isRoaming);
+ }
+
+ public void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
+ invokeMethod("setDetailedState", new Class<?>[]{DetailedState.class, String.class, String.class}, detailedState, reason, extraInfo);
+ }
+
+ public void setExtraInfo(String extraInfo) {
+ invokeMethod("setExtraInfo", new Class<?>[]{String.class}, extraInfo);
+ }
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java b/app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java
new file mode 100644
index 0000000..bab5c5d
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java
@@ -0,0 +1,581 @@
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+//
+// This file is derivative work, inspired by the original class definition:
+// "com.android.server.wifi.WifiStateMachine$WifiNetworkAgent.java"
+// as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fil.libre.repwifiapp.fwproxies;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.util.Log;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class RepWifiNetworkAgent extends Handler {
+
+ public final int netId;
+
+ private Messenger myMessenger = null;
+
+ private volatile AsyncChannelProxy mAsyncChannel;
+ private final String LOG_TAG;
+ private static final boolean DBG = true;
+ private static final boolean VDBG = true;
+ private final Context mContext;
+ private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
+ private volatile long mLastBwRefreshTime = 0;
+ private static final long BW_REFRESH_MIN_WIN_MS = 500;
+ private boolean mPollLceScheduled = false;
+ private AtomicBoolean mPollLcePending = new AtomicBoolean(false);
+
+ /* as in com.android.internal.util.Protocol.BASE_NETWORK_AGENT; */
+ private static final int BASE = 0x00081000;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform it of
+ * suspected connectivity problems on its network. The NetworkAgent
+ * should take steps to verify and correct connectivity.
+ */
+ public static final int CMD_SUSPECT_BAD = BASE;
+
+ /**
+ * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
+ * ConnectivityService to pass the current NetworkInfo (connection state).
+ * Sent when the NetworkInfo changes, mainly due to change of state.
+ * obj = NetworkInfo
+ */
+ public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * NetworkCapabilties.
+ * obj = NetworkCapabilities
+ */
+ public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * NetworkProperties.
+ * obj = NetworkProperties
+ */
+ public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
+
+ public static final int WIFI_BASE_SCORE = 60;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * network score.
+ * obj = network score Integer
+ */
+ public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to add new UID ranges
+ * to be forced into this Network. For VPNs only.
+ * obj = UidRange[] to forward
+ */
+ public static final int EVENT_UID_RANGES_ADDED = BASE + 5;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to remove UID ranges
+ * from being forced into this Network. For VPNs only.
+ * obj = UidRange[] to stop forwarding
+ */
+ public static final int EVENT_UID_RANGES_REMOVED = BASE + 6;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform the agent of
+ * the
+ * networks status - whether we could use the network or could not, due to
+ * either a bad network configuration (no internet link) or captive portal.
+ *
+ * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK}
+ */
+ public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
+
+ public static final int VALID_NETWORK = 1;
+ public static final int INVALID_NETWORK = 2;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to indicate this network
+ * was
+ * explicitly selected. This should be sent before the NetworkInfo is marked
+ * CONNECTED so it can be given special treatment at that time.
+ *
+ * obj = boolean indicating whether to use this network even if unvalidated
+ */
+ public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform the agent of
+ * whether the network should in the future be used even if not validated.
+ * This decision is made by the user, but it is the network transport's
+ * responsibility to remember it.
+ *
+ * arg1 = 1 if true, 0 if false
+ */
+ public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform the agent to
+ * pull
+ * the underlying network connection for updated bandwidth information.
+ */
+ public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to request that the
+ * specified packet be sent
+ * periodically on the given interval.
+ *
+ * arg1 = the slot number of the keepalive to start
+ * arg2 = interval in seconds
+ * obj = KeepalivePacketData object describing the data to be sent
+ *
+ * Also used internally by ConnectivityService / KeepaliveTracker, with
+ * different semantics.
+ */
+ public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11;
+
+ /**
+ * Requests that the specified keepalive packet be stopped.
+ *
+ * arg1 = slot number of the keepalive to stop.
+ *
+ * Also used internally by ConnectivityService / KeepaliveTracker, with
+ * different semantics.
+ */
+ public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to provide status on a
+ * packet keepalive
+ * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or
+ * an asynchronous
+ * error notification.
+ *
+ * This is also sent by KeepaliveTracker to the app's
+ * ConnectivityManager.PacketKeepalive to
+ * so that the app's PacketKeepaliveCallback methods can be called.
+ *
+ * arg1 = slot number of the keepalive
+ * arg2 = error code
+ */
+ public static final int EVENT_PACKET_KEEPALIVE = BASE + 13;
+
+ /**
+ * Sent by ConnectivityService to inform this network transport of signal
+ * strength thresholds
+ * that when crossed should trigger a system wakeup and a
+ * NetworkCapabilities update.
+ *
+ * obj = int[] describing signal strength thresholds.
+ */
+ public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
+
+ /**
+ * Sent by ConnectivityService to the NeworkAgent to inform the agent to
+ * avoid
+ * automatically reconnecting to this network (e.g. via autojoin). Happens
+ * when user selects "No" option on the "Stay connected?" dialog box.
+ */
+ public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
+
+ public RepWifiNetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
+ NetworkCapabilitiesProxy nc, LinkPropertiesProxy lp, int score) {
+
+ super(looper);
+
+ LOG_TAG = logTag;
+ mContext = context;
+ if (ni == null || nc == null || lp == null) {
+ throw new IllegalArgumentException();
+ }
+
+ if (VDBG)
+ log("Registering NetworkAgent");
+
+ ConnectivityManagerProxy cm = new ConnectivityManagerProxy(mContext);
+
+ myMessenger = new Messenger(this);
+ netId = cm.registerNetworkAgent(myMessenger, new NetworkInfoProxy(ni),
+ new LinkPropertiesProxy(lp), new NetworkCapabilitiesProxy(nc), score);
+
+ }
+
+ public boolean isChannellConnected() {
+ return (mAsyncChannel != null);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+
+ switch (msg.what) {
+ case AsyncChannelProxy.CMD_CHANNEL_FULL_CONNECTION: {
+ if (mAsyncChannel != null) {
+ log("Received new connection while already connected!");
+ } else {
+ if (VDBG)
+ log("NetworkAgent fully connected");
+ AsyncChannelProxy ac = new AsyncChannelProxy();
+ ac.connected(null, this, msg.replyTo);
+ ac.replyToMessage(msg, AsyncChannelProxy.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannelProxy.STATUS_SUCCESSFUL);
+ synchronized (mPreConnectedQueue) {
+ mAsyncChannel = ac;
+ for (Message m : mPreConnectedQueue) {
+ ac.sendMessage(m);
+ }
+ mPreConnectedQueue.clear();
+ }
+ }
+ break;
+ }
+ case AsyncChannelProxy.CMD_CHANNEL_DISCONNECT: {
+ if (VDBG)
+ log("CMD_CHANNEL_DISCONNECT");
+ if (mAsyncChannel != null)
+ mAsyncChannel.disconnect();
+ break;
+ }
+ case AsyncChannelProxy.CMD_CHANNEL_DISCONNECTED: {
+ if (DBG)
+ log("NetworkAgent channel lost");
+ // let the client know CS is done with us.
+
+ synchronized (mPreConnectedQueue) {
+ mAsyncChannel = null;
+ }
+ break;
+ }
+ case CMD_SUSPECT_BAD: {
+ log("Unhandled Message " + msg);
+ break;
+ }
+ case CMD_REQUEST_BANDWIDTH_UPDATE: {
+ long currentTimeMs = System.currentTimeMillis();
+ if (VDBG) {
+ log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
+ }
+ if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
+ mPollLceScheduled = false;
+ if (mPollLcePending.getAndSet(true) == false) {
+
+ shouldCallUninimplementedMethod("pollLceData()");
+
+ }
+ } else {
+ // deliver the request at a later time rather than discard it
+ // completely.
+ if (!mPollLceScheduled) {
+ long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS - currentTimeMs + 1;
+ mPollLceScheduled = sendEmptyMessageDelayed(CMD_REQUEST_BANDWIDTH_UPDATE,
+ waitTime);
+ }
+ }
+ break;
+ }
+ case CMD_REPORT_NETWORK_STATUS: {
+ if (VDBG) {
+ log("CMD_REPORT_NETWORK_STATUS("
+ + (msg.arg1 == VALID_NETWORK ? "VALID)" : "INVALID)"));
+ }
+ shouldCallUninimplementedMethod("shounetworkStatus(msg.arg1)");
+ break;
+ }
+ case CMD_SAVE_ACCEPT_UNVALIDATED: {
+ shouldCallUninimplementedMethod("saveAcceptUnvalidated(msg.arg1 != 0)");
+
+ break;
+ }
+ case CMD_START_PACKET_KEEPALIVE: {
+ shouldCallUninimplementedMethod("startPacketKeepalive(msg)");
+ break;
+ }
+ case CMD_STOP_PACKET_KEEPALIVE: {
+ shouldCallUninimplementedMethod("stopPacketKeepalive(msg)");
+
+ break;
+ }
+
+ case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
+ ArrayList<Integer> thresholds = ((Bundle) msg.obj).getIntegerArrayList("thresholds");
+ int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0];
+ for (int i = 0; i < intThresholds.length; i++) {
+ intThresholds[i] = thresholds.get(i);
+ }
+ shouldCallUninimplementedMethod("setSignalStrengthThresholds(intThresholds)");
+ break;
+ }
+ case CMD_PREVENT_AUTOMATIC_RECONNECT: {
+ shouldCallUninimplementedMethod("preventAutomaticReconnect()");
+ break;
+ }
+ default: {
+ String rep = "";
+ if (msg.replyTo != null) {
+ rep = msg.replyTo.toString();
+ }
+ log("Received unhandled message: what = " + msg.what + " replyTo: " + rep);
+ }
+ }
+ }
+
+ private void queueOrSendMessage(int what, Object obj) {
+ queueOrSendMessage(what, 0, 0, obj);
+ }
+
+ /*
+ * private void queueOrSendMessage(int what, int arg1, int arg2) {
+ * queueOrSendMessage(what, arg1, arg2, null);
+ * }
+ */
+
+ private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) {
+ if (VDBG)
+ log("Send or queue message; what=" + what);
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = arg1;
+ msg.arg2 = arg2;
+ msg.obj = obj;
+ msg.replyTo = this.myMessenger;
+
+ queueOrSendMessage(msg);
+ }
+
+ private void queueOrSendMessage(Message msg) {
+ synchronized (mPreConnectedQueue) {
+ if (mAsyncChannel != null) {
+ if (VDBG)
+ log("Actually sending message " + msg);
+ mAsyncChannel.sendMessage(msg);
+ } else {
+ mPreConnectedQueue.add(msg);
+ }
+ }
+ }
+
+ /**
+ * Called by the bearer code when it has new LinkProperties data.
+ */
+ public void sendLinkProperties(LinkPropertiesProxy linkProperties) {
+ queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED,
+ new LinkPropertiesProxy(linkProperties).inner);
+ }
+
+ /**
+ * Called by the bearer code when it has new NetworkInfo data.
+ */
+ public void sendNetworkInfo(NetworkInfo networkInfo) {
+ queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED,
+ new NetworkInfoProxy(networkInfo).getNetworkInfo());
+ }
+
+ /**
+ * Called by the bearer code when it has new NetworkCapabilities data.
+ */
+ public void sendNetworkCapabilities(NetworkCapabilitiesProxy networkCapabilities) {
+ mPollLcePending.set(false);
+ mLastBwRefreshTime = System.currentTimeMillis();
+ queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, new NetworkCapabilitiesProxy(
+ networkCapabilities).inner);
+ }
+
+ /**
+ * Called by the bearer code when it has a new score for this network.
+ */
+ public void sendNetworkScore(int score) {
+ if (score < 0) {
+ throw new IllegalArgumentException("Score must be >= 0");
+ }
+ queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, Integer.valueOf(score));
+ }
+
+ protected void log(String s) {
+ Log.d(LOG_TAG, "NetworkAgent: " + s);
+ }
+
+ private void shouldCallUninimplementedMethod(String methodName) {
+ String msg = "[WRN] Should be calling " + methodName
+ + " but the method is not implemented by the proxy..";
+ Log.w(LOG_TAG, msg);
+ }
+
+ /*
+ * A proxy for package com.android.internal.util.AsyncChannel;
+ * Mererly replicates constants and functions needed by the NetworkAgent to
+ * communicate with the other side of the Handler
+ */
+ private static class AsyncChannelProxy extends FrameworkProxy {
+
+ // as in com.android.internal.util.Protocol.BASE_SYSTEM_ASYNC_CHANNEL;
+ private static final int BASE = 0x00011000;
+
+ /** Successful status always 0, !0 is an unsuccessful status */
+ public static final int STATUS_SUCCESSFUL = 0;
+
+ /**
+ * Command typically sent when after receiving the
+ * CMD_CHANNEL_HALF_CONNECTED.
+ * This is used to initiate a long term connection with the destination
+ * and
+ * typically the destination will reply with
+ * CMD_CHANNEL_FULLY_CONNECTED.
+ *
+ * msg.replyTo = srcMessenger.
+ */
+ public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1;
+
+ /**
+ * Command typically sent after the destination receives a
+ * CMD_CHANNEL_FULL_CONNECTION.
+ * This signifies the acceptance or rejection of the channel by the
+ * sender.
+ *
+ * msg.arg1 == 0 : Accept connection
+ * : All other values signify the destination rejected the connection
+ * and {@link AsyncChannel#disconnect} would typically be called.
+ */
+ public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2;
+
+ /**
+ * Command sent when one side or the other wishes to disconnect. The
+ * sender
+ * may or may not be able to receive a reply depending upon the protocol
+ * and
+ * the state of the connection. The receiver should call
+ * {@link AsyncChannel#disconnect} to close its side of the channel and
+ * it will receive a CMD_CHANNEL_DISCONNECTED
+ * when the channel is closed.
+ *
+ * msg.replyTo = messenger that is disconnecting
+ */
+ public static final int CMD_CHANNEL_DISCONNECT = BASE + 3;
+
+ /**
+ * Command sent when the channel becomes disconnected. This is sent when
+ * the
+ * channel is forcibly disconnected by the system or as a reply to
+ * CMD_CHANNEL_DISCONNECT.
+ *
+ * msg.arg1 == 0 : STATUS_SUCCESSFUL
+ * 1 : STATUS_BINDING_UNSUCCESSFUL
+ * 2 : STATUS_SEND_UNSUCCESSFUL
+ * : All other values signify failure and the channel state is
+ * indeterminate
+ * msg.obj == the AsyncChannel
+ * msg.replyTo = messenger disconnecting or null if it was never
+ * connected.
+ */
+ public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
+
+ /*
+ * Following is a block of unused system constants, kept here for future
+ * reference
+ *//**
+ * Command sent when the channel is half connected. Half connected
+ * means that the channel can be used to send commends to the
+ * destination
+ * but the destination is unaware that the channel exists. The first
+ * command sent to the destination is typically
+ * CMD_CHANNEL_FULL_CONNECTION if
+ * it is desired to establish a long term connection, but any command
+ * maybe
+ * sent.
+ *
+ * msg.arg1 == 0 : STATUS_SUCCESSFUL
+ * 1 : STATUS_BINDING_UNSUCCESSFUL
+ * msg.obj == the AsyncChannel
+ * msg.replyTo == dstMessenger if successful
+ */
+ /*
+ * public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0;
+ *
+ * private static final int CMD_TO_STRING_COUNT =
+ * CMD_CHANNEL_DISCONNECTED - BASE + 1;
+ *//** Error attempting to bind on a connect */
+ /*
+ * public static final int STATUS_BINDING_UNSUCCESSFUL = 1;
+ *//** Error attempting to send a message */
+ /*
+ * public static final int STATUS_SEND_UNSUCCESSFUL = 2;
+ *//** CMD_FULLY_CONNECTED refused because a connection already exists */
+ /*
+ * public static final int
+ * STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
+ *//** Error indicating abnormal termination of destination messenger */
+ /*
+ * public static final int STATUS_REMOTE_DISCONNECTION = 4;
+ */
+
+ public AsyncChannelProxy() {
+ createInnerObject(null);
+ }
+
+ @Override
+ protected String getInnerClassName() {
+ return "com.android.internal.util.AsyncChannel";
+ }
+
+ public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+ invokeMethod("connected", getTypesArray(Context.class, Handler.class, Messenger.class),
+ srcContext, srcHandler, dstMessenger);
+ }
+
+ public void disconnect() {
+ invokeMethod("disconnect", null);
+ }
+
+ public void sendMessage(Message msg) {
+ invokeMethod("sendMessage", Message.class, msg);
+ }
+
+ public void replyToMessage(Message srcMsg, int what, int arg1) {
+ invokeMethod("replyToMessage", getTypesArray(Message.class, int.class, int.class),
+ srcMsg, what, arg1);
+ }
+
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/RouteInfoProxy.java b/app/src/fil/libre/repwifiapp/fwproxies/RouteInfoProxy.java
new file mode 100644
index 0000000..ad2e9f6
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/RouteInfoProxy.java
@@ -0,0 +1,59 @@
+//
+// Copyright 2017, 2018 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/>.
+//
+// ********************************************************************
+//
+// This file is derivative work, inspired by the original class definition:
+// "android.net.RouteInfo.java" as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fil.libre.repwifiapp.fwproxies;
+
+import java.net.InetAddress;
+
+public class RouteInfoProxy extends FrameworkProxy{
+
+ @Override
+ protected String getInnerClassName() {
+ return "android.net.RouteInfo";
+ }
+
+ public RouteInfoProxy(InetAddress gateway, String ifaceName) {
+ Class<?>[] sig = new Class<?>[]{getClassFromName("android.net.IpPrefix"),
+ InetAddress.class, String.class};
+ createInnerObject(sig, null, gateway, ifaceName);
+ }
+
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java b/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java
deleted file mode 100644
index e271dbe..0000000
--- a/app/src/fil/libre/repwifiapp/helpers/ConnectionStatus.java
+++ /dev/null
@@ -1,109 +0,0 @@
-//
-// 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;
-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;
- }
- }
-
- public AccessPointInfo getNetworkDetails(){
- AccessPointInfo i = new AccessPointInfo(SSID, BSSID, "","", "");
- return Commons.storage.getSavedNetwork(i);
- }
-
-}
diff --git a/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java b/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java
deleted file mode 100644
index 3eff6c8..0000000
--- a/app/src/fil/libre/repwifiapp/helpers/Engine6p0.java
+++ /dev/null
@@ -1,271 +0,0 @@
-//
-// 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 org.apache.http.conn.util.InetAddressUtils;
-import fil.libre.repwifiapp.Commons;
-
-public class Engine6p0 extends Engine {
-
- @Override
- public boolean connect(AccessPointInfo info) {
-
- WpaSupplicant.kill();
-
- 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 (!WpaSupplicant.start()) {
- Utils.logDebug("Unable to run wpa start");
- return false;
- }
-
- // create new network and get network id
- String netID = WpaCli.createNetworkGetId();
- if (netID == null) {
- Utils.logDebug("Unable to fetch network id");
- return false;
- }
-
- // set network SSID
- if (!WpaCli.setNetworkSSID(info.getSsid(), netID)) {
- Utils.logDebug("Failed to set network ssid");
- return false;
- }
-
- if (info.isHidden() && !WpaCli.setNetworkScanSSID(netID)) {
- Utils.logDebug("Failed to set scan_ssid 1 for hidden network.");
- return false;
- }
-
- // set password (if any)
- if (!WpaCli.setNetworkPSK(info, netID)) {
- Utils.logDebug("Failed to set network psk");
- return false;
- }
-
- // select the network we just created
- if (!WpaCli.selectNetwork(netID)) {
- Utils.logDebug("Unable to wpa_cli select network");
- return false;
- }
-
- // enable the newtork
- if (!WpaCli.enableNetwork(netID)) {
- Utils.logDebug("Unable to wpa_cli enable_newtork");
- return false;
- }
-
- // kill previous dhchcd instances
- if (!RootCommand.executeRootCmd("killall -SIGINT dhcpcd")){
- Utils.logError("Unable to kill previous instances of dhcpcd");
- }
-
- // get DHCP
- Utils.logDebug("Attempt to run dhcpcd..");
- if (!runDhcpcd(info.getDhcpConfiguration())) {
- Utils.logDebug("Failed to run dhcpcd");
- return false;
- }
-
- // try to fetch gateway
- String gw = getGateWayTimeout(Commons.WAIT_FOR_GATEWAY);
- if (gw == null || !InetAddressUtils.isIPv4Address(gw)) {
- // failed to get gateway
- Utils.logDebug("Failed to get gateway");
- return false;
- }
-
- if (!RootCommand.executeRootCmd("ndc network create 1")) {
- Utils.logDebug("Failed to wpa_cli network create 1 ");
- return false;
- }
-
- if (!RootCommand.executeRootCmd("ndc network interface add 1 "
- + WpaSupplicant.INTERFACE_NAME)) {
- Utils.logDebug("Failed to add interface.");
- return false;
- }
-
- // set route to gateway for all traffic
- if (!RootCommand.executeRootCmd("ndc network route add 1 " + WpaSupplicant.INTERFACE_NAME
- + " 0.0.0.0/0 " + gw)) {
- Utils.logDebug("Failed to add route to gateway");
- return false;
- }
-
- if (!setDns(Commons.getDnss(), gw)) {
- Utils.logDebug("Failed to set DNS");
- return false;
- }
-
- // use network
- if (!RootCommand.executeRootCmd("ndc network default set 1")) {
- Utils.logDebug("Failed to set network as default");
- return false;
- }
-
- return true;
-
- }
-
- private boolean destroyNetwork() {
- // needs root (tested)
- return RootCommand.executeRootCmd("ndc network destroy 1");
- }
-
- private boolean setDns(String[] dnss, String gateway) {
-
- if (dnss == null || dnss.length == 0) {
- // the DNS setting has been left blank
- // try to use the gateway as dns
-
- if (gateway == null || gateway.length() == 0) {
- // no possible DNS.
- return false;
- }
-
- dnss = new String[] { gateway, gateway };
-
- }
-
- if (!InetAddressUtils.isIPv4Address(dnss[0])) {
- // invalid ip can't proceed.
- return false;
- }
-
- String cmd = "ndc resolver setnetdns 1 " + dnss[0];
-
- if (dnss.length > 1 && InetAddressUtils.isIPv4Address(dnss[1])) {
- cmd += " " + dnss[1];
- } else {
- cmd += " " + dnss[0];
- }
-
- return RootCommand.executeRootCmd(cmd);
- }
-
- private String getGateWayTimeout(int timeoutMillis) {
-
- String gw = getGateway();
- if (gw != null && !gw.trim().isEmpty()) {
- return gw;
- }
-
- Utils.logDebug("Gateway not available.. going into wait loop..");
-
- // gateway not (yet) available
- // waits for a maximum of timeoutMillis milliseconds
- // to let the interface being registered.
- int msWaited = 0;
- while (msWaited < timeoutMillis) {
-
- try {
- Thread.sleep(100);
- } catch (Exception e) {
- return null;
- }
- msWaited += 100;
-
- gw = getGateway();
- if (gw != null && !gw.trim().isEmpty()) {
- Utils.logDebug("Gateway found after wait loop!");
- return gw;
- }
- }
-
- // unable to get gateway
- Utils.logError("Gateway not found after wait loop.");
- return null;
-
- }
-
- private String getGateway() {
-
- try {
-
- // doesn't need root (tested)
- ShellCommand cmd = new ShellCommand("ip route show dev " + WpaSupplicant.INTERFACE_NAME);
- if (cmd.execute() != 0) {
- Utils.logDebug("command failed show route");
- return null;
- }
-
- // read command output
- String out = cmd.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() {
- // needs root (tested)
- return RootCommand.executeRootCmd("ndc interface clearaddrs "
- + WpaSupplicant.INTERFACE_NAME);
- }
-
-} \ No newline at end of file
diff --git a/app/src/fil/libre/repwifiapp/helpers/Logger.java b/app/src/fil/libre/repwifiapp/helpers/Logger.java
new file mode 100644
index 0000000..2641571
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/helpers/Logger.java
@@ -0,0 +1,160 @@
+//
+// Copyright 2017, 2018 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.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Environment;
+import android.util.Log;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.service.ConnectionManagementService;
+import java.io.File;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+public abstract class Logger {
+
+ public static String APP_NAME = "RepWifi";
+
+ private static int logPriority = 3;
+
+ 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 < logPriority) {
+ return;
+ }
+
+ Log.d(APP_NAME, msg);
+ }
+
+
+ @SuppressLint("SimpleDateFormat")
+ public static String getLogDumpFile() {
+
+ File f = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ if (f == null || !f.exists()) {
+ return null;
+ }
+
+
+ String basefolder;
+ try {
+ basefolder = f.getCanonicalPath();
+ } catch (Exception e) {
+ logError("Exception while resolving canonical path for log dump file.", e);
+ return null;
+ }
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss", Locale.getDefault());
+ String ts = dateFormat.format(Calendar.getInstance().getTime());
+ return basefolder + "/repwifi_log_dump." + ts + ".log";
+ }
+
+ public static boolean dumpLogcatToFile(Context appcontext){
+ return dumpLogcatToFile(getLogDumpFile(),appcontext);
+ }
+
+ public static void setLogPriority(int priority){
+
+ if (priority < 0){
+ priority = 0;
+ }
+
+ logPriority = priority;
+
+ }
+
+ public static boolean dumpLogcatToFile(String filePath, Context appcontext) {
+
+ if (filePath == null) {
+ return false;
+ }
+
+ try {
+
+ String cmd1 = "logcat -d | grep " + APP_NAME + ">" + filePath;
+ String cmd2 = "logcat -d | grep -A10 -B10 " + appcontext.getPackageName()
+ + ">>" + filePath;
+ String cmd3 = "logcat -d | grep " + ConnectionManagementService.LOG_TAG_NETWORKAGENT
+ + ">>" + filePath;
+ String cmd4 = "logcat -d | grep " + ConnectionManagementService.LOG_TAG_SERVICE + ">>"
+ + filePath;
+
+ String SEP_LOG = "\n\n---------- [REPWIFI_LOG_SEPARATOR] ----------\n\n";
+
+ RootCommand c1 = new RootCommand(cmd1);
+ RootCommand c2 = new RootCommand(cmd2);
+ RootCommand c3 = new RootCommand(cmd3);
+ RootCommand c4 = new RootCommand(cmd4);
+
+ if (c1.execute() != 0) {
+ return false;
+ }
+
+ if (!Utils.writeFile(filePath, SEP_LOG, false)) {
+ return false;
+ }
+
+ if (c2.execute() != 0) {
+ return false;
+ }
+
+ if (!Utils.writeFile(filePath, SEP_LOG, false)) {
+ return false;
+ }
+
+ if (c3.execute() != 0) {
+ return false;
+ }
+
+ if (c4.execute() != 0) {
+ return false;
+ }
+
+ RootCommand.executeRootCmd("chmod 666 " + filePath);
+
+ return true;
+
+ } catch (Exception e) {
+ logError("Exception during log dump.", e);
+ return false;
+ }
+
+ }
+
+
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/OpenVpnManager.java b/app/src/fil/libre/repwifiapp/helpers/OpenVpnManager.java
deleted file mode 100644
index 5de2501..0000000
--- a/app/src/fil/libre/repwifiapp/helpers/OpenVpnManager.java
+++ /dev/null
@@ -1,237 +0,0 @@
-//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
-//
-// This file is part of RepWifiApp.
-// This file is based upon the example file included in
-// de.blinkt.openvpn package by Arne Schwabe.
-//
-// 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.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.IBinder;
-import android.os.RemoteException;
-import java.util.ArrayList;
-import java.util.List;
-import de.blinkt.openvpn.api.APIVpnProfile;
-import de.blinkt.openvpn.api.IOpenVPNAPIService;
-
-public class OpenVpnManager {
-
- public static final String SERVICE_PACKAGE_NAME = "de.blinkt.openvpn";
- public static final String APP_COMMON_NAME = "OpenVPN for Android";
- public static final String PLACEHOLDER_APPNAME = "[VPN_EXT_APP]";
-
- private static boolean VpnIsConnected;
- private static OpenVpnManager _currentInstance;
-
- protected IOpenVPNAPIService _vpnSvc;
-
- private Activity _caller;
- private ServiceConnection _svcConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- _vpnSvc = IOpenVPNAPIService.Stub.asInterface(service);
- }
-
- public void onServiceDisconnected(ComponentName className) {
- _vpnSvc = null;
- }
- };
-
- private OpenVpnManager(Activity c) throws Exception {
- this._caller = c;
- bindService();
- }
-
- private void bindService() throws Exception {
-
- Intent intentGetService = new Intent(IOpenVPNAPIService.class.getName());
- intentGetService.setPackage(SERVICE_PACKAGE_NAME);
- if (!_caller.bindService(intentGetService, _svcConnection, Context.BIND_AUTO_CREATE)) {
- throw new Exception("FAILED to bind to OpenVPN service!");
- }
-
- }
-
- private void unbindService() {
- _caller.unbindService(_svcConnection);
- }
-
- private Intent askApiPermissionsGetIntentInternal() throws RemoteException {
- return _vpnSvc.prepare(_caller.getPackageName());
- }
-
- private boolean startVpnInternal(String profileUuid) {
-
- if (profileUuid == null) {
- Utils.logError("Invoked startVpn with null uuid");
- return false;
- }
-
- if (_vpnSvc == null) {
- Utils.logError("Invoked startVpn but inner service is null.");
- return false;
- }
-
- try {
-
- _vpnSvc.startProfile(profileUuid);
- VpnIsConnected = true;
- return true;
-
- } catch (RemoteException e) {
- Utils.logError("Exception while starting vpn.", e);
- return false;
- }
- }
-
- private boolean disconnectInternal() {
-
- if (_vpnSvc == null) {
- Utils.logDebug("Attempted to disconnect from VPN, but inner service is null");
- VpnIsConnected = false;
- return true;
- }
-
- try {
- _vpnSvc.disconnect();
- VpnIsConnected = false;
- return true;
- } catch (RemoteException e) {
- Utils.logError("Exception while disconnecting from vpn.", e);
- return false;
- }
- }
-
- private List<String> getExistingProfilesInternal(){
-
- try {
- List<APIVpnProfile> list = _vpnSvc.getProfiles();
-
- List<String> ret = new ArrayList<String>();
- for (APIVpnProfile vp : list) {
- ret.add(vp.mName);
- }
-
- return ret;
-
- } catch (RemoteException e) {
- Utils.logError("Exception while retrieving profiles from vpn service.", e);
- return null;
- }
-
- }
-
- private String getUuidFromNameInternal(String profileName) {
-
- if (_vpnSvc == null) {
- Utils.logError("Called getUuidFromName but inner service is null!");
- return null;
- }
-
- try {
- List<APIVpnProfile> list = _vpnSvc.getProfiles();
-
- for (APIVpnProfile vp : list) {
- if (vp.mName.equals(profileName)) {
- return vp.mUUID;
- }
- }
-
- return null;
-
- } catch (RemoteException e) {
- Utils.logError("Exception while retrieving profiles from vpn service.", e);
- return null;
- }
- }
-
- public void close() {
- if (_vpnSvc != null) {
- unbindService();
-
- }
-
- }
-
- public static void initialize(Activity caller){
-
- if (_currentInstance != null){
- return;
- }
-
- try {
- _currentInstance = new OpenVpnManager(caller);
- } catch (Exception e) {
- Utils.logError("Exception while initializing vpn manager.",e);
- }
- }
-
- public static boolean isExternalAppInstalled(Activity caller) {
-
- try {
-
- ApplicationInfo i;
- i = caller.getPackageManager().getApplicationInfo(SERVICE_PACKAGE_NAME, 0);
- return (i != null);
-
- } catch (NameNotFoundException e) {
- return false;
- }
-
- }
-
- public static boolean startVpn(String profileUuid){
- if (_currentInstance == null){
- return false;
- }
- return _currentInstance.startVpnInternal(profileUuid);
- }
-
- public static boolean disconnect(){
- if (_currentInstance == null){
- return false;
- }
- return _currentInstance.disconnectInternal();
- }
-
- public static boolean isVpnConnected(){
- return VpnIsConnected;
- }
-
- public static String getUuidFromName(String profileName){
- if (_currentInstance == null){
- return null;
- }
- return _currentInstance.getUuidFromNameInternal(profileName);
- }
-
- public static List<String> getExistingProfiles(){
- return _currentInstance.getExistingProfilesInternal();
- }
-
- public static Intent askApiPermissionsGetIntent() throws RemoteException{
- return _currentInstance.askApiPermissionsGetIntentInternal();
- }
-
-}
diff --git a/app/src/fil/libre/repwifiapp/helpers/RootCommand.java b/app/src/fil/libre/repwifiapp/helpers/RootCommand.java
index bd859c8..61dfa2d 100644
--- a/app/src/fil/libre/repwifiapp/helpers/RootCommand.java
+++ b/app/src/fil/libre/repwifiapp/helpers/RootCommand.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -20,40 +20,61 @@
package fil.libre.repwifiapp.helpers;
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.Utils;
import java.io.DataOutputStream;
import java.io.InputStream;
+import java.util.concurrent.TimeoutException;
public class RootCommand extends ShellCommand {
- // protected static final String CMD_WRAPPING = "export TEMPOUT=\"$(%s)\";echo \"$TEMPOUT\";exit $?";
- protected static final String CMD_WRAPPING = "TEMPOUT=\"$(%s)\";ec=$?;echo \"$TEMPOUT\";exit $ec";
+ protected static final String CMD_WRAPPING = "TEMPOUT=\"$(%s)\";ec=$?;echo \"$TEMPOUT\";echo $ec > \"%s\";exit $ec";
+ //protected static final String CMD_WRAPPING = "TEMPOUT=\"$(%s)\";ec=$?;echo \"$TEMPOUT\";exit $ec";
public RootCommand(String commandText) {
super(commandText);
this._cmdTxt = commandText;
}
+
+ public static boolean executeRootCmd(String cmd){
+ // won't return
+ try {
+ return executeRootCmd(cmd, -1);
+ } catch (TimeoutException e){
+ // will never throw timeout exception as it won't use asynchronous wait.
+ return false;
+ }
+ }
+
+ public static boolean executeRootCmd(String cmd, long timeoutMillis) throws TimeoutException{
- public static boolean executeRootCmd(String cmd) {
-
try {
RootCommand c = new RootCommand(cmd);
- if (c.execute() == 0) {
+ if (c.execute(timeoutMillis) == 0) {
return true;
} else {
return false;
}
- } catch (Exception e) {
- Utils.logError("Error executing \"" + cmd + "\"", e);
+ }
+ catch (TimeoutException te){
+ throw te;
+ }
+ catch (Exception e) {
+ Logger.logError("Error executing \"" + cmd + "\"", e);
return false;
}
}
@Override
public int execute() throws Exception {
-
+ return execute(-1);
+ }
+
+ public int execute(long timeoutMillis) throws Exception{
+
if (this._cmdTxt == null) {
return EXITCODE_INVALID_INPUT;
}
@@ -64,9 +85,9 @@ public class RootCommand extends ShellCommand {
InputStream os = su.getInputStream();
InputStream es = su.getErrorStream();
- Utils.logDebug("SU:EXEC: " + this._cmdTxt);
+ Logger.logDebug("SU:EXEC: " + this._cmdTxt);
- String wrappedCmd = String.format(CMD_WRAPPING, this._cmdTxt);
+ String wrappedCmd = String.format(CMD_WRAPPING, this._cmdTxt, Commons.getExitCodeTempFile());
stdin.writeBytes(wrappedCmd + "\n");
stdin.flush();
@@ -76,7 +97,16 @@ public class RootCommand extends ShellCommand {
sb.append(getStringFromStream(es));
sb.append(getStringFromStream(os));
- int res = su.waitFor();
+ int res;
+
+ if (timeoutMillis <= MIN_TIMEOUT_MILLIS){
+ res = su.waitFor();
+
+ } else {
+ Logger.logDebug("Executing command with " + timeoutMillis + "ms timeout.");
+ ProcessTimeout w = new ProcessTimeout();
+ res = w.waitFor(su, timeoutMillis);
+ }
// re-read the output, in case it was empty when first tried
sb.append(getStringFromStream(es));
@@ -84,10 +114,16 @@ public class RootCommand extends ShellCommand {
this._cmdOut = sb.toString();
- Utils.logDebug("OUT: " + getOutput());
+ Logger.logDebug("OUT: " + getOutput());
+ if (res == 0){
+ // could be su's own exit code hiding the original one:
+ res = readLastExitCodeFromFile();
+ }
+
+ Logger.logDebug("ExitCode: " + res);
return res;
-
+
}
public int testRootAccess() throws Exception {
@@ -96,16 +132,27 @@ public class RootCommand extends ShellCommand {
DataOutputStream stdin = new DataOutputStream(su.getOutputStream());
- Utils.logDebug("Testing root access: executing simple \"su\"");
+ Logger.logDebug("Testing root access: executing simple \"su\"");
stdin.writeBytes("exit\n");
stdin.flush();
int res = su.waitFor();
- Utils.logDebug("Simple \"su\" exitcode: " + res);
+ Logger.logDebug("Simple \"su\" exitcode: " + res);
return res;
}
-
+
+ private int readLastExitCodeFromFile(){
+
+ String strec = Utils.readFile(Commons.getExitCodeTempFile()).trim();
+ try{
+ return Integer.parseInt(strec);
+ }catch(NumberFormatException e){
+ Logger.logError("NumberFormatException while parsing contents of ExitCodeTempFile: " + strec);
+ return EXITCODE_PARSING_ERROR;
+ }
+ }
+
}
diff --git a/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java b/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java
index f232ac7..d6b7553 100644
--- a/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java
+++ b/app/src/fil/libre/repwifiapp/helpers/ShellCommand.java
@@ -1,11 +1,34 @@
+//
+// Copyright 2017, 2018 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.IOException;
import java.io.InputStream;
+import java.util.concurrent.TimeoutException;
public class ShellCommand {
public static final int EXITCODE_INVALID_INPUT = -9;
+ public static final int EXITCODE_PARSING_ERROR = 999;
+ public static final int MIN_TIMEOUT_MILLIS = 100;
protected String _cmdOut = "";
protected String _cmdTxt = "";
@@ -20,7 +43,7 @@ public class ShellCommand {
return EXITCODE_INVALID_INPUT;
}
- Utils.logDebug("EXEC: " + this._cmdTxt);
+ Logger.logDebug("EXEC: " + this._cmdTxt);
Process cmd = Runtime.getRuntime().exec(this._cmdTxt);
@@ -41,32 +64,16 @@ public class ShellCommand {
this._cmdOut = sb.toString();
- Utils.logDebug("EXITCODE: " + res);
- Utils.logDebug("OUT: " + getOutput());
+ Logger.logDebug("EXITCODE: " + res);
+ Logger.logDebug("OUT: " + getOutput());
return res;
}
protected String getStringFromStream(InputStream s) throws IOException {
-
java.util.Scanner sc = new java.util.Scanner(s,"UTF-8").useDelimiter("\\A");
return sc.hasNext() ? sc.next() : "";
-
- /*
-
- StringBuilder sb = new StringBuilder();
- while ((s.available() > 0)) {
- int b = s.read();
- if (b >= 0) {
- sb.append((char) b);
- } else {
- break;
- }
- }
-
- return sb.toString();*/
-
}
public String getOutput() {
@@ -74,5 +81,67 @@ public class ShellCommand {
return this._cmdOut;
}
+
+ protected class ProcessTimeout{
+
+ private Process _proc;
+ private int _exitCode;
+ private boolean _hasExited = false;
+ private InterruptedException e = null;
+
+ public int waitFor(Process p, long timeoutMillis) throws InterruptedException, TimeoutException{
+
+ // waits for a maximum of timeoutMillis milliseconds
+ // for the process to exit.
+ int msWaited = 0;
+ this._proc = p;
+ startWaitingForProcess();
+ while (msWaited < timeoutMillis) {
+
+ if (e != null){
+ // exception from the underlying thread;
+ throw e;
+ }
+
+ if (! _hasExited){
+ Thread.sleep(MIN_TIMEOUT_MILLIS);
+ msWaited += MIN_TIMEOUT_MILLIS;
+
+ } else {
+ return _exitCode;
+ }
+ }
+
+ throw new TimeoutException("Timeout elapsed while waiting for inner process to finish its execution.");
+
+ }
+
+ private void startWaitingForProcess(){
+
+ new Thread(new Runnable() {
+ public void run(){
+ try {
+ int exitCode = _proc.waitFor();
+ setExitCode(exitCode);
+ } catch (InterruptedException e) {
+ setException(e);
+ }
+ }
+ }).start();
+
+ }
+
+ private void setExitCode(int ec){
+ _hasExited = true;
+ _exitCode = ec;
+ }
+
+ private void setException(InterruptedException e){
+ this.e = e;
+ }
+
+ }
+
}
+
diff --git a/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java b/app/src/fil/libre/repwifiapp/network/AccessPointInfo.java
index eee569d..862a852 100644
--- a/app/src/fil/libre/repwifiapp/helpers/AccessPointInfo.java
+++ b/app/src/fil/libre/repwifiapp/network/AccessPointInfo.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,19 +18,23 @@
//
// ********************************************************************
-package fil.libre.repwifiapp.helpers;
+package fil.libre.repwifiapp.network;
+import android.os.Parcel;
+import android.os.Parcelable;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.Logger;
import org.json.JSONException;
import org.json.JSONObject;
-import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
-public class AccessPointInfo implements Serializable {
+public class AccessPointInfo implements Parcelable {
- private static final long serialVersionUID = 2L;
+ public static final String DUMMY_VPN_PROFILE = "--------";
+
private static final int MAX_SSID_LENGTH = 32;
protected static final String SCAN_FILE_HDR = "bssid / frequency / signal level / flags / ssid";
@@ -117,6 +121,11 @@ public class AccessPointInfo implements Serializable {
}
public void setVpnProfileName(String profileName){
+
+ if (profileName != null && profileName.equals(DUMMY_VPN_PROFILE)){
+ profileName = "";
+ }
+
_vpnProfileName = profileName;
}
@@ -227,7 +236,7 @@ public class AccessPointInfo implements Serializable {
return info;
} catch (Exception e) {
- Utils.logError("Error while parsing line: " + line, e);
+ Logger.logError("Error while parsing line: " + line, e);
return null;
}
@@ -241,7 +250,7 @@ public class AccessPointInfo implements Serializable {
return null;
}
- Utils.logDebug("AccesPointInfo trying to parse file scan content:\n"
+ Logger.logDebug("AccesPointInfo trying to parse file scan content:\n"
+ scanResultContent);
String[] lines = scanResultContent.split("\n");
@@ -265,7 +274,7 @@ public class AccessPointInfo implements Serializable {
// try to parse line into network info
AccessPointInfo info = AccessPointInfo.parseLine(l);
if (info == null) {
- Utils.logError("Failed to parse line into AccessPointInfo: " + l);
+ Logger.logError("Failed to parse line into AccessPointInfo: " + l);
continue;
}
@@ -280,10 +289,23 @@ public class AccessPointInfo implements Serializable {
return a;
} catch (Exception e) {
- Utils.logError("Error while parsing scan results in class AccessPointInfo", e);
+ Logger.logError("Error while parsing scan results in class AccessPointInfo", e);
+ return null;
+ }
+
+ }
+
+ public static AccessPointInfo[] fromParcellableArray(Parcelable[] p){
+ if (p == null) {
return null;
}
+ AccessPointInfo[] infos = new AccessPointInfo[p.length];
+ for (int j = 0; j < infos.length; j++) {
+ infos[j] = (AccessPointInfo) p[j];
+ }
+
+ return infos;
}
public JSONObject toJson(){
@@ -311,7 +333,7 @@ public class AccessPointInfo implements Serializable {
return j;
} catch (JSONException e) {
- Utils.logError("Exception while converting AccessPointInfo to JSON.", e);
+ Logger.logError("Exception while converting AccessPointInfo to JSON.", e);
return null;
}
@@ -346,7 +368,7 @@ public class AccessPointInfo implements Serializable {
return info;
} catch (JSONException e) {
- Utils.logError("Exception while parsing json object to AccessPointInfo", e);
+ Logger.logError("Exception while parsing json object to AccessPointInfo", e);
return null;
}
@@ -367,4 +389,54 @@ public class AccessPointInfo implements Serializable {
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public AccessPointInfo(Parcel in){
+
+ this._ssid = in.readString();
+ this._bssid = in.readString();
+ this._auth = in.readString();
+ this._level = in.readString();
+ this._freq = in.readString();
+ this._password = in.readString();
+ this._vpnProfileName = in.readString();
+ this._isHidden = in.readInt() == 1 ? true : false;
+ this._lastTimeUsed = in.readLong();
+ this._dhcpsets = in.readParcelable(DhcpSettings.class.getClassLoader());
+
+ }
+
+ public static final Parcelable.Creator<AccessPointInfo> CREATOR = new Parcelable.Creator<AccessPointInfo>() {
+ public AccessPointInfo createFromParcel(Parcel in) {
+ return new AccessPointInfo(in);
+ }
+
+ @Override
+ public AccessPointInfo[] newArray(int size) {
+ return new AccessPointInfo[size];
+ }
+
+
+
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+
+ dest.writeString(_ssid);
+ dest.writeString(_bssid);
+ dest.writeString(_auth);
+ dest.writeString(_level);
+ dest.writeString(_freq);
+ dest.writeString(_password);
+ dest.writeString(_vpnProfileName);
+ dest.writeInt(_isHidden ? 1 : 0);
+ dest.writeLong(_lastTimeUsed);
+ dest.writeParcelable(_dhcpsets, flags);
+
+ }
+
}
diff --git a/app/src/fil/libre/repwifiapp/network/ConnectionResult.java b/app/src/fil/libre/repwifiapp/network/ConnectionResult.java
new file mode 100644
index 0000000..32ae771
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/network/ConnectionResult.java
@@ -0,0 +1,95 @@
+//
+// Copyright 2017, 2018 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.network;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class ConnectionResult implements Parcelable {
+
+ public static final int CONN_OK = 0;
+ public static final int CONN_FAILED = 1;
+ public static final int CONN_TIMEOUT = 2;
+ // public static final int CONN_DNS_FAIL = 3; // Removed as dns is now set
+ // by the framework
+ public static final int CONN_GW_FAIL = 4;
+ public static final int CONN_ABORTED = 5;
+ public static final int CONN_NOTIFY_FAILED = 6;
+ public static final int NO_RESULT = -1;
+
+ private ConnectionStatus _status = null;
+ private int _result = NO_RESULT;
+
+ public ConnectionResult(int result) {
+ this._result = result;
+ this._status = null;
+ }
+
+ public ConnectionStatus getStatus() {
+ return _status;
+ }
+
+ public int getResult() {
+ return _result;
+ }
+
+ public void setStatus(ConnectionStatus status) {
+
+ // keep coherence between the result code and the status
+ if (status != null && status.isConnected() && this._result == CONN_OK) {
+ this._status = status;
+ } else if (this._result == CONN_OK) {
+ this._result = CONN_FAILED;
+ this._status = null;
+ } else {
+ this._status = null;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public ConnectionResult(Parcel in) {
+ this._result = in.readInt();
+ this._status = in.readParcelable(ConnectionStatus.class.getClassLoader());
+ }
+
+ public static final Parcelable.Creator<ConnectionResult> CREATOR = new Parcelable.Creator<ConnectionResult>() {
+ public ConnectionResult createFromParcel(Parcel in) {
+ return new ConnectionResult(in);
+ }
+
+ @Override
+ public ConnectionResult[] newArray(int size) {
+ return new ConnectionResult[size];
+ }
+
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(this._result);
+ dest.writeParcelable(this._status, flags);
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/network/ConnectionStatus.java b/app/src/fil/libre/repwifiapp/network/ConnectionStatus.java
new file mode 100644
index 0000000..5fac0a1
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/network/ConnectionStatus.java
@@ -0,0 +1,298 @@
+//
+// Copyright 2017, 2018 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.network;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.Logger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class ConnectionStatus implements Parcelable {
+
+ 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 wpaStatus = null;
+ public String SSID = null;
+ public String BSSID = null;
+ public String IP = null;
+ public String gateway = null;
+ public String subnetMask = null;
+ public String hwAddress = null;
+ public String broadcastAddress = null;
+
+ 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";
+
+ private static final String IFCONFIG_BCAST = "Bcast";
+ private static final String IFCONFIG_MASK = "Mask";
+ private static final String IFCONFIG_HWADDR = "HWaddr";
+ private static final String IFCONFIG_KVALSEP = ":";
+ private static final String IFCONFIG_FSEP = " ";
+
+ public ConnectionStatus() {
+ }
+
+ 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.wpaStatus = val;
+ } else if (key.equals(KeyIP)) {
+ s.IP = val;
+ }
+
+ }
+
+ return s;
+
+ }
+
+ public static ConnectionStatus getDummyDisconnected() {
+ ConnectionStatus s = new ConnectionStatus();
+ s.wpaStatus = STATUS_DISCONNECTED;
+ return s;
+ }
+
+ public boolean parseIfconfigOutput(String ifconfigOutput) {
+
+ if (ifconfigOutput == null) {
+ return false;
+ }
+
+ String[] lines = ifconfigOutput.split("\n");
+ if (lines.length < 2) {
+ return false;
+ }
+
+ String[] fields1 = lines[0].split(IFCONFIG_FSEP);
+ String[] fields2 = lines[1].split(IFCONFIG_FSEP);
+
+ for (String f : fields1) {
+ // first line uses a single blank space as key-val separator
+ String[] splt = f.split(" ");
+ if (splt.length == 2 && splt[0].equals(IFCONFIG_HWADDR)) {
+ this.hwAddress = splt[1];
+ }
+ }
+
+ for (String f : fields2) {
+ String[] splt = f.split(IFCONFIG_KVALSEP);
+ if (splt.length == 2) {
+
+ String key = splt[0];
+ String val = splt[1];
+
+ if (key.equals(IFCONFIG_MASK)) {
+
+ this.subnetMask = val.trim();
+
+ } else if (key.equals(IFCONFIG_BCAST)) {
+
+ this.broadcastAddress = val;
+
+ } else if (key.equals(IFCONFIG_HWADDR)) {
+
+ this.hwAddress = val;
+
+ }
+
+ }
+ }
+
+ return true;
+
+ }
+
+ public boolean isConnected() {
+
+ if (this.wpaStatus == null) {
+ return false;
+ }
+
+ if (this.wpaStatus.equals(STATUS_CONNECTED)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /***
+ * @return Returns a string representation of the current IP address and
+ * subnet mask (e.g. "192.168.1.123/24"); returns null if either the
+ * address or the mask is null.
+ */
+ public String addressAndMaskToString() {
+
+ if (this.IP == null || this.subnetMask == null) {
+ return null;
+ }
+
+ int mask = Utils.netmaskStringToInt(this.subnetMask);
+ return this.IP + "/" + mask;
+
+ }
+
+ public InetAddress getInetAddress() {
+ if (this.IP == null) {
+ return null;
+ }
+
+ try {
+ return InetAddress.getByName(this.IP);
+ } catch (UnknownHostException e) {
+ Logger.logError("Exception while parsing InetAddress from string", e);
+ return null;
+ }
+
+ }
+
+ public int getSubnetMaskInt() {
+ return Utils.netmaskStringToInt(this.subnetMask);
+ }
+
+ public InetAddress getGatewayInetAddress() {
+
+ if (this.gateway == null) {
+ return null;
+ }
+
+ try {
+ return InetAddress.getByName(this.gateway);
+ } catch (Exception e) {
+ Logger.logError("Exception while parsing gateway's InetAddress from string.", e);
+ return null;
+ }
+
+ }
+
+ public AccessPointInfo getNetworkDetails() {
+ AccessPointInfo i = new AccessPointInfo(SSID, BSSID, "", "", "");
+ return NetworkManager.getSavedNetwork(i);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public ConnectionStatus(Parcel in) {
+
+ this.SSID = in.readString();
+ this.BSSID = in.readString();
+ this.IP = in.readString();
+ this.subnetMask = in.readString();
+ this.gateway = in.readString();
+ this.hwAddress = in.readString();
+ this.broadcastAddress = in.readString();
+ this.wpaStatus = in.readString();
+
+ }
+
+ public static final Parcelable.Creator<ConnectionStatus> CREATOR = new Parcelable.Creator<ConnectionStatus>() {
+ public ConnectionStatus createFromParcel(Parcel in) {
+ return new ConnectionStatus(in);
+ }
+
+ public ConnectionStatus[] newArray(int size) {
+ return new ConnectionStatus[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+
+ dest.writeString(this.SSID);
+ dest.writeString(this.BSSID);
+ dest.writeString(this.IP);
+ dest.writeString(this.subnetMask);
+ dest.writeString(this.gateway);
+ dest.writeString(this.hwAddress);
+ dest.writeString(this.broadcastAddress);
+ dest.writeString(this.wpaStatus);
+
+ }
+
+ public boolean equals(ConnectionStatus status) {
+
+ if (status == null) {
+ return false;
+ }
+
+ if (status.isConnected() != this.isConnected()) {
+ return false;
+ }
+
+ return fieldEquals(this.IP, status.IP) && fieldEquals(this.BSSID, status.BSSID)
+ && fieldEquals(this.SSID, status.SSID)
+ && fieldEquals(this.subnetMask, status.subnetMask)
+ && fieldEquals(this.gateway, status.gateway)
+ && fieldEquals(this.hwAddress, status.hwAddress);
+
+ }
+
+ private boolean fieldEquals(String myField, String extField) {
+ return myField == null ? extField == null : myField.equals(extField);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "WPAsts: %s; \nIP: %s; \nMask: %s; \nGway: %s; \nBcast: %s; \nHWaddr: %s ",
+ wpaStatus, IP, subnetMask, gateway, broadcastAddress, hwAddress);
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/helpers/DhcpSettings.java b/app/src/fil/libre/repwifiapp/network/DhcpSettings.java
index c0587a3..65524d5 100644
--- a/app/src/fil/libre/repwifiapp/helpers/DhcpSettings.java
+++ b/app/src/fil/libre/repwifiapp/network/DhcpSettings.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,17 +18,19 @@
//
// ********************************************************************
-package fil.libre.repwifiapp.helpers;
+package fil.libre.repwifiapp.network;
+import android.nfc.FormatException;
+import android.os.Parcel;
+import android.os.Parcelable;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.Logger;
import org.apache.http.conn.util.InetAddressUtils;
import org.json.JSONException;
import org.json.JSONObject;
-import java.io.Serializable;
-import android.nfc.FormatException;
-public class DhcpSettings implements Serializable {
+public class DhcpSettings implements Parcelable {
- private static final long serialVersionUID = 1L;
public boolean useDhcp;
private String _staticIP;
private int _mask;
@@ -37,7 +39,7 @@ public class DhcpSettings implements Serializable {
private static final String JSONKEY_DHCP = "DHCP";
private static final String JSONKEY_STATIC_IP = "StaticIP";
private static final String JSONKEY_GW = "Gateway";
-
+
public DhcpSettings(boolean useDhcp, String staticIP, String subnetMask, String defaultGateway)
throws FormatException {
this(useDhcp, staticIP, Utils.netmaskStringToInt(subnetMask), defaultGateway);
@@ -62,12 +64,12 @@ public class DhcpSettings implements Serializable {
}
- private DhcpSettings(){
+ private DhcpSettings() {
// inner use
}
-
- public static DhcpSettings parseSavedSettings(String staticIPwithMask, String defaultGateway){
-
+
+ public static DhcpSettings parseSavedSettings(String staticIPwithMask, String defaultGateway) {
+
try {
String[] ipm = staticIPwithMask.split("/");
@@ -75,24 +77,24 @@ public class DhcpSettings implements Serializable {
int mask = Integer.parseInt(ipm[1]);
return new DhcpSettings(false, ip, mask, defaultGateway);
-
} catch (Exception e) {
- Utils.logError("Exception while parsing DhcpSettings for saved network. Reverting to dhcp.", e);
+ Logger.logError("Exception while parsing DhcpSettings for saved network. Reverting to dhcp.",
+ e);
return null;
}
-
+
}
-
- public static DhcpSettings getDefault(){
+
+ public static DhcpSettings getDefault() {
try {
return new DhcpSettings(true, null, 24, null);
} catch (FormatException e) {
- //no format exception can happen.
+ // no format exception can happen.
return null;
}
}
-
+
private boolean validateParams(String ip, String gateway, int mask) {
if (isValidAddress(ip) && isValidAddress(gateway) && isValidMask(mask)) {
@@ -102,26 +104,26 @@ public class DhcpSettings implements Serializable {
}
}
-
- public static boolean isValidAddress(String ipAddress){
+
+ public static boolean isValidAddress(String ipAddress) {
return InetAddressUtils.isIPv4Address(ipAddress);
}
-
- public static boolean isValidMaks(String mask){
+
+ public static boolean isValidMaks(String mask) {
int m = Utils.netmaskStringToInt(mask);
return isValidMask(m);
}
- public static boolean isValidMask(int mask){
- if (mask >= 8 && mask <= 32){
+ public static boolean isValidMask(int mask) {
+ if (mask >= 8 && mask <= 32) {
return true;
- }else{
+ } else {
return false;
}
}
-
+
public String getStaticIP() {
- if (_staticIP == null){
+ if (_staticIP == null) {
return "";
}
return _staticIP;
@@ -134,72 +136,107 @@ public class DhcpSettings implements Serializable {
public int getSubnetMaskInt() {
return _mask;
}
-
- public String getSubnetMaskString(){
+
+ public String getSubnetMaskString() {
String v = Utils.netmaskIntToString(_mask);
- if (v == null){
+ if (v == null) {
return "";
}
return v;
}
-
+
public String getDefaultGateway() {
- if (_defGw == null){
+ if (_defGw == null) {
return "";
}
return _defGw;
}
- public JSONObject toJson(){
-
+ public JSONObject toJson() {
+
JSONObject j = new JSONObject();
-
+
try {
j.put(JSONKEY_DHCP, useDhcp);
j.put(JSONKEY_GW, getDefaultGateway());
j.put(JSONKEY_STATIC_IP, getStaticIPwithMask());
-
+
return j;
-
+
} catch (JSONException e) {
- Utils.logError("Exception while converting DhcpSettings to JSON.", e);
+ Logger.logError("Exception while converting DhcpSettings to JSON.", e);
return null;
}
-
-
+
}
-
- public static DhcpSettings fromJsonObject(JSONObject json){
-
- if (json == null){
+
+ public static DhcpSettings fromJsonObject(JSONObject json) {
+
+ if (json == null) {
return null;
}
-
+
DhcpSettings sets = new DhcpSettings();
-
+
try {
-
+
sets.useDhcp = json.getBoolean(JSONKEY_DHCP);
-
- if (json.has(JSONKEY_GW) && ! json.isNull(JSONKEY_GW)){
+
+ if (json.has(JSONKEY_GW) && !json.isNull(JSONKEY_GW)) {
sets._defGw = json.getString(JSONKEY_GW);
}
-
- if (json.has(JSONKEY_STATIC_IP) && !json.isNull(JSONKEY_STATIC_IP)){
-
+
+ if (json.has(JSONKEY_STATIC_IP) && !json.isNull(JSONKEY_STATIC_IP)) {
+
String[] splt = json.getString(JSONKEY_STATIC_IP).split("/");
sets._staticIP = splt[0];
sets._mask = Integer.parseInt(splt[1]);
-
+
}
-
+
return sets;
-
+
} catch (Exception e) {
- Utils.logError("Exception while parsing json object to DhcpSettings", e);
+ Logger.logError("Exception while parsing json object to DhcpSettings", e);
return null;
}
-
+
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
}
-
+
+ public DhcpSettings(Parcel in) {
+
+ this.useDhcp = in.readInt() == 1 ? true : false;
+ this._staticIP = in.readString();
+ this._mask = in.readInt();
+ this._defGw = in.readString();
+
+ }
+
+ public static final Parcelable.Creator<DhcpSettings> CREATOR = new Parcelable.Creator<DhcpSettings>() {
+ public DhcpSettings createFromParcel(Parcel in) {
+ return new DhcpSettings(in);
+ }
+
+ @Override
+ public DhcpSettings[] newArray(int size) {
+ return new DhcpSettings[size];
+ }
+
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+
+ dest.writeInt(useDhcp ? 1 : 0);
+ dest.writeString(_staticIP);
+ dest.writeInt(_mask);
+ dest.writeString(_defGw);
+
+ }
+
}
diff --git a/app/src/fil/libre/repwifiapp/helpers/Engine.java b/app/src/fil/libre/repwifiapp/network/Engine.java
index 225d993..34de124 100644
--- a/app/src/fil/libre/repwifiapp/helpers/Engine.java
+++ b/app/src/fil/libre/repwifiapp/network/Engine.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,50 +18,87 @@
//
// ********************************************************************
-package fil.libre.repwifiapp.helpers;
+package fil.libre.repwifiapp.network;
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.helpers.RootCommand;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
public abstract class Engine implements IEngine {
+
+ public static final String PIDFILE_DHCPCD = "/data/misc/dhcp/dhcpcd-wlan0.pid";
+
@Override
public AccessPointInfo[] getAvailableNetworks() {
- Utils.logDebug("getAvailableNetworks():");
+ Logger.logDebug("getAvailableNetworks():");
if (!WpaSupplicant.start()) {
- Utils.logError("Failed starting wpa_supplicant");
+ Logger.logError("Failed starting wpa_supplicant");
return null;
}
if (!WpaCli.scanNetworks()) {
- Utils.logError("failed scanning networks");
+ Logger.logError("failed scanning networks");
return null;
}
String scanRes = WpaCli.getScanResults();
if (scanRes == null) {
- Utils.logError("failed getting scan results");
+ Logger.logError("failed getting scan results");
return null;
}
AccessPointInfo[] a = AccessPointInfo.parseScanResult(scanRes);
if (a == null) {
- Utils.logError("Unable to parse scan file into AccessPointInfo array");
+ Logger.logError("Unable to parse scan file into AccessPointInfo array");
return a;
}
- Utils.logDebug("# of APs found: " + a.length);
+ Logger.logDebug("# of APs found: " + a.length);
return a;
}
+
+ public ConnectionStatus getConnectionStatus() {
+
+ ConnectionStatus s = WpaCli.getConnectionStatus();
+ if (s == null){
+ return null;
+ }
+
+ String ifcfg = getIfconfigString();
+ s.parseIfconfigOutput(ifcfg);
+ return s;
+ }
+
+ private String getIfconfigString(){
+
+ // needs root for accessing encapsulation and hardware address (tested).
+ RootCommand cmd = new RootCommand("ifconfig " + WpaSupplicant.INTERFACE_NAME);
+
+ try {
+ if (cmd.execute() != 0){
+ Logger.logError("FAILED to run ifconfig to obtain interface info.");
+ return null;
+ }
+ } catch (Exception e) {
+ Logger.logError("Exception while running ifconfig.", e);
+ return null;
+ }
+
+ return cmd.getOutput();
+
+ }
@Override
- public abstract boolean connect(AccessPointInfo info);
+ public abstract int connect(AccessPointInfo info);
@Override
public boolean disconnect() {
@@ -70,16 +107,7 @@ public abstract class Engine implements IEngine {
}
- /***
- * returns null if unable to determine connection status for any reason.
- */
- @Override
- public ConnectionStatus getConnectionStatus() {
- return WpaCli.getConnectionStatus();
- }
-
- @Override
- public boolean isInterfaceAvailable(String ifaceName) throws SocketException {
+ public static boolean isInterfaceAvailable(String ifaceName) throws SocketException {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
@@ -93,35 +121,42 @@ public abstract class Engine implements IEngine {
}
- public boolean runDhcpcd() {
+ public int runDhcpcd() throws Exception{
// needs root
// option -w avoids dhcpcd forking to background,
// in order to keep control over its exit code, and be able to wait for it.
// option -A avoids ARP IP checking, we use it to save some seconds in the connection process.
- return RootCommand.executeRootCmd("dhcpcd -w -A " + WpaSupplicant.INTERFACE_NAME);
-
+ // option -t <timeout> sets time out for obtaining a lease.
+ String cmdText = "dhcpcd -w -A -t " + Commons.WAIT_FOR_DHCPCD + " " + WpaSupplicant.INTERFACE_NAME;
+ RootCommand su = new RootCommand(cmdText);
+ return su.execute();
}
- public boolean runDhcpcd(DhcpSettings dhcpConfig) {
+ public int runDhcpcd(DhcpSettings dhcpConfig) throws Exception{
if (dhcpConfig == null || dhcpConfig.useDhcp){
- Utils.logDebug("running dhchpc without dhcp settings, reverting to dhcp");
+ Logger.logDebug("running dhchpc without dhcp settings, reverting to dhcp");
return runDhcpcd();
}
- Utils.logDebug("Running dhcpcd with custom ip settings");
- String cmdMask = "dhcpcd -w -A -S ip_address=%s -S routers=%s %s";
+ Logger.logDebug("Running dhcpcd with custom ip settings");
+ String cmdMask = "dhcpcd -w -A -S ip_address=%s -S routers=%s -t %d %s";
String cmd = String.format(cmdMask,
dhcpConfig.getStaticIPwithMask(),
dhcpConfig.getDefaultGateway(),
+ Commons.WAIT_FOR_DHCPCD,
WpaSupplicant.INTERFACE_NAME);
- return RootCommand.executeRootCmd(cmd);
+ RootCommand su = new RootCommand(cmd);
+ return su.execute();
}
public static boolean killDhcpcd(){
- return RootCommand.executeRootCmd("killall -SIGINT dhcpcd");
+ if (! RootCommand.executeRootCmd("killall -SIGINT dhcpcd")){
+ return false;
+ }
+ return RootCommand.executeRootCmd("rm " + PIDFILE_DHCPCD);
}
public boolean interfaceUp() {
@@ -129,4 +164,5 @@ public abstract class Engine implements IEngine {
return RootCommand.executeRootCmd("ifconfig " + WpaSupplicant.INTERFACE_NAME + " up");
}
+
}
diff --git a/app/src/fil/libre/repwifiapp/network/Engine6p0.java b/app/src/fil/libre/repwifiapp/network/Engine6p0.java
new file mode 100644
index 0000000..c6475e2
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/network/Engine6p0.java
@@ -0,0 +1,315 @@
+//
+// Copyright 2017, 2018 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.network;
+
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.helpers.RootCommand;
+import fil.libre.repwifiapp.helpers.ShellCommand;
+import org.apache.http.conn.util.InetAddressUtils;
+
+public class Engine6p0 extends Engine {
+
+ private Object abortFlagSync = new Object();
+ private boolean abortConnectionSignaled = false;
+
+ @Override
+ public int connect(AccessPointInfo info) {
+
+ WpaSupplicant.kill();
+
+
+ if (info == null) {
+ Logger.logDebug("Engine's connect() received a null AccessPointInfo");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // clear any previously set network
+ if (!destroyNetwork()) {
+ Logger.logDebug("Unable to ndc destroy network");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // clear interface's ip
+ if (!clearAddrs()) {
+ Logger.logDebug("Unable to ndc clearaddrs");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // bring up interface
+ if (!interfaceUp()) {
+ Logger.logDebug("Unable to bring up interface.");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // launch wpa_supplicant specifying our custom configuration and the
+ // socket file
+ if (!WpaSupplicant.start()) {
+ Logger.logDebug("Unable to run wpa start");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // create new network and get network id
+ String netID = WpaCli.createNetworkGetId();
+ if (netID == null) {
+ Logger.logDebug("Unable to fetch network id");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // set network SSID
+ if (!WpaCli.setNetworkSSID(info.getSsid(), netID)) {
+ Logger.logDebug("Failed to set network ssid");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ if (info.isHidden() && !WpaCli.setNetworkScanSSID(netID)) {
+ Logger.logDebug("Failed to set scan_ssid 1 for hidden network.");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // set password (if any)
+ if (!WpaCli.setNetworkPSK(info, netID)) {
+ Logger.logDebug("Failed to set network psk");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // select the network we just created
+ if (!WpaCli.selectNetwork(netID)) {
+ Logger.logDebug("Unable to wpa_cli select network");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // enable the newtork
+ if (!WpaCli.enableNetwork(netID)) {
+ Logger.logDebug("Unable to wpa_cli enable_newtork");
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // kill previous dhchcd instances
+ if (!killDhcpcd()) {
+ Logger.logError("Unable to kill previous instances of dhcpcd");
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // get DHCP
+ Logger.logDebug("Attempt to run dhcpcd..");
+ try {
+
+ int retcode = runDhcpcd(info.getDhcpConfiguration());
+ if (retcode == 1) {
+ Logger.logDebug("Dhcpcd exited on timeout exceeded.");
+ return ConnectionResult.CONN_TIMEOUT;
+
+ } else if (retcode != 0) {
+ Logger.logDebug("Dhcpcd exited with unknown code: " + retcode);
+ return ConnectionResult.CONN_FAILED;
+
+ }
+ } catch (Exception e) {
+ Logger.logError("Exception while executing dhcpcd: ", e);
+ return ConnectionResult.CONN_FAILED;
+ }
+
+ if (!checkAbortSignal())
+ return ConnectionResult.CONN_ABORTED;
+
+ // try to fetch gateway
+ String gw = getGateWayTimeout(Commons.WAIT_FOR_GATEWAY);
+ if (gw == null || !InetAddressUtils.isIPv4Address(gw)) {
+ // failed to get gateway
+ Logger.logDebug("Failed to get gateway");
+ return ConnectionResult.CONN_GW_FAIL;
+ }
+
+ /*
+ * Calls to ndc to set gateway and dns were removed 2018-04-09
+ * Starting from 2018-04-20, RepWifi registers itself as a NetworkAgent.
+ * When we register, all the following steps are performed by
+ * ConnectivityService itself:
+ * - creating a new network
+ * - setting the gateway
+ * - setting DNS
+ * There is no reason to perform those actions on our side via the command line;
+ * it would conflict with ConnectivityService's calls to "ndc"
+ */
+
+ return ConnectionResult.CONN_OK;
+
+ }
+
+ public void abortConnection() {
+ synchronized (abortFlagSync) {
+ this.abortConnectionSignaled = true;
+ }
+ }
+
+ @Override
+ public ConnectionStatus getConnectionStatus() {
+ ConnectionStatus s = super.getConnectionStatus();
+ if (s == null) {
+ return null;
+ }
+
+ s.gateway = this.getGateway();
+
+ return s;
+ }
+
+ private boolean checkAbortSignal() {
+
+ synchronized (abortFlagSync) {
+ if (abortConnectionSignaled) {
+ abortConnectionSignaled = false;
+ Logger.logDebug("Engine received abort connection signal. Aborting connection...");
+ killDhcpcd();
+ disconnect();
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private boolean destroyNetwork() {
+
+ // needs root (tested)
+ return RootCommand.executeRootCmd("ndc network destroy 1");
+ }
+
+ private String getGateWayTimeout(int timeoutMillis) {
+
+ String gw = getGateway();
+ if (gw != null && !gw.trim().isEmpty()) {
+ return gw;
+ }
+
+ Logger.logDebug("Gateway not available.. going into wait loop..");
+
+ // gateway not (yet) available
+ // waits for a maximum of timeoutMillis milliseconds
+ // to let the interface being registered.
+ int msWaited = 0;
+ while (msWaited < timeoutMillis) {
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ return null;
+ }
+ msWaited += 100;
+
+ gw = getGateway();
+ if (gw != null && !gw.trim().isEmpty()) {
+ Logger.logDebug("Gateway found after wait loop!");
+ return gw;
+ }
+ }
+
+ // unable to get gateway
+ Logger.logError("Gateway not found after wait loop.");
+ return null;
+
+ }
+
+ private String getGateway() {
+
+ try {
+
+ // doesn't need root (tested)
+ ShellCommand cmd = new ShellCommand("ip route show dev " + WpaSupplicant.INTERFACE_NAME);
+ if (cmd.execute() != 0) {
+ Logger.logDebug("command failed show route");
+ return null;
+ }
+
+ // read command output
+ String out = cmd.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) {
+ Logger.logError("Error while trying to fetch route", e);
+ return null;
+ }
+
+ }
+
+ private boolean clearAddrs() {
+ // needs root (tested)
+ return RootCommand.executeRootCmd("ndc interface clearaddrs "
+ + WpaSupplicant.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/network/IEngine.java
index 26ebddb..d598550 100644
--- a/app/src/fil/libre/repwifiapp/helpers/IEngine.java
+++ b/app/src/fil/libre/repwifiapp/network/IEngine.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,20 +18,20 @@
//
// ********************************************************************
-package fil.libre.repwifiapp.helpers;
-
-import java.net.SocketException;
+package fil.libre.repwifiapp.network;
public interface IEngine {
public AccessPointInfo[] getAvailableNetworks();
- public boolean connect(AccessPointInfo info);
+ public int connect(AccessPointInfo info);
public boolean disconnect();
public ConnectionStatus getConnectionStatus();
- public boolean isInterfaceAvailable(String ifaceName) throws SocketException;
+ // public boolean isInterfaceAvailable(String ifaceName) throws SocketException;
+ public void abortConnection();
+
}
diff --git a/app/src/fil/libre/repwifiapp/helpers/NetworkButton.java b/app/src/fil/libre/repwifiapp/network/NetworkButton.java
index 7d0bdf9..49c816c 100644
--- a/app/src/fil/libre/repwifiapp/helpers/NetworkButton.java
+++ b/app/src/fil/libre/repwifiapp/network/NetworkButton.java
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
//
// This file is part of RepWifiApp.
//
@@ -18,7 +18,7 @@
//
// ********************************************************************
-package fil.libre.repwifiapp.helpers;
+package fil.libre.repwifiapp.network;
import android.content.Context;
import android.widget.Button;
diff --git a/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java b/app/src/fil/libre/repwifiapp/network/NetworkManager.java
index f78b4a5..4d5635d 100644
--- a/app/src/fil/libre/repwifiapp/helpers/NetworkManager.java
+++ b/app/src/fil/libre/repwifiapp/network/NetworkManager.java
@@ -1,43 +1,45 @@
//
-// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+// Copyright 2017, 2018 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
+// it under the terms of the GNU General public static 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.
+// GNU General public static License for more details.
//
-// You should have received a copy of the GNU General Public License
+// You should have received a copy of the GNU General public static License
// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
//
// ********************************************************************
-package fil.libre.repwifiapp.helpers;
+package fil.libre.repwifiapp.network;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.helpers.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.util.ArrayList;
-public class NetworkManager {
+public abstract class NetworkManager {
- private static final String VERSION_NOTE = "RepWifiStorageVersion: 2.0\n";
+ private static final String VERSION_NOTE = "RepWifiStorageVersion: 2.0";
private static final String F_SEP = "\t";
private static final int NET_MAX_AGE = 1095; // Expressed in days
- private String _knownNetworksFile = null;
+ private static String knownNetworksFile = null;
- public NetworkManager(String networksFilePath) {
- this._knownNetworksFile = networksFilePath;
+ public static void init(String storageFilePath){
+ knownNetworksFile = storageFilePath;
}
-
- private AccessPointInfo getSavedInfo(AccessPointInfo i) {
+
+ private static AccessPointInfo getSavedInfo(AccessPointInfo i) {
if (i == null) {
return null;
@@ -87,7 +89,7 @@ public class NetworkManager {
}
- private boolean saveOrRemove(AccessPointInfo info, boolean save) {
+ private static boolean saveOrRemove(AccessPointInfo info, boolean save) {
AccessPointInfo[] existingNets = getKnownNetworks();
@@ -153,7 +155,7 @@ public class NetworkManager {
}
- private AccessPointInfo getFromStringOld(String savedString) {
+ private static AccessPointInfo getFromStringOld(String savedString) {
if (savedString == null || savedString.trim().equals("")) {
return null;
@@ -194,7 +196,7 @@ public class NetworkManager {
lastusedmillis = Long.parseLong(lastUsed);
} catch (NumberFormatException e) {
// invalid format
- Utils.logError("Invalid time format in network manager \"" + lastUsed
+ Logger.logError("Invalid time format in network manager \"" + lastUsed
+ "\". Network BSSID: " + bssid, e);
}
@@ -216,7 +218,7 @@ public class NetworkManager {
}
- private boolean saveList(AccessPointInfo[] list) {
+ private static boolean saveList(AccessPointInfo[] list) {
try {
@@ -238,63 +240,53 @@ public class NetworkManager {
sb.append(jarr.toString(2));
- return Utils.writeFile(_knownNetworksFile, sb.toString(), true);
+ return Utils.writeFile(knownNetworksFile, sb.toString(), true);
} catch (Exception e) {
- Utils.logError("Exception while saving AccessPointInfo array to JSON-formatted file.",
+ Logger.logError("Exception while saving AccessPointInfo array to JSON-formatted file.",
e);
return false;
}
- /*
- * 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 boolean updateStorageVersion() {
+ public static boolean updateStorageVersion() {
- String[] lines = Utils.readFileLines(_knownNetworksFile);
-
- if (lines == null){
- return false;
- }
-
- if (lines.length == 0) {
- return true;
- }
+ try{
+ String[] lines = Utils.readFileLines(knownNetworksFile);
+
+ if (lines == null){
+ return false;
+ }
+
+ if (lines.length == 0) {
+ return true;
+ }
- if (lines[0].trim().equals(VERSION_NOTE)) {
- return true;
+ if (lines[0].trim().equals(VERSION_NOTE)) {
+ return true;
- } else {
+ } else {
- AccessPointInfo[] infos = getKnownNetworksOld();
- if (infos == null || infos.length == 0) {
- return true;
- }
- return saveList(infos);
+ AccessPointInfo[] infos = getKnownNetworksOld();
+ if (infos == null || infos.length == 0) {
+ return true;
+ }
+ return saveList(infos);
+ }
+ }catch (Exception e){
+ Logger.logError("Exception while trying to update network storage version",e);
+ return false;
}
}
- public AccessPointInfo[] getKnownNetworks() {
+ public static AccessPointInfo[] getKnownNetworks() {
try {
- String fconts = Utils.readFile(_knownNetworksFile);
+ String fconts = Utils.readFile(knownNetworksFile);
if (fconts == null) {
return null;
}
@@ -325,22 +317,22 @@ public class NetworkManager {
return list.toArray(arr);
} catch (Exception e) {
- Utils.logError("Exception while parsing JSON content from storage file.", e);
+ Logger.logError("Exception while parsing JSON content from storage file.", e);
return null;
}
}
- public AccessPointInfo[] getKnownNetworksOld() {
+ public static AccessPointInfo[] getKnownNetworksOld() {
ArrayList<AccessPointInfo> list = new ArrayList<AccessPointInfo>();
- File f = new File(this._knownNetworksFile);
+ File f = new File(knownNetworksFile);
if (!f.exists()) {
return null;
}
- String[] lines = Utils.readFileLines(_knownNetworksFile);
+ String[] lines = Utils.readFileLines(knownNetworksFile);
if (lines == null || lines.length == 0) {
return null;
}
@@ -361,7 +353,7 @@ public class NetworkManager {
}
- public boolean isKnown(AccessPointInfo info) {
+ public static boolean isKnown(AccessPointInfo info) {
AccessPointInfo i = getSavedInfo(info);
if (i == null) {
@@ -372,15 +364,15 @@ public class NetworkManager {
}
- public boolean save(AccessPointInfo info) {
+ public static boolean save(AccessPointInfo info) {
return saveOrRemove(info, true);
}
- public boolean remove(AccessPointInfo info) {
+ public static boolean remove(AccessPointInfo info) {
return saveOrRemove(info, false);
}
- public AccessPointInfo getSavedNetwork(AccessPointInfo i) {
+ public static AccessPointInfo getSavedNetwork(AccessPointInfo i) {
return getSavedInfo(i);
}
diff --git a/app/src/fil/libre/repwifiapp/helpers/WpaCli.java b/app/src/fil/libre/repwifiapp/network/WpaCli.java
index 8bd6561..10f6b7c 100644
--- a/app/src/fil/libre/repwifiapp/helpers/WpaCli.java
+++ b/app/src/fil/libre/repwifiapp/network/WpaCli.java
@@ -1,8 +1,32 @@
-package fil.libre.repwifiapp.helpers;
+//
+// Copyright 2017, 2018 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.network;
+
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.helpers.RootCommand;
public abstract class WpaCli {
- private static final int SCAN_WAIT_INTERVAL = 3;
+ private static final int SCAN_WAIT_INTERVAL = 4;
private static final String BASE_COMMAND = "wpa_cli -p" + WpaSupplicant.SOCKET_DIR + " -P"
+ WpaSupplicant.PID_FILE + " -i" + WpaSupplicant.INTERFACE_NAME;
@@ -23,7 +47,7 @@ public abstract class WpaCli {
}
} catch (Exception e) {
- Utils.logError("Error while creating network", e);
+ Logger.logError("Error while creating network", e);
return null;
}
@@ -34,21 +58,11 @@ public abstract class WpaCli {
try {
// needs root (wpa_cli)
- RootCommand su = new RootCommand(BASE_COMMAND + " 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;
- }
+ return executeCmd(BASE_COMMAND + " set_network " + networkID + " ssid '\"" + ssid
+ + "\"'");
} catch (Exception e) {
- Utils.logError("Error while setting network SSID", e);
+ Logger.logError("Error while setting network SSID", e);
return false;
}
@@ -68,20 +82,10 @@ public abstract class WpaCli {
cmdSetPass = BASE_COMMAND + " 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;
- }
+ return executeCmd(cmdSetPass);
} catch (Exception e) {
- Utils.logError("Error while setting network PSK", e);
+ Logger.logError("Error while setting network PSK", e);
return false;
}
@@ -92,21 +96,10 @@ public abstract class WpaCli {
try {
// needs root (wpa_cli)
- RootCommand su = new RootCommand(BASE_COMMAND + " set_network " + networkID
- + " scan_ssid 1");
- 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;
- }
+ return executeCmd(BASE_COMMAND + " set_network " + networkID + " scan_ssid 1");
} catch (Exception e) {
- Utils.logError("Error while setting network SSID", e);
+ Logger.logError("Error while setting network SSID", e);
return false;
}
}
@@ -116,20 +109,10 @@ public abstract class WpaCli {
try {
// needs root (wpa_cli)
- RootCommand su = new RootCommand(BASE_COMMAND + " 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;
- }
+ return executeCmd(BASE_COMMAND + " select_network " + networkID);
} catch (Exception e) {
- Utils.logError("Error while selecting network", e);
+ Logger.logError("Error while selecting network", e);
return false;
}
@@ -140,21 +123,10 @@ public abstract class WpaCli {
try {
// needs root (wpa_cli)
-
- RootCommand su = new RootCommand(BASE_COMMAND + " 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;
- }
+ return executeCmd(BASE_COMMAND + " enable_network " + networkID);
} catch (Exception e) {
- Utils.logError("Error while enabling network", e);
+ Logger.logError("Error while enabling network", e);
return false;
}
@@ -186,15 +158,10 @@ public abstract class WpaCli {
}
} catch (Exception e) {
- Utils.logError("Error while executing wpa_cli status", e);
+ Logger.logError("Error while executing wpa_cli status", e);
return null;
}
- /*
- * // needs root (for wpa_supplicant and wpa_cli) boolean res =
- * RootCommand.executeRootCmd(); if (!res) { return false; } return res;
- */
-
}
/***
@@ -202,11 +169,11 @@ public abstract class WpaCli {
*/
public static ConnectionStatus getConnectionStatus() {
- Utils.logDebug("called getConnecitonStatus()");
+ Logger.logDebug("called getConnecitonStatus()");
if (!WpaSupplicant.isRunning()) {
// wpa_supplicant is not running.
// unable to determine status.
- Utils.logDebug("wpa not running, cannot get connection status.");
+ Logger.logDebug("wpa not running, cannot get connection status.");
return null;
}
@@ -226,7 +193,7 @@ public abstract class WpaCli {
}
} catch (Exception e) {
- Utils.logError("Error while executing wpa_cli status", e);
+ Logger.logError("Error while executing wpa_cli status", e);
return null;
}
@@ -242,22 +209,44 @@ public abstract class WpaCli {
try {
- RootCommand su = new RootCommand(BASE_COMMAND + " disconnect");
- if (su.execute() == 0) {
- String out = su.getOutput();
- if (out != null && out.trim().replace("\n", "").equals("OK")) {
- return true;
- } else {
- return false;
- }
+ return executeCmd(BASE_COMMAND + " disconnect");
+
+ } catch (Exception e) {
+ Logger.logError("Error while enabling network", e);
+ return false;
+ }
+ }
+
+ public static boolean terminateSupplicant() {
+
+ if (!WpaSupplicant.isRunning()){
+ return true;
+ }
+ try {
+
+ return executeCmd(BASE_COMMAND + " terminate");
+
+ } catch (Exception e) {
+ Logger.logError("Error while enabling network", e);
+ return false;
+ }
+
+ }
+
+ private static boolean executeCmd(String cmdTxt) throws Exception {
+
+ RootCommand su = new RootCommand(cmdTxt);
+ if (su.execute() == 0) {
+ String out = su.getOutput();
+ if (out != null && out.trim().replace("\n", "").equals("OK")) {
+ return true;
} else {
return false;
}
-
- } catch (Exception e) {
- Utils.logError("Error while enabling network", e);
+ } else {
return false;
}
+
}
}
diff --git a/app/src/fil/libre/repwifiapp/helpers/WpaSupplicant.java b/app/src/fil/libre/repwifiapp/network/WpaSupplicant.java
index 1dfe449..d8079b9 100644
--- a/app/src/fil/libre/repwifiapp/helpers/WpaSupplicant.java
+++ b/app/src/fil/libre/repwifiapp/network/WpaSupplicant.java
@@ -1,4 +1,27 @@
-package fil.libre.repwifiapp.helpers;
+//
+// Copyright 2017, 2018 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.network;
+
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.helpers.RootCommand;
public abstract class WpaSupplicant {
@@ -6,7 +29,7 @@ public abstract class WpaSupplicant {
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 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";
@@ -17,14 +40,17 @@ public abstract class WpaSupplicant {
+ " -I" + OVERLAY_FILE + " -e" + ENTROPY_FILE;
public static boolean start() {
-
- Utils.logDebug("startWpaSupplicant():");
-
+
+ Logger.logDebug("startWpaSupplicant():");
+ if (isRunning()){
+ return true;
+ }
+
// needs root (for wpa_supplicant)
if (RootCommand.executeRootCmd(BASE_COMMNAD)) {
return true;
} else {
- Utils.logDebug("Failed to start wpa");
+ Logger.logDebug("Failed to start wpa");
return false;
}
@@ -54,7 +80,7 @@ public abstract class WpaSupplicant {
}
} catch (Exception e) {
- Utils.logError("Exception during isWpaSupplicantRunning()", e);
+ Logger.logError("Exception during isWpaSupplicantRunning()", e);
retval = false;
}
diff --git a/app/src/fil/libre/repwifiapp/service/Channel.java b/app/src/fil/libre/repwifiapp/service/Channel.java
new file mode 100644
index 0000000..856c88d
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/service/Channel.java
@@ -0,0 +1,148 @@
+//
+// Copyright 2017, 2018 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.service;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import fil.libre.repwifiapp.ActivityLauncher;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.ConnectionResult;
+import fil.libre.repwifiapp.network.ConnectionStatus;
+
+public class Channel {
+
+ public static final String PAYLOAD_APINFO = ActivityLauncher.EXTRA_APINFO;
+ public static final String PAYLOAD_CONNSTATUS = ActivityLauncher.EXTRA_CONSTATUS;
+ public static final String PAYLOAD_CONNRES = ActivityLauncher.EXTRA_CONNRES;
+ public static String PAYLOAD_PREFKEY = "PrefKey";
+
+ private Messenger src;
+ private Messenger dest;
+ private Context context;
+
+ public Channel(Context context, Messenger destination, Messenger source) {
+ this.context = context;
+ this.dest = destination;
+ this.src = source;
+ }
+
+ public Channel(Context context, Messenger destination) {
+ this(context, destination, null);
+ }
+
+ public boolean sendMsg(int what) {
+ return sendMsg(what, (Parcelable) null, null);
+ }
+
+ public boolean sendMsg(int what, Parcelable payload, String payloadKey) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(payloadKey, payload);
+ return sendMsg(what, bundle, 0);
+ }
+
+ public boolean sendMsg(int what, Parcelable[] payload, String payloadKey) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArray(payloadKey, payload);
+ return sendMsg(what, bundle, 0);
+ }
+
+ public boolean sendMsg(int what, Bundle b, int arg1) {
+
+ if (dest == null){
+ Logger.logError("Tried to send message but destination messenger is null. What: " + what);
+ return false;
+ }
+
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = arg1;
+
+ if (src != null) {
+ msg.replyTo = src;
+ }
+
+ if (b != null) {
+ msg.setData(b);
+ }
+
+ try {
+ dest.send(msg);
+ return true;
+ } catch (RemoteException e) {
+ Logger.logError("RemoteException while trying to send message: " + msg.toString()
+ + " to recipient: " + dest.toString(), e);
+ return false;
+ }
+ }
+
+ public ConnectionResult getConnectionResultPayload(Message msg){
+ return (ConnectionResult) getPayload(msg, PAYLOAD_CONNRES);
+ }
+
+ public ConnectionStatus getConnectionStatusPayload(Message msg){
+ return (ConnectionStatus) getPayload(msg, PAYLOAD_CONNSTATUS);
+ }
+
+ public AccessPointInfo getAccessPointInfoPayload(Message msg){
+ return (AccessPointInfo) getPayload(msg, PAYLOAD_APINFO);
+ }
+
+ public String getStringPayload(Message msg, String key){
+ Bundle b = msg.getData();
+ if (b == null) {
+ return null;
+ }
+ return b.getString(key);
+ }
+
+
+ private Parcelable getPayload(Message msg, String key) {
+
+ Bundle b = msg.getData();
+ if (b == null) {
+ return null;
+ }
+
+ b.setClassLoader(context.getClassLoader());
+ return b.getParcelable(key);
+
+ }
+
+
+ public AccessPointInfo[] getApinfoArrayPayload(Message msg) {
+
+ Bundle b = msg.getData();
+ if (b == null) {
+ return null;
+ }
+
+ b.setClassLoader(context.getClassLoader());
+ Parcelable[] p = b.getParcelableArray(PAYLOAD_APINFO);
+ return AccessPointInfo.fromParcellableArray(p);
+ }
+
+
+}
diff --git a/app/src/fil/libre/repwifiapp/service/ConnectionManagementService.java b/app/src/fil/libre/repwifiapp/service/ConnectionManagementService.java
new file mode 100644
index 0000000..2f70306
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/service/ConnectionManagementService.java
@@ -0,0 +1,720 @@
+//
+// Copyright 2017, 2018 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.service;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import fil.libre.repwifiapp.Commons;
+import fil.libre.repwifiapp.Prefs;
+import fil.libre.repwifiapp.R;
+import fil.libre.repwifiapp.Utils;
+import fil.libre.repwifiapp.activities.MainActivity;
+import fil.libre.repwifiapp.fwproxies.LinkAddressProxy;
+import fil.libre.repwifiapp.fwproxies.LinkPropertiesProxy;
+import fil.libre.repwifiapp.fwproxies.NetworkCapabilitiesProxy;
+import fil.libre.repwifiapp.fwproxies.NetworkInfoProxy;
+import fil.libre.repwifiapp.fwproxies.RepWifiNetworkAgent;
+import fil.libre.repwifiapp.fwproxies.RouteInfoProxy;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.AccessPointInfo;
+import fil.libre.repwifiapp.network.ConnectionResult;
+import fil.libre.repwifiapp.network.ConnectionStatus;
+import fil.libre.repwifiapp.network.Engine6p0;
+import fil.libre.repwifiapp.network.IEngine;
+import fil.libre.repwifiapp.network.NetworkManager;
+import fil.libre.repwifiapp.network.WpaCli;
+import fil.libre.repwifiapp.network.WpaSupplicant;
+import fil.libre.repwifiapp.service.StatusManager.ConnectionStatusChangeListener;
+import org.apache.http.conn.util.InetAddressUtils;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+
+public class ConnectionManagementService extends Service implements ConnectionStatusChangeListener {
+
+ public static final String LOG_TAG_SERVICE = "RepWifiConnectionManagementService";
+
+ public static final String ACTION_DOMAIN = "fil.libre.repwifiapp.ConnectionService";
+ public static final String ACTION_CONNECT = ACTION_DOMAIN + ".ACTION_CONNECT";
+ public static final String ACTION_DISCONNECT = ACTION_DOMAIN + ".ACTION_DISCONNECT";
+ public static final String ACTION_VOID = ACTION_DOMAIN + ".ACTION_VOID";
+
+ public static final int MSG_BASE = 0;
+ public static final int CMD_START_CONNECT = MSG_BASE + 1;
+ public static final int CMD_ABORT_CONNECTION = MSG_BASE + 2;
+ public static final int CMD_DISCONNECT = MSG_BASE + 3;
+ public static final int CMD_GET_AVAILABLE_NETWORKS = MSG_BASE + 4;
+ public static final int CMD_START_MONITOR_CONNECTION_STATUS = MSG_BASE + 5;
+ public static final int CMD_STOP_MONITOR_CONNECTION_STATUS = MSG_BASE + 6;
+ public static final int CMD_STATUS_UPDATE = MSG_BASE + 7;
+ public static final int CMD_AUTOCONNECT = MSG_BASE + 8;
+ public static final int CMD_CLIENT_UNBINDING = MSG_BASE + 9;
+
+ /**
+ * TODO:
+ * Remove this command when a better model for the application's settings is
+ * implemented using @ContentProvider.
+ * For now, the UI will use this command to signal the service's process
+ * when a change is detected in the @SharedPreferences.
+ * A @ContentProvider should be used instead, to properly share the
+ * application's settings between the UI process and the background service.
+ * This command should be removed especially if the service is ever made
+ * "exported", i.e. available to other applications, in order to prevent
+ * external apps from tampering with the inner state of the service.
+ */
+ public static final int CMD_PREF_CHANGED = MSG_BASE + 10;
+
+ public static final int MSG_STATUS_CHANGE = MSG_BASE + 1001;
+ public static final int MSG_CONNECTION_RESULT = MSG_BASE + 1002;
+ public static final int MSG_AVAILABLE_NETWORKS = MSG_BASE + 1003;
+ public static final int MSG_AUTOCONNECT_REPORT = MSG_BASE + 1004;
+ public static final int MSG_DISCONNECT_REPORT = MSG_BASE + 1005;
+
+ /**
+ * This message is returned to a calling client, upon reception of a Command
+ * which the caller is not allowed to request, the original command id is
+ * reported in "arg1" field of this reply message.
+ */
+ public static final int MSG_PERMISSION_DENIED = MSG_BASE + 1403;
+
+ public static final int CHECK_STATUS_INTERVAL_SECS = 15;
+ public static final String PLACEHOLDER_CHECK_STATUS_INTERVAL = "[CHK_STS_INTERVAL]";
+
+ public static final String LOG_TAG_NETWORKAGENT = "RepWifiNetworkAgent";
+
+ private RepWifiNetworkAgent currentNetworkAgent = null;
+ private IEngine eng = null;
+ private StatusManager smonitor;
+ private ArrayList<Channel> statusWatchers = new ArrayList<Channel>();
+
+ private final Messenger messenger = new Messenger(new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+
+ Channel channel = new Channel(ConnectionManagementService.this, msg.replyTo);
+
+ switch (msg.what) {
+ case CMD_START_CONNECT:
+
+ AccessPointInfo info = channel.getAccessPointInfoPayload(msg);
+ if (info == null) {
+ Logger.logError("Received connect message without valid AccessPointInfo.");
+ } else {
+ connect(info, channel);
+ }
+ break;
+
+ case CMD_ABORT_CONNECTION:
+ abortConnection();
+ break;
+
+ case CMD_DISCONNECT:
+ disconnect(channel);
+ break;
+
+ case CMD_GET_AVAILABLE_NETWORKS:
+ getAvailableNetworks(channel);
+ break;
+
+ case CMD_START_MONITOR_CONNECTION_STATUS:
+ startMonitoringNetworkStatus(channel);
+ break;
+
+ case CMD_STOP_MONITOR_CONNECTION_STATUS:
+ stopMonitoringNetworkStatus(channel);
+ break;
+
+ case CMD_STATUS_UPDATE:
+ getStatus(channel);
+ break;
+
+ case CMD_CLIENT_UNBINDING:
+ onClientUnbinding(channel);
+ break;
+
+ case CMD_PREF_CHANGED:
+ String prefKey = channel.getStringPayload(msg, Channel.PAYLOAD_PREFKEY);
+ onPreferenceChanged(prefKey);
+ break;
+
+ default:
+ Logger.logError("Received message with unknown what: " + msg.what);
+ }
+ }
+
+ });
+
+ public ConnectionManagementService() {
+ }
+
+ @Override
+ public void onCreate() {
+
+ Commons.init(getApplicationContext());
+ initEngine();
+
+ Logger.APP_NAME = LOG_TAG_SERVICE;
+ Logger.setLogPriority(Prefs.getLogPriority(getApplicationContext()));
+
+ // Reset wpa_supplicant when the service is first run
+ // This is needed in case the internal WifiManager is controlling the
+ // current instance of wpa_supplicant.
+ Utils.killBackEnd(getApplicationContext(), true);
+
+ smonitor = new StatusManager(eng, this);
+
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+
+ if (intent == null) {
+ Logger.logDebug("[WRN]Service started with null intent!");
+ return START_STICKY;
+ }
+
+ String a = intent.getAction();
+
+ if (a == null) {
+ Logger.logDebug("[WRN] Service started with null action");
+ return START_STICKY;
+ }
+
+ Logger.logDebug("Service started with action: " + a);
+
+ if (a == ACTION_CONNECT) {
+ handleActionConnect(intent.getExtras());
+
+ } else if (a == ACTION_DISCONNECT) {
+ handleActionDisconnect();
+
+ } else if (a == ACTION_VOID) {
+ // Just start the service and wait for bindings
+ Logger.logDebug("Started with void action.");
+ } else {
+ Logger.logError("Unknown action " + a);
+ }
+
+ getStatus();
+ return START_STICKY;
+
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ smonitor.unsetListener();
+ }
+
+ private void handleActionConnect(Bundle xtras) {
+
+ if (xtras == null || xtras.containsKey(Channel.PAYLOAD_APINFO)) {
+ Logger.logError("Requested action connect without AccespointInfo extra!");
+ return;
+ }
+
+ try {
+ AccessPointInfo info = (AccessPointInfo) xtras.get(Channel.PAYLOAD_APINFO);
+
+ connect(info);
+
+ } catch (Exception e) {
+ Logger.logError("Exception while extracting AccessPointInfo object from start intent's extras.",
+ e);
+ }
+
+ }
+
+ private void handleActionDisconnect() {
+ disconnect();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return this.messenger.getBinder();
+ }
+
+ private ConnectionResult connect(AccessPointInfo info, Channel callback) {
+
+ initEngine();
+
+ int result = eng.connect(info);
+ ConnectionResult connectionResult = new ConnectionResult(result);
+ ConnectionStatus status = null;
+
+ if (result == ConnectionResult.CONN_OK) {
+
+ Logger.logDebug("Result code CONN_OK");
+
+ status = smonitor.getConnectionStatus();
+ connectionResult.setStatus(status);
+
+ if (info.needsPassword()) {
+
+ if (status != null) {
+ // update APinfo with the right BSSID
+ info.setBssid(status.BSSID);
+ }
+
+ // Save network
+ if (NetworkManager.save(info)) {
+ Logger.logDebug("Network saved: " + status.SSID);
+
+ } else {
+ Logger.logError("FAILED saving network: " + status.SSID);
+
+ }
+
+ }
+
+ }
+
+ reportConnectionResult(connectionResult, callback);
+ return connectionResult;
+ }
+
+ public ConnectionResult connect(AccessPointInfo info) {
+ return connect(info, null);
+ }
+
+ /**
+ * Attempts to connect to any nearby known network if found.
+ *
+ * @return Returns null if a network is found and connected.
+ * Returns an empty array if no network is found.
+ * Returns an array of AccessPointInfo if no nearby network is
+ * known.
+ */
+ public AccessPointInfo[] autoConnect() {
+ return autoConnect(null);
+ }
+
+ private AccessPointInfo[] autoConnect(Channel callback) {
+ try {
+
+ AccessPointInfo[] nets = eng.getAvailableNetworks();
+ if (nets == null || nets.length == 0) {
+ nets = new AccessPointInfo[] {};
+ }
+
+ for (AccessPointInfo i : nets) {
+
+ if (NetworkManager.isKnown(i)) {
+ connect(i, null);
+ nets = null;
+ }
+
+ }
+
+ // if no network is known, return available networks:
+ if (callback != null) {
+ reportAutoconnectResult(nets, callback);
+ }
+ return nets;
+
+ } catch (Exception e) {
+ Logger.logError("Error while autoconnecting", e);
+ return null;
+ }
+ }
+
+ private ConnectionStatus getStatus(Channel callback) {
+
+ ConnectionStatus status = smonitor.getConnectionStatus();
+
+ if (callback != null) {
+ callback.sendMsg(MSG_STATUS_CHANGE, status, Channel.PAYLOAD_CONNSTATUS);
+ }
+ return status;
+
+ }
+
+ public ConnectionStatus getStatus() {
+ return getStatus(null);
+ }
+
+ public void abortConnection() {
+ initEngine();
+ eng.abortConnection();
+ }
+
+ public boolean disconnect() {
+ return disconnect(null);
+ }
+
+ private boolean disconnect(Channel callback) {
+
+ initEngine();
+ boolean res = eng.disconnect();
+ ConnectionStatus status = getStatus();
+
+ if (callback != null) {
+ callback.sendMsg(MSG_DISCONNECT_REPORT, status, Channel.PAYLOAD_CONNSTATUS);
+ }
+
+ return res;
+ }
+
+ private AccessPointInfo[] getAvailableNetworks(Channel callback) {
+ initEngine();
+ AccessPointInfo[] nets = eng.getAvailableNetworks();
+ if (callback != null) {
+ callback.sendMsg(MSG_AVAILABLE_NETWORKS, nets, Channel.PAYLOAD_APINFO);
+ }
+ return nets;
+ }
+
+ public AccessPointInfo[] getAvailableNetworks() {
+ return getAvailableNetworks(null);
+ }
+
+ private void initEngine() {
+ if (eng == null) {
+ eng = new Engine6p0();
+ }
+ }
+
+ private void reportConnectionResult(ConnectionResult result, Channel callback) {
+ callback.sendMsg(MSG_CONNECTION_RESULT, result, Channel.PAYLOAD_CONNRES);
+ }
+
+ private void reportAutoconnectResult(AccessPointInfo[] infos, Channel callback) {
+ callback.sendMsg(MSG_AUTOCONNECT_REPORT, infos, Channel.PAYLOAD_APINFO);
+ }
+
+ private static final int NOTIFICATION_ID = 1;
+
+ @Override
+ public void onConnectionStatusChange(ConnectionStatus status) {
+
+ Logger.logDebug("Received connection status changed");
+ notifyWifiState(status);
+ updateNotification(status);
+ reportNetworkStatus(status);
+
+ }
+
+ private void onClientUnbinding(Channel client) {
+
+ if (client == null) {
+ return;
+ }
+
+ Logger.logDebug("Processing client unbinding.. ");
+ stopMonitoringNetworkStatus(client);
+
+ }
+
+ private boolean notifyWifiState(ConnectionStatus status) {
+
+ try {
+
+ if (status == null) {
+ Logger.logDebug("Received null ConnectionStatus; using dummy status disconnected.");
+ status = ConnectionStatus.getDummyDisconnected();
+ }
+
+ Logger.logDebug("Notifying wifi state with status object: " + status.toString());
+
+ NetworkInfoProxy ni = NetworkInfoProxy.getForWifi();
+ NetworkCapabilitiesProxy nc = new NetworkCapabilitiesProxy();
+ LinkPropertiesProxy lp = new LinkPropertiesProxy();
+ lp.setInterfaceName(WpaSupplicant.INTERFACE_NAME);
+
+ if (status.isConnected()) {
+
+ ni.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+ ni.setIsAvailable(true);
+
+ if (!lp.addLinkAddress(new LinkAddressProxy(status.getInetAddress(), status
+ .getSubnetMaskInt()))) {
+ Logger.logError("Failed to add LinkAddress to LinkProperties.");
+ return false;
+ }
+
+ if (!lp.addRoute(new RouteInfoProxy(status.getGatewayInetAddress(),
+ WpaSupplicant.INTERFACE_NAME))) {
+ Logger.logError("Failed to add route to linkProperties");
+ return false;
+ }
+
+ InetAddress[] dnss = getUseableDnss(status.gateway);
+
+ if (dnss == null || dnss.length == 0) {
+ Logger.logError("Received null or empty dns array");
+ return false;
+ }
+
+ for (InetAddress d : dnss) {
+ if (d != null && !lp.addDnsServer(d)) {
+ Logger.logError("Failed to add dns to LinkProperties.");
+ return false;
+ }
+ }
+
+ nc.addCapability(NetworkCapabilitiesProxy.NET_CAPABILITY_NOT_METERED);
+ nc.addCapability(NetworkCapabilitiesProxy.NET_CAPABILITY_INTERNET);
+
+ if (!agentIsAvailable()) {
+ Logger.logDebug("Willing to communicate netwtork connection, but no NetworkAgent available. Creating new NetworkAgent..");
+ createNetworkAgent(ni, lp, nc, 100);
+ }
+
+ } else if (agentIsAvailable()) {
+ ni.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+ ni.setIsAvailable(true);
+
+ } else {
+ // status is "disconnected" and we have no active communication
+ // channel with the ConnectivityService.
+ // no need to establish a new channel just to communicate
+ // disconnection:
+ // ConnectivityService should know we're disconnected already.
+ return true;
+ }
+
+ Logger.logDebug("About to call NetworkAgent.sendNetworkIngfo() connected="
+ + status.isConnected());
+
+ currentNetworkAgent.sendNetworkInfo(ni.getNetworkInfo());
+ Logger.logDebug("Called NetworkAgent.sendNetworkIngfo()..");
+
+ return true;
+
+ } catch (Exception e) {
+ Logger.logError("FAIL registerNetworkAgent", e);
+ return false;
+ }
+
+ }
+
+ private boolean agentIsAvailable() {
+ return (currentNetworkAgent != null && currentNetworkAgent.isChannellConnected());
+ }
+
+ private int createNetworkAgent(NetworkInfoProxy ni, LinkPropertiesProxy lp,
+ NetworkCapabilitiesProxy nc, int score) {
+
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ Logger.logDebug("About to create new RepWifiNetworkAgent...");
+ try {
+
+ currentNetworkAgent = new RepWifiNetworkAgent(Looper.myLooper(),
+ getApplicationContext().getApplicationContext(), LOG_TAG_NETWORKAGENT,
+ ni.getNetworkInfo(), nc, lp, score);
+ Logger.logDebug("Created RepWifiNetworkAgent, netId: " + currentNetworkAgent.netId);
+ return currentNetworkAgent.netId;
+
+ } catch (Exception e) {
+ Logger.logError("Exception while creating RepWifiNetworkAgent", e);
+ return -1;
+ }
+
+ }
+
+ private String[] getConfiguredDnss() {
+
+ // no more default DNS, it's a stupid thing to do.
+ // instead, default to empty dns (using gateway as dns)
+ // it should be up to the user to chose their own dns explicitly.
+ String dns1 = Prefs.getString(getApplicationContext(),Prefs.PREF_DNS_1, "");
+ String dns2 = Prefs.getString(getApplicationContext(), Prefs.PREF_DNS_2, "");
+
+ if (dns1 == null || dns1.isEmpty()) {
+ return null;
+ }
+
+ return new String[] { dns1, dns2 };
+
+ }
+
+ private InetAddress[] getUseableDnss(String gateway) {
+
+ String[] dnss = getConfiguredDnss();
+
+ if (dnss == null || dnss.length == 0) {
+ // the DNS setting has been left blank
+ // try to use the gateway as dns
+
+ if (gateway == null || gateway.length() == 0) {
+ // no possible DNS.
+ return null;
+ }
+
+ dnss = new String[] { gateway, null };
+
+ }
+
+ InetAddress d1 = null;
+ InetAddress d2 = null;
+
+ if (InetAddressUtils.isIPv4Address(dnss[0])) {
+ try {
+
+ d1 = InetAddress.getByName(dnss[0]);
+
+ if (dnss[1] != null && InetAddressUtils.isIPv4Address(dnss[1])) {
+
+ d2 = InetAddress.getByName(dnss[1]);
+
+ }
+
+ } catch (UnknownHostException e) {
+ Logger.logError("Exception while parsing dns address!", e);
+ return null;
+ }
+
+ return new InetAddress[] { d1, d2 };
+
+ } else {
+ Logger.logError("Wrong dns1 format!");
+ return null;
+ }
+
+ }
+
+ private void updateNotification(ConnectionStatus status) {
+
+ if (status == null) {
+ status = WpaCli.getConnectionStatus();
+ }
+
+ Notification.Builder builder = new Notification.Builder(getApplicationContext());
+
+ Intent intent = new Intent(getApplicationContext(), MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent,
+ 0);
+ builder.setContentIntent(pendingIntent);
+
+ int iconId = R.drawable.ic_stat_discon;
+ String msg = "RepWifi";
+ if (status != null) {
+ if (status.isConnected()) {
+ iconId = R.drawable.ic_stat_repwifi;
+ msg += " - " + status.SSID;
+ } else {
+ msg += " - " + status.wpaStatus;
+ }
+
+ }
+
+ builder.setSmallIcon(iconId);
+
+ builder.setContentTitle(msg);
+ builder.setContentText(getString(R.string.msg_touch_open));
+
+ Notification n = builder.build();
+ n.flags |= Notification.FLAG_NO_CLEAR;
+
+ NotificationManager notificationManager = (NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE);
+ notificationManager.notify(NOTIFICATION_ID, n);
+
+ }
+
+ private void onPreferenceChanged(String prefName) {
+
+ if (prefName == null) {
+ Logger.logError("Received preference changed event, but prefName is null!");
+ return;
+ }
+
+ if (prefName.equals(Prefs.PREF_MONITOR_NET_STATE)) {
+ setMonitorNetworkStatus(Prefs.isNetworkStateMonitoringEnabled(getApplicationContext()));
+
+ } else if (prefName.equals(Prefs.PREF_LOG_LEVEL)) {
+ Logger.setLogPriority(Prefs.getLogPriority(getApplicationContext()));
+
+ }
+
+ }
+
+ private boolean monitoringExplicitlyEnabled = false;
+
+ private void setMonitorNetworkStatus(boolean enabled) {
+
+ monitoringExplicitlyEnabled = enabled;
+ if (enabled) {
+ startMonitoringNetworkStatus(null);
+
+ } else {
+ stopMonitoringNetworkStatus(null);
+
+ }
+ }
+
+ private void startMonitoringNetworkStatus(Channel watcher) {
+
+ synchronized (statusWatchers) {
+ if (watcher != null && !statusWatchers.contains(watcher)) {
+ Logger.logDebug("Added watcher for network status: " + watcher.toString());
+ statusWatchers.add(watcher);
+ }
+ }
+
+ smonitor.startPolling(CHECK_STATUS_INTERVAL_SECS * 1000);
+
+ }
+
+ private void stopMonitoringNetworkStatus(Channel watcher) {
+
+ synchronized (statusWatchers) {
+
+ if (watcher != null && statusWatchers.remove(watcher)) {
+ Logger.logDebug("Removed watcher for network status: " + watcher.toString());
+ }
+
+ if (statusWatchers.isEmpty() && !monitoringExplicitlyEnabled) {
+ if (smonitor != null) {
+ smonitor.stopPolling();
+ }
+ }
+ }
+
+ }
+
+ private void reportNetworkStatus(ConnectionStatus status) {
+
+ synchronized (statusWatchers) {
+
+ for (Channel m : statusWatchers) {
+ if (!m.sendMsg(MSG_STATUS_CHANGE, status, Channel.PAYLOAD_CONNSTATUS)) {
+ // remove recipient from watchers as it's not able to
+ // receive messages anymore
+ statusWatchers.remove(m);
+ }
+ }
+ }
+ }
+
+}
diff --git a/app/src/fil/libre/repwifiapp/service/StatusManager.java b/app/src/fil/libre/repwifiapp/service/StatusManager.java
new file mode 100644
index 0000000..1894a87
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/service/StatusManager.java
@@ -0,0 +1,139 @@
+//
+// Copyright 2018 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.service;
+
+import android.os.Handler;
+import fil.libre.repwifiapp.helpers.Logger;
+import fil.libre.repwifiapp.network.ConnectionStatus;
+import fil.libre.repwifiapp.network.IEngine;
+
+public class StatusManager {
+
+ public interface ConnectionStatusChangeListener {
+
+ public void onConnectionStatusChange(ConnectionStatus status);
+
+ }
+
+ private Handler handler;
+ private Runnable runnable;
+ private boolean isStarted = false;
+ private int interval = 30000;
+ private ConnectionStatus currentStatus;
+
+ private IEngine eng = null;
+ private ConnectionStatusChangeListener listener = null;
+
+ public StatusManager(IEngine engine, ConnectionStatusChangeListener listener) {
+
+ this.listener = listener;
+ handler = new Handler();
+ currentStatus = ConnectionStatus.getDummyDisconnected();
+ eng = engine;
+
+ }
+
+ public ConnectionStatus getConnectionStatus() {
+ updateStatus();
+ return currentStatus;
+ }
+
+ private void updateStatus() {
+
+ synchronized (currentStatus) {
+
+ ConnectionStatus nextStatus = eng.getConnectionStatus();
+
+ if (nextStatus == null) {
+ nextStatus = ConnectionStatus.getDummyDisconnected();
+ }
+
+ if (! currentStatus.equals(nextStatus) && listener != null) {
+ listener.onConnectionStatusChange(nextStatus);
+ }
+
+ this.currentStatus = nextStatus;
+
+ }
+
+ }
+
+ public void startPolling(int intervalMs) {
+
+ synchronized (this) {
+
+ if (isStarted) {
+ Logger.logDebug("Called StatusMonitor.start() but monitor already started.. ignoring..");
+ return;
+ }
+
+ isStarted = true;
+
+ this.interval = intervalMs;
+
+ runnable = new Runnable() {
+ @Override
+ public void run() {
+
+ try {
+
+ Logger.logDebug("Polling enabled, connection status update triggered.");
+ updateStatus();
+
+ } catch (Exception e) {
+ Logger.logError("Exception while executing recurring network status update..",
+ e);
+ }
+
+ handler.postDelayed(this, interval);
+ }
+ };
+
+ Logger.logDebug("Starting recurring network status update every " + interval + " ms");
+ handler.postDelayed(runnable, interval);
+ }
+
+ }
+
+ public void stopPolling() {
+
+ synchronized (this) {
+
+ if (!isStarted) {
+ Logger.logDebug("Called StatusMonitor.stop() but already stopped.. ignoring..");
+ return;
+ }
+
+ try {
+ handler.removeCallbacks(runnable);
+ Logger.logDebug("Stopped recurring network status update.");
+ } finally {
+ isStarted = false;
+ }
+ }
+
+ }
+
+ public void unsetListener(){
+ stopPolling();
+ this.listener = null;
+ }
+
+}