diff --git a/app/build.gradle b/app/build.gradle index b0771f5..a52bcdd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,7 +41,7 @@ android { minSdkVersion rootProject.minSdkVersion targetSdkVersion rootProject.sdkVersion versionCode 17 - versionName "0.0.3.5" + versionName "0.0.3.6" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" javaCompileOptions { diff --git a/app/src/main/java/com/github/cgg/clasha/GlobalSettingsPreferenceFragment.kt b/app/src/main/java/com/github/cgg/clasha/GlobalSettingsPreferenceFragment.kt index 1ee15c1..22a9274 100644 --- a/app/src/main/java/com/github/cgg/clasha/GlobalSettingsPreferenceFragment.kt +++ b/app/src/main/java/com/github/cgg/clasha/GlobalSettingsPreferenceFragment.kt @@ -1,17 +1,20 @@ package com.github.cgg.clasha +import android.os.Build import android.os.Bundle import android.text.Editable import android.text.TextUtils import android.widget.EditText import androidx.preference.Preference import androidx.preference.PreferenceCategory +import androidx.preference.SwitchPreference import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.ToastUtils import com.github.cgg.clasha.bg.BaseService import com.github.cgg.clasha.data.DataStore import com.github.cgg.clasha.utils.Key import com.github.cgg.clasha.utils.getGson +import com.github.cgg.clasha.utils.remove import com.github.cgg.clasha.widget.EditTextDialog import com.takisoft.preferencex.AutoSummaryEditTextPreference import com.takisoft.preferencex.PreferenceFragmentCompat @@ -46,6 +49,11 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { val dnsMode = findPreference(Key.dnsMode) val clashLoglevel = findPreference(Key.clashLoglevel) + val serviceModeValue = DataStore.serviceMode + val meteredPr = findPreference(Key.metered) + meteredPr!!.apply { + if (Build.VERSION.SDK_INT >= 28) isEnabled = serviceModeValue == Key.modeVpn else remove() + } /*val onServiceModeChange = Preference.OnPreferenceChangeListener { preference, newValue -> val (enabledLocalDns, enabledTransproxy) = when (newValue as String?) { Key.modeProxy -> Pair(false, false) @@ -67,6 +75,7 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { portApi?.isEnabled = true clashLoglevel?.isEnabled = true dnsMode?.isEnabled = true + meteredPr?.isEnabled = true } else { serviceMode?.isEnabled = false portHttpProxy?.isEnabled = false @@ -77,6 +86,7 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() { portApi?.isEnabled = false clashLoglevel?.isEnabled = false dnsMode?.isEnabled = false + meteredPr?.isEnabled = false } } diff --git a/app/src/main/java/com/github/cgg/clasha/bg/VpnService.kt b/app/src/main/java/com/github/cgg/clasha/bg/VpnService.kt index 548265b..18bf487 100644 --- a/app/src/main/java/com/github/cgg/clasha/bg/VpnService.kt +++ b/app/src/main/java/com/github/cgg/clasha/bg/VpnService.kt @@ -62,22 +62,6 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { override fun getLocalizedMessage() = getString(R.string.reboot_required) } - @TargetApi(Build.VERSION_CODES.P) - private val defaultNetworkCallback = object : ConnectivityManager.NetworkCallback() { - override fun onAvailable(network: Network) { - underlyingNetwork = network - } - - override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities?) { - // it's a good idea to refresh capabilities - underlyingNetwork = network - } - - override fun onLost(network: Network) { - underlyingNetwork = null - } - } - private inner class ProtectWorker : ConcurrentLocalSocketListener( "ClashVpnThread", File(app.deviceStorage.noBackupFilesDir, "protect_path") @@ -108,12 +92,16 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { private var conn: ParcelFileDescriptor? = null private var worker: ProtectWorker? = null private var active = false + private var metered = false private var underlyingNetwork: Network? = null set(value) { field = value if (active && Build.VERSION.SDK_INT >= 22) setUnderlyingNetworks(underlyingNetworks) } - private val underlyingNetworks get() = underlyingNetwork?.let { arrayOf(it) } + private val underlyingNetworks + get() = + // clearing underlyingNetworks makes Android 9 consider the network to be metered + if (Build.VERSION.SDK_INT == 28 && metered) null else underlyingNetwork?.let { arrayOf(it) } override fun onBind(intent: Intent) = when (intent.action) { SERVICE_INTERFACE -> super.onBind(intent) @@ -177,9 +165,15 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { //bypass us builder.addDisallowedApplication(packageName) builder.addDisallowedApplication("$packageName:bg") - //todo APP bypass + metered = DataStore.metered + active = true + if (Build.VERSION.SDK_INT >= 22) { + builder.setUnderlyingNetworks(underlyingNetworks) + if (Build.VERSION.SDK_INT >= 29) builder.setMetered(metered) + } + val conn = builder.establish() ?: throw NullConnectionException() this.conn = conn val fd = conn.fd diff --git a/app/src/main/java/com/github/cgg/clasha/data/DataStore.kt b/app/src/main/java/com/github/cgg/clasha/data/DataStore.kt index 9e8ca3f..4361fc3 100644 --- a/app/src/main/java/com/github/cgg/clasha/data/DataStore.kt +++ b/app/src/main/java/com/github/cgg/clasha/data/DataStore.kt @@ -77,6 +77,9 @@ object DataStore { get() = publicStore.getString(Key.clashLoglevel, Key.clashLogInfo)!! set(value) = publicStore.putString(Key.clashLoglevel, value) + var metered: Boolean + get() = publicStore.getBoolean(Key.metered, false) + set(value) = publicStore.putBoolean(Key.metered, value) var portProxy: Int get() = getLocalPort(Key.portProxy, 7891) set(value) = publicStore.putString(Key.portProxy, value.toString()) diff --git a/app/src/main/java/com/github/cgg/clasha/net/DefaultNetworkListener.kt b/app/src/main/java/com/github/cgg/clasha/net/DefaultNetworkListener.kt index f6637be..e21fbc3 100644 --- a/app/src/main/java/com/github/cgg/clasha/net/DefaultNetworkListener.kt +++ b/app/src/main/java/com/github/cgg/clasha/net/DefaultNetworkListener.kt @@ -62,8 +62,8 @@ object DefaultNetworkListener { check(listeners.isNotEmpty()) { "Getting network without any listeners is not supported" } if (network == null) pendingRequests += message else message.response.complete(network) } - is NetworkMessage.Stop -> if (!listeners.isEmpty() && // was not empty - listeners.remove(message.key) != null && listeners.isEmpty()) { + is NetworkMessage.Stop -> if (listeners.isNotEmpty() && // was not empty + listeners.remove(message.key) != null && listeners.isEmpty()) { network = null unregister() } diff --git a/app/src/main/java/com/github/cgg/clasha/utils/Key.kt b/app/src/main/java/com/github/cgg/clasha/utils/Key.kt index d31bfd3..854c669 100644 --- a/app/src/main/java/com/github/cgg/clasha/utils/Key.kt +++ b/app/src/main/java/com/github/cgg/clasha/utils/Key.kt @@ -73,8 +73,8 @@ object Key { const val portHttpProxy = "portHttpProxy" const val portLocalDns = "portLocalDns" const val portTransproxy = "portTransproxy" - const val portApi = "portApi" + const val metered = "metered" const val route = "route" diff --git a/app/src/main/java/com/github/cgg/clasha/utils/Utils.kt b/app/src/main/java/com/github/cgg/clasha/utils/Utils.kt index d0eb207..fe90a12 100644 --- a/app/src/main/java/com/github/cgg/clasha/utils/Utils.kt +++ b/app/src/main/java/com/github/cgg/clasha/utils/Utils.kt @@ -17,6 +17,7 @@ import android.text.TextUtils import android.util.Log import android.util.TypedValue import androidx.annotation.AttrRes +import androidx.preference.Preference import com.blankj.utilcode.util.LogUtils import com.crashlytics.android.Crashlytics import com.github.cgg.clasha.App @@ -325,4 +326,6 @@ class JSONArrayAdapter : JsonSerializer, JsonDeserializer } } -} \ No newline at end of file +} + +fun Preference.remove() = parent!!.removePreference(this) diff --git a/app/src/main/res/drawable/ic_device_data_usage.xml b/app/src/main/res/drawable/ic_device_data_usage.xml new file mode 100644 index 0000000..1bad248 --- /dev/null +++ b/app/src/main/res/drawable/ic_device_data_usage.xml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1dd008c..02d75aa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -100,7 +100,8 @@ Dns Custom(fallback) Allow Lan IPV6 Enable - + Metered Hint + Hint system to treat VPN as metered Please select a profile diff --git a/app/src/main/res/xml/pref_global.xml b/app/src/main/res/xml/pref_global.xml index df23630..0dfa194 100644 --- a/app/src/main/res/xml/pref_global.xml +++ b/app/src/main/res/xml/pref_global.xml @@ -72,6 +72,12 @@ android:singleLine="true" android:title="@string/port_proxy"/> + +