diff --git a/app/src/main/java/com/github/kr328/clash/BaseActivity.kt b/app/src/main/java/com/github/kr328/clash/BaseActivity.kt
index 679df30..0b01e1a 100644
--- a/app/src/main/java/com/github/kr328/clash/BaseActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/BaseActivity.kt
@@ -103,7 +103,7 @@ abstract class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope()
if (language.isEmpty())
return super.attachBaseContext(base)
- val configuration = base.resources.configuration
+ val configuration = Configuration()
val localeOverride = if (languageOverride.size == 2)
Locale(languageOverride[0], languageOverride[1])
else
@@ -117,6 +117,8 @@ abstract class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ language = uiSettings.get(UiSettings.LANGUAGE)
+
resetDarkMode()
resetLightNavigationBar()
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 60c527a..f95e765 100644
--- a/app/src/main/java/com/github/kr328/clash/MainActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/MainActivity.kt
@@ -13,6 +13,7 @@ import com.github.kr328.clash.service.ClashService
import com.github.kr328.clash.service.data.ClashProfileEntity
import com.github.kr328.clash.service.util.intent
import com.github.kr328.clash.service.util.startForegroundServiceCompat
+import com.github.kr328.clash.utils.startClashService
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
@@ -35,10 +36,8 @@ class MainActivity : BaseActivity() {
if (clashRunning) {
stopService(ClashService::class.intent)
} else {
- val vpnRequest = VpnService.prepare(this)
- if (vpnRequest == null)
- startForegroundServiceCompat(ClashService::class.intent)
- else
+ val vpnRequest = startClashService()
+ if ( vpnRequest != null )
startActivityForResult(vpnRequest, REQUEST_CODE)
}
}
diff --git a/app/src/main/java/com/github/kr328/clash/MainApplication.kt b/app/src/main/java/com/github/kr328/clash/MainApplication.kt
index dd869e0..16ce9d3 100644
--- a/app/src/main/java/com/github/kr328/clash/MainApplication.kt
+++ b/app/src/main/java/com/github/kr328/clash/MainApplication.kt
@@ -2,12 +2,16 @@ package com.github.kr328.clash
import android.app.Application
import android.content.Context
+import android.content.res.Configuration
import com.github.kr328.clash.core.Global
+import com.github.kr328.clash.core.utils.Log
+import com.github.kr328.clash.preference.UiSettings
import com.github.kr328.clash.remote.Broadcasts
import com.github.kr328.clash.remote.Remote
import com.microsoft.appcenter.AppCenter
import com.microsoft.appcenter.analytics.Analytics
import com.microsoft.appcenter.crashes.Crashes
+import java.util.*
@Suppress("unused")
class MainApplication : Application() {
diff --git a/app/src/main/java/com/github/kr328/clash/OnBootReceiver.kt b/app/src/main/java/com/github/kr328/clash/OnBootReceiver.kt
index 571a01a..bb5eb50 100644
--- a/app/src/main/java/com/github/kr328/clash/OnBootReceiver.kt
+++ b/app/src/main/java/com/github/kr328/clash/OnBootReceiver.kt
@@ -3,9 +3,19 @@ package com.github.kr328.clash
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import com.github.kr328.clash.service.Intents
+import com.github.kr328.clash.service.ProfileBackgroundService
+import com.github.kr328.clash.service.util.componentName
+import com.github.kr328.clash.service.util.startForegroundServiceCompat
+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
+ context.startClashService()
+ context.startForegroundServiceCompat(Intent(Intents.INTENT_ACTION_PROFILE_SETUP)
+ .setComponent(ProfileBackgroundService::class.componentName))
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/kr328/clash/ProxiesActivity.kt b/app/src/main/java/com/github/kr328/clash/ProxiesActivity.kt
index 8025c48..5b0dc70 100644
--- a/app/src/main/java/com/github/kr328/clash/ProxiesActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/ProxiesActivity.kt
@@ -294,11 +294,18 @@ class ProxiesActivity : BaseActivity(), ScrollBinding.Callback {
PrefixMerger.Result(p.name, "", p)
}
+ val data = if ( r.content.isEmpty() ) {
+ r.prefix to p.type.toString()
+ }
+ else {
+ r.content to r.prefix
+ }
+
ProxyAdapter.ProxyInfo(
p.name,
it.name,
- r.prefix,
- if (r.content.isEmpty()) p.type.toString() else r.content,
+ data.first,
+ data.second,
p.delay.toShort(),
it.type == Proxy.Type.SELECT,
p.name == it.current
diff --git a/app/src/main/java/com/github/kr328/clash/SettingsNetworkActivity.kt b/app/src/main/java/com/github/kr328/clash/SettingsNetworkActivity.kt
index 164bb91..4e05670 100644
--- a/app/src/main/java/com/github/kr328/clash/SettingsNetworkActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/SettingsNetworkActivity.kt
@@ -2,6 +2,7 @@ package com.github.kr328.clash
import android.os.Bundle
import com.github.kr328.clash.settings.NetworkFragment
+import com.google.android.material.snackbar.Snackbar
class SettingsNetworkActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -13,6 +14,9 @@ class SettingsNetworkActivity : BaseActivity() {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment, NetworkFragment())
.commit()
+
+ if ( clashRunning )
+ Snackbar.make(rootView, R.string.options_unavailable, Snackbar.LENGTH_INDEFINITE).show()
}
override val activityLabel: CharSequence?
diff --git a/app/src/main/java/com/github/kr328/clash/adapter/ProfileAdapter.kt b/app/src/main/java/com/github/kr328/clash/adapter/ProfileAdapter.kt
index 4b3ae46..6b9de36 100644
--- a/app/src/main/java/com/github/kr328/clash/adapter/ProfileAdapter.kt
+++ b/app/src/main/java/com/github/kr328/clash/adapter/ProfileAdapter.kt
@@ -132,6 +132,6 @@ class ProfileAdapter(private val context: Context, private val callback: Callbac
}
private fun offsetDate(date: Long): CharSequence {
- return IntervalUtils.intervalString(System.currentTimeMillis() - date)
+ return IntervalUtils.intervalString(context,System.currentTimeMillis() - date)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/kr328/clash/settings/InterfaceFragment.kt b/app/src/main/java/com/github/kr328/clash/settings/InterfaceFragment.kt
index a9ee4b6..1041d57 100644
--- a/app/src/main/java/com/github/kr328/clash/settings/InterfaceFragment.kt
+++ b/app/src/main/java/com/github/kr328/clash/settings/InterfaceFragment.kt
@@ -2,6 +2,7 @@ package com.github.kr328.clash.settings
import com.github.kr328.clash.R
import com.github.kr328.clash.preference.UiSettings
+import com.github.kr328.clash.service.settings.ServiceSettings
class InterfaceFragment: BaseSettingFragment() {
companion object {
@@ -15,6 +16,10 @@ class InterfaceFragment: BaseSettingFragment() {
on(KEY_LANGUAGE, UiSettings.LANGUAGE.asSource(ui))
onApply {
+ service.commit {
+ put(ServiceSettings.LANGUAGE, ui.get(UiSettings.LANGUAGE))
+ }
+
requireActivity().recreate()
}
}
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 6369e17..6c84bec 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
@@ -1,5 +1,7 @@
package com.github.kr328.clash.settings
+import android.os.Bundle
+import com.github.kr328.clash.BaseActivity
import com.github.kr328.clash.R
import com.github.kr328.clash.preference.UiSettings
import com.github.kr328.clash.service.settings.ServiceSettings
@@ -15,6 +17,13 @@ class NetworkFragment: BaseSettingFragment() {
private const val KEY_ACCESS_CONTROL_MODE = "access_control_mode"
}
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if ((requireActivity() as BaseActivity).clashRunning)
+ preferenceScreen.isEnabled = false
+ }
+
override fun onCreateDataStore(): SettingsDataStore {
return SettingsDataStore().apply {
on(KEY_ENABLE_VPN_SERVICE, UiSettings.ENABLE_VPN.asSource(ui))
diff --git a/app/src/main/java/com/github/kr328/clash/utils/IntervalUtils.kt b/app/src/main/java/com/github/kr328/clash/utils/IntervalUtils.kt
index ac2d1fd..f9eeade 100644
--- a/app/src/main/java/com/github/kr328/clash/utils/IntervalUtils.kt
+++ b/app/src/main/java/com/github/kr328/clash/utils/IntervalUtils.kt
@@ -1,5 +1,6 @@
package com.github.kr328.clash.utils
+import android.content.Context
import com.github.kr328.clash.R
import com.github.kr328.clash.core.Global
@@ -11,9 +12,7 @@ object IntervalUtils {
private const val MILLIS_MONTH = MILLIS_DAY * 30
private const val MILLIS_YEAR = MILLIS_MONTH * 12
- fun intervalString(interval: Long): String {
- val context = Global.application
-
+ fun intervalString(context: Context, interval: Long): String {
val year = interval / MILLIS_YEAR
val month = interval / MILLIS_MONTH
val day = interval / MILLIS_DAY
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
new file mode 100644
index 0000000..a29629d
--- /dev/null
+++ b/app/src/main/java/com/github/kr328/clash/utils/ServiceUtils.kt
@@ -0,0 +1,25 @@
+package com.github.kr328.clash.utils
+
+import android.content.Context
+import android.content.Intent
+import android.net.VpnService
+import com.github.kr328.clash.preference.UiSettings
+import com.github.kr328.clash.service.ClashService
+import com.github.kr328.clash.service.Intents
+import com.github.kr328.clash.service.util.intent
+import com.github.kr328.clash.service.util.startForegroundServiceCompat
+
+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(ClashService::class.intent
+ .putExtra(Intents.INTENT_EXTRA_START_TUN, startTun))
+
+ return null
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_adjust.xml b/app/src/main/res/drawable/ic_adjust.xml
deleted file mode 100644
index 44852ab..0000000
--- a/app/src/main/res/drawable/ic_adjust.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 92c624d..1cff5e9 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -2,7 +2,6 @@
为应用配置访问权限
关于
- 访问控制
访问控制模式
访问控制应用包列表
追加系统 DNS
@@ -15,7 +14,6 @@
绕过私有网络
绕过私有网络地址
取消
- 正在捕捉日志
Clash 日志捕捉工具
新配置
Clash 启动失败
@@ -42,12 +40,10 @@
编辑配置
空名称
启用 IPv6 支持 (不建议)
- 已启用
退出而不保存
所有变更将会丢失
导出
外部
- 反馈
文件
文件已导出
%s %s
@@ -86,7 +82,7 @@
配置
配置名称
配置 URL
- 配置文件
+ 配置
参数
代理
近期
@@ -97,7 +93,6 @@
规则
规则模式
运行中
- 发送
设置
显示流量
在通知中自动刷新流量
@@ -114,4 +109,5 @@
URL
实用工具
VPN Service
+ 选项在 Clash 运行时不可用
\ 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 f5db0ed..8bd155e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -18,7 +18,6 @@
Logs
Settings
- Feedback
Support
About
@@ -54,7 +53,6 @@
Edit
Delete
Export
- Send
Properties
Duplicate
Reset Providers
@@ -91,9 +89,7 @@
Cancel
Clash Logcat
- Capturing logs
History
- Enabled
Log Viewer
%s %s
%s %s.log
@@ -131,11 +127,12 @@
Force use builtin DNS config
Append System DNS
Auto add system dns to clash
- Access Control
Access Control Mode
Access Control Packages
Configure access permission for apps
Language
Dark Mode
+
+ Options Unavailable until Clash Stopped
diff --git a/app/src/main/res/xml/export_contents.xml b/app/src/main/res/xml/export_contents.xml
deleted file mode 100644
index c12988d..0000000
--- a/app/src/main/res/xml/export_contents.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/core/src/main/golang/profile/load.go b/core/src/main/golang/profile/load.go
index ea38bc7..cd98278 100644
--- a/core/src/main/golang/profile/load.go
+++ b/core/src/main/golang/profile/load.go
@@ -104,6 +104,7 @@ func parseConfig(data []byte, baseDir string) (*config.Config, error) {
return nil, err
}
+ raw.Experimental.Interface = ""
raw.ExternalUI = ""
raw.ExternalController = ""
raw.Rule = append([]string{fmt.Sprintf("IP-CIDR,%s,REJECT", tunAddress)}, raw.Rule...)
diff --git a/core/src/main/java/com/github/kr328/clash/core/Global.kt b/core/src/main/java/com/github/kr328/clash/core/Global.kt
index b27c2cc..43b6714 100644
--- a/core/src/main/java/com/github/kr328/clash/core/Global.kt
+++ b/core/src/main/java/com/github/kr328/clash/core/Global.kt
@@ -1,9 +1,11 @@
package com.github.kr328.clash.core
import android.app.Application
+import android.content.res.Configuration
object Global {
lateinit var application: Application
+ val overrideConfiguration = Configuration()
fun init(application: Application) {
this.application = application
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
deleted file mode 100644
index a5bfc6d..0000000
--- a/core/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- core
-
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 1fb43e9..5418dcf 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
@@ -1,12 +1,37 @@
package com.github.kr328.clash.service
import android.app.Service
+import android.content.Context
+import android.content.res.Configuration
import com.github.kr328.clash.core.Clash
+import com.github.kr328.clash.service.settings.ServiceSettings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
+import java.util.*
abstract class BaseService : Service(), CoroutineScope by MainScope() {
+ lateinit var settings: ServiceSettings
+
+ override fun attachBaseContext(base: Context?) {
+ settings = ServiceSettings(base ?: return super.attachBaseContext(base))
+
+ val language = settings.get(ServiceSettings.LANGUAGE)
+ if ( language.isEmpty() )
+ return super.attachBaseContext(base)
+ val languageOverride = language.split("-")
+
+ val configuration = Configuration()
+ val localeOverride = if (languageOverride.size == 2)
+ Locale(languageOverride[0], languageOverride[1])
+ else
+ Locale(languageOverride[0])
+
+ configuration.setLocale(localeOverride)
+
+ super.attachBaseContext(base.createConfigurationContext(configuration))
+ }
+
override fun onCreate() {
super.onCreate()
diff --git a/service/src/main/java/com/github/kr328/clash/service/ClashNotification.kt b/service/src/main/java/com/github/kr328/clash/service/ClashNotification.kt
index e40a3e9..aab95b2 100644
--- a/service/src/main/java/com/github/kr328/clash/service/ClashNotification.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/ClashNotification.kt
@@ -63,9 +63,7 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
init {
createNotificationChannel()
- runBlocking {
- update()
- }
+ notifyBaseNotification()
if (enableRefresh) {
launch {
@@ -133,6 +131,15 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
}
}
+ private fun notifyBaseNotification() {
+ val notification = baseBuilder
+ .setContentTitle(profile)
+ .setContentText(context.getText(R.string.running))
+ .build()
+
+ context.startForeground(CLASH_STATUS_NOTIFICATION_ID, notification)
+ }
+
private suspend fun update() {
val notification = withContext(Dispatchers.Default) {
createNotification()
diff --git a/service/src/main/java/com/github/kr328/clash/service/ClashService.kt b/service/src/main/java/com/github/kr328/clash/service/ClashService.kt
index 9b348c2..b72af2d 100644
--- a/service/src/main/java/com/github/kr328/clash/service/ClashService.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/ClashService.kt
@@ -18,9 +18,6 @@ import kotlinx.coroutines.sync.Mutex
class ClashService : BaseService() {
companion object {
- const val INTENT_EXTRA_START_TUN =
- "${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.start.tun"
-
var isServiceRunning = false
}
@@ -29,7 +26,6 @@ class ClashService : BaseService() {
private lateinit var notification: ClashNotification
private var stopReason: String? = null
private val reloadChannel = Channel(Channel.CONFLATED)
- private val settings: ServiceSettings by lazy { ServiceSettings(this) }
private val reloadReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.`package` != packageName)
@@ -64,7 +60,8 @@ class ClashService : BaseService() {
broadcastClashStarted(this)
- val startVpn = intent?.getBooleanExtra(INTENT_EXTRA_START_TUN, true) ?: true
+ val startVpn = intent?.getBooleanExtra(
+ Intents.INTENT_EXTRA_START_TUN, true) ?: true
if (startVpn)
startService(TunService::class.intent)
diff --git a/service/src/main/java/com/github/kr328/clash/service/Intents.kt b/service/src/main/java/com/github/kr328/clash/service/Intents.kt
index 4dedd7d..2d583de 100644
--- a/service/src/main/java/com/github/kr328/clash/service/Intents.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/Intents.kt
@@ -22,4 +22,6 @@ object Intents {
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.profile"
const val INTENT_EXTRA_PROFILE_REQUEST =
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.profile.request"
+ const val INTENT_EXTRA_START_TUN =
+ "${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.start.tun"
}
\ No newline at end of file
diff --git a/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt b/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt
index 934a60f..6f9ab3f 100644
--- a/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/net/DefaultNetworkChannel.kt
@@ -68,8 +68,6 @@ class DefaultNetworkChannel(val context: Context, scope: CoroutineScope) :
return
launch {
- delay(1000)
-
val network = detectDefaultNetwork()
val link = network?.let(connectivity::getLinkProperties)
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 554caf3..99767ca 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
@@ -12,6 +12,8 @@ class ServiceSettings(context: Context):
const val ACCESS_CONTROL_MODE_BLACKLIST = "access_control_mode_blacklist"
const val ACCESS_CONTROL_MODE_WHITELIST = "access_control_mode_whitelist"
+ val LANGUAGE =
+ StringEntry("language", "")
val IPV6_SUPPORT =
BooleanEntry("ipv6_support", false)
val BYPASS_PRIVATE_NETWORK =
diff --git a/service/src/main/res/values-zh/strings.xml b/service/src/main/res/values-zh/strings.xml
new file mode 100644
index 0000000..83e2ced
--- /dev/null
+++ b/service/src/main/res/values-zh/strings.xml
@@ -0,0 +1,16 @@
+
+
+ Clash 管理器服务
+ Clash 配置管理服务
+ Clash 核心服务
+ Clash 状态
+ 配置服务状态
+ 配置更新工具正在运行
+ 配置处理状态
+ 正在处理配置文件
+ 更新 %s 完成
+ 更新 %s 失败
+ 正在更新 %s
+ 正在运行
+ Tun 服务
+
\ No newline at end of file
diff --git a/service/src/main/res/values/strings.xml b/service/src/main/res/values/strings.xml
index b6b67c4..e48f498 100644
--- a/service/src/main/res/values/strings.xml
+++ b/service/src/main/res/values/strings.xml
@@ -1,10 +1,8 @@
- Clash
-
Clash Status
- "%1$s↑\t%2$s↓"
+ "%1$s↑\t%2$s↓"
Profile Service Status
Profile Updater Running
@@ -19,4 +17,6 @@
Tun Device Service
Clash Manager Service
Clash Profile Manager Service
+
+ Running