diff --git a/app/src/main/java/eu/faircode/netguard/ActivitySettings.java b/app/src/main/java/eu/faircode/netguard/ActivitySettings.java
index 151ca045..23f13f94 100644
--- a/app/src/main/java/eu/faircode/netguard/ActivitySettings.java
+++ b/app/src/main/java/eu/faircode/netguard/ActivitySettings.java
@@ -109,6 +109,11 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere
else if ("whitelist_roaming".equals(name))
SinkholeService.reload("other", this);
+ else if ("metered_2g".equals(name) ||
+ "metered_3g".equals(name) ||
+ "metered_4g".equals(name))
+ SinkholeService.reload(null, this);
+
else if ("manage_system".equals(name))
SinkholeService.reload(null, this);
diff --git a/app/src/main/java/eu/faircode/netguard/SinkholeService.java b/app/src/main/java/eu/faircode/netguard/SinkholeService.java
index baf473f5..e9b1db3f 100644
--- a/app/src/main/java/eu/faircode/netguard/SinkholeService.java
+++ b/app/src/main/java/eu/faircode/netguard/SinkholeService.java
@@ -38,6 +38,8 @@ import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
@@ -291,6 +293,20 @@ public class SinkholeService extends VpnService {
}
};
+ private PhoneStateListener phoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onDataConnectionStateChanged(int state, int networkType) {
+ Log.i(TAG, "Data connection state changed state=" + state + " network type=" + networkType);
+ if (state == TelephonyManager.DATA_CONNECTED) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
+ if (!prefs.getBoolean("metered_2g", true) ||
+ !prefs.getBoolean("metered_3g", true) ||
+ !prefs.getBoolean("metered_4g", true))
+ reload(null, SinkholeService.this);
+ }
+ }
+ };
+
private BroadcastReceiver packageAddedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -327,6 +343,9 @@ public class SinkholeService extends VpnService {
ifPackage.addAction(Intent.ACTION_PACKAGE_ADDED);
ifPackage.addDataScheme("package");
registerReceiver(packageAddedReceiver, ifPackage);
+
+ TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+ tm.listen(phoneStateListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
}
@Override
@@ -354,6 +373,9 @@ public class SinkholeService extends VpnService {
unregisterReceiver(connectivityChangedReceiver);
unregisterReceiver(packageAddedReceiver);
+ TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+ tm.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
+
if (vpn != null) {
stopDebug();
stopVPN(vpn);
diff --git a/app/src/main/java/eu/faircode/netguard/Util.java b/app/src/main/java/eu/faircode/netguard/Util.java
index 7c26996c..f0b1d4f0 100644
--- a/app/src/main/java/eu/faircode/netguard/Util.java
+++ b/app/src/main/java/eu/faircode/netguard/Util.java
@@ -22,6 +22,7 @@ package eu.faircode.netguard;
import android.app.ApplicationErrorReport;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
@@ -37,6 +38,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
+import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
@@ -75,7 +77,38 @@ public class Util {
public static boolean isMetered(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- return cm.isActiveNetworkMetered();
+ boolean metered = cm.isActiveNetworkMetered();
+ NetworkInfo ni = cm.getActiveNetworkInfo();
+ if (metered && ni != null && ni.getType() == ConnectivityManager.TYPE_MOBILE) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ switch (ni.getSubtype()) {
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ case TelephonyManager.NETWORK_TYPE_IDEN:
+ return prefs.getBoolean("metered_2g", true);
+
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
+ case TelephonyManager.NETWORK_TYPE_EVDO_0:
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ return prefs.getBoolean("metered_3g", true);
+
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ return prefs.getBoolean("metered_4g", true);
+
+ default:
+ Log.w(Util.class.getName(), "Unknown network subtype=" + ni.getSubtype());
+ }
+ }
+
+ return metered;
}
public static boolean isInteractive(Context context) {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f4883df1..d50cde82 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -17,6 +17,9 @@ These issues are caused by bugs in Android, or in the software provided by the m
Block Wi-Fi by default
Block mobile by default
Block roaming by default
+ 2G is metered
+ 3G is metered
+ 4G is metered
Manage system applications
Use dark theme
Show state indicators
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index ea58fc04..410cf1d0 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -12,6 +12,18 @@
android:defaultValue="true"
android:key="whitelist_roaming"
android:title="@string/setting_whitelist_roaming" />
+
+
+