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" /> + + +