diff --git a/app/src/main/java/com/github/kr328/clash/MainActivity.kt b/app/src/main/java/com/github/kr328/clash/MainActivity.kt index 10be5b5..d20b401 100644 --- a/app/src/main/java/com/github/kr328/clash/MainActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/MainActivity.kt @@ -13,8 +13,8 @@ import com.github.kr328.clash.common.utils.asBytesString import com.github.kr328.clash.core.model.General import com.github.kr328.clash.remote.withClash import com.github.kr328.clash.remote.withProfile -import com.github.kr328.clash.utils.startClashService -import com.github.kr328.clash.utils.stopClashService +import com.github.kr328.clash.service.util.startClashService +import com.github.kr328.clash.service.util.stopClashService import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.* diff --git a/app/src/main/java/com/github/kr328/clash/OnBootReceiver.kt b/app/src/main/java/com/github/kr328/clash/OnBootReceiver.kt deleted file mode 100644 index 9acb55d..0000000 --- a/app/src/main/java/com/github/kr328/clash/OnBootReceiver.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.kr328.clash - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import com.github.kr328.clash.service.Constants -import com.github.kr328.clash.utils.startClashService - -class OnBootReceiver : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - if (intent?.action != Intent.ACTION_BOOT_COMPLETED || context == null) - return - - if (context.cacheDir.resolve(Constants.CLASH_SERVICE_RUNNING_FILE).exists()) - context.startClashService() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt b/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt index 25f7d5e..d803cb6 100644 --- a/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/ProfilesActivity.kt @@ -76,6 +76,8 @@ class ProfilesActivity : BaseActivity(), ProfileAdapter.Callback, ProfilesMenu.C commitAsync(id) else ProfileProvider.releaseTemp(self, id) + + Unit } } diff --git a/app/src/main/java/com/github/kr328/clash/TileService.kt b/app/src/main/java/com/github/kr328/clash/TileService.kt index a94103e..4ee79e8 100644 --- a/app/src/main/java/com/github/kr328/clash/TileService.kt +++ b/app/src/main/java/com/github/kr328/clash/TileService.kt @@ -10,8 +10,8 @@ import android.service.quicksettings.TileService import com.github.kr328.clash.common.Permissions import com.github.kr328.clash.common.ids.Intents import com.github.kr328.clash.remote.RemoteUtils -import com.github.kr328.clash.utils.startClashService -import com.github.kr328.clash.utils.stopClashService +import com.github.kr328.clash.service.util.startClashService +import com.github.kr328.clash.service.util.stopClashService class TileService : TileService() { private var currentProfile = "" diff --git a/app/src/main/java/com/github/kr328/clash/preference/UiSettings.kt b/app/src/main/java/com/github/kr328/clash/preference/UiSettings.kt index a7053d0..ac6980e 100644 --- a/app/src/main/java/com/github/kr328/clash/preference/UiSettings.kt +++ b/app/src/main/java/com/github/kr328/clash/preference/UiSettings.kt @@ -16,7 +16,6 @@ class UiSettings(context: Context) : const val DARK_MODE_DARK = "dark" const val DARK_MODE_LIGHT = "light" - val ENABLE_VPN = BooleanEntry("enable_vpn", true) val PROXY_GROUP_SORT = StringEntry("proxy_group_sort", PROXY_SORT_DEFAULT) val PROXY_PROXY_SORT = StringEntry("proxy_proxy_sort", PROXY_SORT_DEFAULT) val PROXY_LAST_SELECT_GROUP = StringEntry("proxy_last_select_group", "") diff --git a/app/src/main/java/com/github/kr328/clash/settings/BehaviorFragment.kt b/app/src/main/java/com/github/kr328/clash/settings/BehaviorFragment.kt index 47df815..5bba98e 100644 --- a/app/src/main/java/com/github/kr328/clash/settings/BehaviorFragment.kt +++ b/app/src/main/java/com/github/kr328/clash/settings/BehaviorFragment.kt @@ -2,10 +2,10 @@ package com.github.kr328.clash.settings import android.content.pm.PackageManager import android.os.Bundle -import com.github.kr328.clash.OnBootReceiver import com.github.kr328.clash.R import com.github.kr328.clash.common.util.componentName import com.github.kr328.clash.remote.Broadcasts +import com.github.kr328.clash.service.RestartReceiver import com.github.kr328.clash.service.settings.ServiceSettings class BehaviorFragment : BaseSettingFragment() { @@ -40,7 +40,7 @@ class BehaviorFragment : BaseSettingFragment() { PackageManager.COMPONENT_ENABLED_STATE_DISABLED requireActivity().packageManager.setComponentEnabledSetting( - OnBootReceiver::class.componentName, + RestartReceiver::class.componentName, status, PackageManager.DONT_KILL_APP ) @@ -48,7 +48,7 @@ class BehaviorFragment : BaseSettingFragment() { override fun get(): Any? { val status = requireActivity().packageManager - .getComponentEnabledSetting(OnBootReceiver::class.componentName) + .getComponentEnabledSetting(RestartReceiver::class.componentName) return status == PackageManager.COMPONENT_ENABLED_STATE_ENABLED } diff --git a/app/src/main/java/com/github/kr328/clash/settings/NetworkFragment.kt b/app/src/main/java/com/github/kr328/clash/settings/NetworkFragment.kt index 97114ab..49ef77b 100644 --- a/app/src/main/java/com/github/kr328/clash/settings/NetworkFragment.kt +++ b/app/src/main/java/com/github/kr328/clash/settings/NetworkFragment.kt @@ -32,7 +32,7 @@ class NetworkFragment : BaseSettingFragment() { override fun onCreateDataStore(): SettingsDataStore { return SettingsDataStore().apply { - on(KEY_ENABLE_VPN_SERVICE, UiSettings.ENABLE_VPN.asSource(ui)) + on(KEY_ENABLE_VPN_SERVICE, ServiceSettings.ENABLE_VPN.asSource(service)) on(BYPASS_PRIVATE_NETWORK, ServiceSettings.BYPASS_PRIVATE_NETWORK.asSource(service)) on(KEY_DNS_HIJACKING, ServiceSettings.DNS_HIJACKING.asSource(service)) on(KEY_DNS_OVERRIDE, ServiceSettings.OVERRIDE_DNS.asSource(service)) diff --git a/app/src/main/java/com/github/kr328/clash/utils/ServiceUtils.kt b/app/src/main/java/com/github/kr328/clash/utils/ServiceUtils.kt index 53c3022..d71e8b2 100644 --- a/app/src/main/java/com/github/kr328/clash/utils/ServiceUtils.kt +++ b/app/src/main/java/com/github/kr328/clash/utils/ServiceUtils.kt @@ -11,22 +11,3 @@ import com.github.kr328.clash.service.ClashService import com.github.kr328.clash.service.TunService import com.github.kr328.clash.service.util.sendBroadcastSelf -fun Context.startClashService(): Intent? { - val startTun = UiSettings(this).get(UiSettings.ENABLE_VPN) - - if (startTun) { - val vpnRequest = VpnService.prepare(this) - if (vpnRequest != null) - return vpnRequest - - startForegroundServiceCompat(TunService::class.intent) - } else { - startForegroundServiceCompat(ClashService::class.intent) - } - - return null -} - -fun Context.stopClashService() { - sendBroadcastSelf(Intent(Intents.INTENT_ACTION_REQUEST_STOP)) -} \ No newline at end of file diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index d79765a..57f1e42 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -10,7 +10,7 @@ Clash for Android 自动更新 (分钟) 行为 - 启动 + 重启 绕过私有网络 绕过私有网络地址 取消 @@ -94,8 +94,8 @@ 在通知中自动刷新流量 代理组排序 代理排序 - 在系统启动时启动 Clash - 开机时启动 + 允许 Clash 自动重启 + 自动重启 打开 URL 提供程序失败 已停止 支持 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 269b90a..00698cb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -106,9 +106,9 @@ Network Interface - Boot - Start on Boot - Start Clash on system boot + Restart + Auto Restart + Allow clash auto restart Notification Show Traffic diff --git a/app/src/main/res/xml/settings_behavior.xml b/app/src/main/res/xml/settings_behavior.xml index 2eba88d..599fb87 100644 --- a/app/src/main/res/xml/settings_behavior.xml +++ b/app/src/main/res/xml/settings_behavior.xml @@ -1,11 +1,11 @@ - + + android:title="@string/auto_restart" + android:summary="@string/allow_clash_auto_restart" /> + android:permission="${applicationId}.permission.RECEIVE_BROADCASTS" /> + diff --git a/service/src/main/java/com/github/kr328/clash/service/BaseService.kt b/service/src/main/java/com/github/kr328/clash/service/BaseService.kt index 88876b3..f2b53ab 100644 --- a/service/src/main/java/com/github/kr328/clash/service/BaseService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/BaseService.kt @@ -3,7 +3,6 @@ package com.github.kr328.clash.service import android.app.Service import android.content.Context import com.github.kr328.clash.common.util.createLanguageConfigurationContext -import com.github.kr328.clash.core.Clash import com.github.kr328.clash.service.settings.ServiceSettings import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope diff --git a/service/src/main/java/com/github/kr328/clash/service/Constants.kt b/service/src/main/java/com/github/kr328/clash/service/Constants.kt index 6c8b144..c99d94b 100644 --- a/service/src/main/java/com/github/kr328/clash/service/Constants.kt +++ b/service/src/main/java/com/github/kr328/clash/service/Constants.kt @@ -8,6 +8,4 @@ object Constants { const val PROFILE_PROVIDER_SUFFIX = ".profiles" const val STATUS_PROVIDER_SUFFIX = ".status" const val SETTING_PROVIDER_SUFFIX = ".settings" - - const val CLASH_SERVICE_RUNNING_FILE = "clash_running" } \ No newline at end of file diff --git a/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt b/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt index 76121c0..303be6d 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ProfileService.kt @@ -4,7 +4,6 @@ import android.content.Intent import android.net.Uri import android.os.IBinder import android.os.RemoteException -import com.github.kr328.clash.common.utils.Log import com.github.kr328.clash.service.data.ProfileDao import com.github.kr328.clash.service.ipc.IStreamCallback import com.github.kr328.clash.service.model.ProfileMetadata diff --git a/service/src/main/java/com/github/kr328/clash/service/RestartReceiver.kt b/service/src/main/java/com/github/kr328/clash/service/RestartReceiver.kt new file mode 100644 index 0000000..b1244ef --- /dev/null +++ b/service/src/main/java/com/github/kr328/clash/service/RestartReceiver.kt @@ -0,0 +1,24 @@ +package com.github.kr328.clash.service + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import com.github.kr328.clash.service.util.startClashService + +class RestartReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (context == null) + return + + when (intent?.action) { + Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_MY_PACKAGE_REPLACED -> { + } + else -> return + } + + ProfileReceiver.tryInitialize(context) + + if (ServiceStatusProvider.shouldStartClashOnBoot) + context.startClashService() + } +} \ No newline at end of file diff --git a/service/src/main/java/com/github/kr328/clash/service/ServiceStatusProvider.kt b/service/src/main/java/com/github/kr328/clash/service/ServiceStatusProvider.kt index 8f02479..978d6eb 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ServiceStatusProvider.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ServiceStatusProvider.kt @@ -10,12 +10,17 @@ import com.github.kr328.clash.common.Global class ServiceStatusProvider : ContentProvider() { companion object { const val METHOD_PING_CLASH_SERVICE = "pingClashService" + private const val CLASH_SERVICE_RUNNING_FILE = "service_running" var serviceRunning: Boolean = false set(value) { field = value - - Global.application.cacheDir.resolve(Constants.CLASH_SERVICE_RUNNING_FILE).apply { + shouldStartClashOnBoot = value + } + var shouldStartClashOnBoot: Boolean + get() = Global.application.cacheDir.resolve(CLASH_SERVICE_RUNNING_FILE).exists() + set(value) { + Global.application.cacheDir.resolve(CLASH_SERVICE_RUNNING_FILE).apply { if (value) createNewFile() else diff --git a/service/src/main/java/com/github/kr328/clash/service/data/DatabaseMigrations.kt b/service/src/main/java/com/github/kr328/clash/service/data/DatabaseMigrations.kt index 9bcaaf7..2308bc8 100644 --- a/service/src/main/java/com/github/kr328/clash/service/data/DatabaseMigrations.kt +++ b/service/src/main/java/com/github/kr328/clash/service/data/DatabaseMigrations.kt @@ -189,6 +189,15 @@ object DatabaseMigrations { } database.execSQL("DROP TABLE _profiles") + + val uiSp = Global.application + .getSharedPreferences("ui", Context.MODE_PRIVATE) + val srvSp = Global.application + .getSharedPreferences("service", Context.MODE_PRIVATE) + + srvSp.edit { + putBoolean("enable_vpn", uiSp.getBoolean("enable_vpn", true)) + } } catch (e: Exception) { Log.e("Migration failure", e) } diff --git a/service/src/main/java/com/github/kr328/clash/service/files/ProfilesResolver.kt b/service/src/main/java/com/github/kr328/clash/service/files/ProfilesResolver.kt index b71cb45..9fb06f2 100644 --- a/service/src/main/java/com/github/kr328/clash/service/files/ProfilesResolver.kt +++ b/service/src/main/java/com/github/kr328/clash/service/files/ProfilesResolver.kt @@ -3,7 +3,6 @@ package com.github.kr328.clash.service.files import android.content.Context import android.os.ParcelFileDescriptor import android.provider.DocumentsContract -import com.github.kr328.clash.common.utils.Log import com.github.kr328.clash.service.R import com.github.kr328.clash.service.data.ProfileDao import com.github.kr328.clash.service.util.resolveProfileFile diff --git a/service/src/main/java/com/github/kr328/clash/service/model/Converters.kt b/service/src/main/java/com/github/kr328/clash/service/model/Converters.kt index d27cf71..d9f6290 100644 --- a/service/src/main/java/com/github/kr328/clash/service/model/Converters.kt +++ b/service/src/main/java/com/github/kr328/clash/service/model/Converters.kt @@ -19,7 +19,7 @@ fun ProfileEntity.toProfileMetadata(context: Context): ProfileMetadata { name = name, type = type, uri = Uri.parse(uri), - source = source?.let { Uri.parse(it)}, + source = source?.let { Uri.parse(it) }, active = active, interval = interval, lastModified = lastModified diff --git a/service/src/main/java/com/github/kr328/clash/service/model/ProfileMetadata.kt b/service/src/main/java/com/github/kr328/clash/service/model/ProfileMetadata.kt index 08b07f7..a34cbbc 100644 --- a/service/src/main/java/com/github/kr328/clash/service/model/ProfileMetadata.kt +++ b/service/src/main/java/com/github/kr328/clash/service/model/ProfileMetadata.kt @@ -19,7 +19,7 @@ data class ProfileMetadata( val active: Boolean, val interval: Long, val lastModified: Long -): Parcelable { +) : Parcelable { enum class Type { FILE, URL, EXTERNAL, UNKNOWN } diff --git a/service/src/main/java/com/github/kr328/clash/service/settings/ServiceSettings.kt b/service/src/main/java/com/github/kr328/clash/service/settings/ServiceSettings.kt index b1c6a1c..b194879 100644 --- a/service/src/main/java/com/github/kr328/clash/service/settings/ServiceSettings.kt +++ b/service/src/main/java/com/github/kr328/clash/service/settings/ServiceSettings.kt @@ -16,6 +16,8 @@ class ServiceSettings(preference: SharedPreferences) : const val ACCESS_CONTROL_MODE_BLACKLIST = "access_control_mode_blacklist" const val ACCESS_CONTROL_MODE_WHITELIST = "access_control_mode_whitelist" + val ENABLE_VPN = + BooleanEntry("enable_vpn", true) val LANGUAGE = StringEntry("language", "") val BYPASS_PRIVATE_NETWORK = diff --git a/service/src/main/java/com/github/kr328/clash/service/util/BroadcastUtils.kt b/service/src/main/java/com/github/kr328/clash/service/util/BroadcastUtils.kt index d278b6c..34e000f 100644 --- a/service/src/main/java/com/github/kr328/clash/service/util/BroadcastUtils.kt +++ b/service/src/main/java/com/github/kr328/clash/service/util/BroadcastUtils.kt @@ -4,12 +4,12 @@ import android.content.Context import android.content.Intent import com.github.kr328.clash.common.Permissions import com.github.kr328.clash.common.ids.Intents -import com.github.kr328.clash.common.utils.Log -import java.lang.Exception fun Context.sendBroadcastSelf(intent: Intent) { - this.sendBroadcast(intent.setPackage(this.packageName), - Permissions.PERMISSION_RECEIVE_BROADCASTS) + this.sendBroadcast( + intent.setPackage(this.packageName), + Permissions.PERMISSION_RECEIVE_BROADCASTS + ) } fun Context.broadcastProfileChanged() { diff --git a/service/src/main/java/com/github/kr328/clash/service/util/ServiceUtils.kt b/service/src/main/java/com/github/kr328/clash/service/util/ServiceUtils.kt new file mode 100644 index 0000000..efdc510 --- /dev/null +++ b/service/src/main/java/com/github/kr328/clash/service/util/ServiceUtils.kt @@ -0,0 +1,31 @@ +package com.github.kr328.clash.service.util + +import android.content.Context +import android.content.Intent +import android.net.VpnService +import com.github.kr328.clash.common.ids.Intents +import com.github.kr328.clash.common.util.intent +import com.github.kr328.clash.common.util.startForegroundServiceCompat +import com.github.kr328.clash.service.ClashService +import com.github.kr328.clash.service.TunService +import com.github.kr328.clash.service.settings.ServiceSettings + +fun Context.startClashService(): Intent? { + val startTun = ServiceSettings(this).get(ServiceSettings.ENABLE_VPN) + + if (startTun) { + val vpnRequest = VpnService.prepare(this) + if (vpnRequest != null) + return vpnRequest + + startForegroundServiceCompat(TunService::class.intent) + } else { + startForegroundServiceCompat(ClashService::class.intent) + } + + return null +} + +fun Context.stopClashService() { + sendBroadcastSelf(Intent(Intents.INTENT_ACTION_REQUEST_STOP)) +} \ No newline at end of file