Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a097966
remove already applied patch file for go1.26.3
wwqgtxx May 7, 2026
1d42dfa
disable futex_time64 again
wwqgtxx May 8, 2026
63a68d4
Defer shortcut setup to MainActivity (#215) (#728)
Goooler May 9, 2026
d7c16ec
Replace shortcut icons (#729)
Goooler May 9, 2026
a616468
Fix parse profile-update-interval http header (#732)
AlexFozor May 12, 2026
d1ac459
Add supported languages to system settings (#733)
Goooler May 12, 2026
6332a9b
Fix clash:// deep link not opening app due to premature Activity fini…
xiwangly2 May 12, 2026
930d04f
Update Proxy.kt
wwqgtxx May 13, 2026
cb9aa9e
Update Proxy.kt
wwqgtxx May 14, 2026
8f7814b
Update Dependencies (#710)
clash-meta-maintainer[bot] May 14, 2026
92a3aaf
Update Dependencies (#737)
clash-meta-maintainer[bot] May 15, 2026
c20a942
Update Proxy.kt
wwqgtxx May 16, 2026
bcf67a2
Update Dependencies (#738)
clash-meta-maintainer[bot] May 16, 2026
686ded2
Bump version to 2.11.28 (211028)
actions-user May 16, 2026
b37570c
fix profile can not be selected by remote controller on android tv (#…
scola May 22, 2026
74cbae2
Update Dependencies (#739)
clash-meta-maintainer[bot] May 31, 2026
c05032b
Bump version to 2.11.29 (211029)
actions-user May 31, 2026
71cb215
fix(profile): prevent HTTP header from overriding custom update inter…
AlexFozor Jun 1, 2026
7f63b75
Update Dependencies (#758)
clash-meta-maintainer[bot] Jun 4, 2026
a69dd69
feat(profile): support age secret keys (#764)
NevadaCities Jun 4, 2026
6390d46
Update Proxy.kt
wwqgtxx Jun 4, 2026
5b0d073
Fixed Shortcut icon, corrected translation. (#766)
NevadaCities Jun 4, 2026
f6670dc
add BundleMRS.7z
wwqgtxx Jun 5, 2026
1452c27
Update Dependencies (#765)
clash-meta-maintainer[bot] Jun 5, 2026
9c80c41
adopt `path-in-bundle` for rule-providers
wwqgtxx Jun 5, 2026
ffda42d
allow ignoring fetch subscription-userinfo error
wwqgtxx Jun 5, 2026
d628f33
feat(settings): add clickable label to generate age-encryption public…
NevadaCities Jun 6, 2026
33a5886
Update Dependencies (#767)
clash-meta-maintainer[bot] Jun 6, 2026
9bfdd3a
Bump version to 2.11.30 (211030)
actions-user Jun 6, 2026
68c4be2
don't use enum class for Proxy.Type
wwqgtxx Jun 11, 2026
2b909e2
Update FilterMode
wwqgtxx Jun 11, 2026
8a0e818
Move subscription info fetch into Go
xishang0128 Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 18 additions & 41 deletions .github/patch/remove_64bits_syscall_on_32bit_linux.patch
Original file line number Diff line number Diff line change
@@ -1,56 +1,33 @@
Subject: [PATCH] remove 64bits syscall on 32bit linux
From bef1938b64a444911de119db613e60b9078ddd81 Mon Sep 17 00:00:00 2001
From: wwqgtxx <wwqgtxx@gmail.com>
Date: Sat, 9 May 2026 00:05:48 +0800
Subject: [PATCH] Disable futex_time64 again

---
Index: src/runtime/os_linux32.go
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
src/runtime/os_linux32.go | 6 ------
1 file changed, 6 deletions(-)

diff --git a/src/runtime/os_linux32.go b/src/runtime/os_linux32.go
--- a/src/runtime/os_linux32.go (revision 030384681641464bf71ed16500075c458363510f)
+++ b/src/runtime/os_linux32.go (date 1771666707318)
@@ -21,14 +21,14 @@
index 1ee1cdcaf90051..4aa42132d73739 100644
--- a/src/runtime/os_linux32.go
+++ b/src/runtime/os_linux32.go
@@ -24,9 +24,6 @@ var use64bitsTimeOn32bits bool

//go:nosplit
func futex(addr unsafe.Pointer, op int32, val uint32, ts *timespec, addr2 unsafe.Pointer, val3 uint32) int32 {
- if !isFutexTime32bitOnly.Load() {
- ret := futex_time64(addr, op, val, ts, addr2, val3)
- // futex_time64 is only supported on Linux 5.0+
- if ret != -_ENOSYS {
- return ret
- }
- isFutexTime32bitOnly.Store(true)
- if use64bitsTimeOn32bits {
- return futex_time64(addr, op, val, ts, addr2, val3)
- }
+ //if !isFutexTime32bitOnly.Load() {
+ // ret := futex_time64(addr, op, val, ts, addr2, val3)
+ // // futex_time64 is only supported on Linux 5.0+
+ // if ret != -_ENOSYS {
+ // return ret
+ // }
+ // isFutexTime32bitOnly.Store(true)
+ //}
// Downgrade ts.
var ts32 timespec32
var pts32 *timespec32
@@ -49,14 +49,14 @@
@@ -45,9 +42,6 @@ func timer_settime64(timerid int32, flags int32, new, old *itimerspec) int32

//go:nosplit
func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32 {
- if !isSetTime32bitOnly.Load() {
- ret := timer_settime64(timerid, flags, new, old)
- // timer_settime64 is only supported on Linux 5.0+
- if ret != -_ENOSYS {
- return ret
- }
- isSetTime32bitOnly.Store(true)
- if use64bitsTimeOn32bits {
- return timer_settime64(timerid, flags, new, old)
- }
+ //if !isSetTime32bitOnly.Load() {
+ // ret := timer_settime64(timerid, flags, new, old)
+ // // timer_settime64 is only supported on Linux 5.0+
+ // if ret != -_ENOSYS {
+ // return ret
+ // }
+ // isSetTime32bitOnly.Store(true)
+ //}

var newts, oldts itimerspec32
var new32, old32 *itimerspec32
var new32, old32 *itimerspec32
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ task("downloadGeoFiles") {
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat" to "geosite.dat",
// "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb" to "country.mmdb",
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb" to "ASN.mmdb",
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/BundleMRS.7z" to "BundleMRS.7z",
)

doLast {
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
android:fullBackupContent="@xml/full_backup_content"
android:icon="@mipmap/ic_launcher"
android:label="@string/application_name"
android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
Expand Down Expand Up @@ -218,4 +219,4 @@
</intent-filter>
</receiver>
</application>
</manifest>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.github.kr328.clash

import android.content.ComponentName
import android.content.pm.PackageManager
import androidx.core.content.pm.ShortcutManagerCompat
import com.github.kr328.clash.common.util.componentName
import com.github.kr328.clash.design.AppSettingsDesign
import com.github.kr328.clash.design.model.Behavior
Expand Down Expand Up @@ -75,9 +74,5 @@ class AppSettingsActivity : BaseActivity<AppSettingsDesign>(), Behavior {
newState,
PackageManager.DONT_KILL_APP
)
if (hide) {
// Prevent launcher activity not found.
ShortcutManagerCompat.removeAllDynamicShortcuts(this)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,18 @@ class ExternalControlActivity : Activity(), CoroutineScope by MainScope() {
}
val name = uri.getQueryParameter("name") ?: getString(R.string.new_profile)

val parsedInterval = uri.getQueryParameter("update-interval")?.toLongOrNull() ?: 0L
val updateInterval = if (parsedInterval > 0) parsedInterval.coerceAtLeast(15L) else 0L
val intervalMs = java.util.concurrent.TimeUnit.MINUTES.toMillis(updateInterval)

create(type, name).also {
patch(it, name, url, 0)
patch(it, name, url, intervalMs, null)
}
}
startActivity(PropertiesActivity::class.intent.setUUID(uuid))
finish()
}
return
}

Intents.ACTION_TOGGLE_CLASH -> if(Remote.broadcasts.clashRunning) {
Expand Down Expand Up @@ -98,4 +103,4 @@ class ExternalControlActivity : Activity(), CoroutineScope by MainScope() {
@Suppress("DEPRECATION")
overridePendingTransition(0, 0)
}
}
}
61 changes: 57 additions & 4 deletions app/src/main/java/com/github/kr328/clash/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.kr328.clash

import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
Expand All @@ -8,6 +9,10 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.github.kr328.clash.common.constants.Intents
import com.github.kr328.clash.common.util.intent
import com.github.kr328.clash.common.util.ticker
import com.github.kr328.clash.design.MainDesign
Expand All @@ -22,7 +27,7 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.selects.select
import kotlinx.coroutines.withContext
import java.util.concurrent.TimeUnit
import com.github.kr328.clash.design.R
import com.github.kr328.clash.design.R as DesignR

class MainActivity : BaseActivity<MainDesign>() {
override suspend fun main() {
Expand Down Expand Up @@ -111,8 +116,8 @@ class MainActivity : BaseActivity<MainDesign>() {
val active = withProfile { queryActive() }

if (active == null || !active.imported) {
showToast(R.string.no_profile_selected, ToastDuration.Long) {
setAction(R.string.profiles) {
showToast(DesignR.string.no_profile_selected, ToastDuration.Long) {
setAction(DesignR.string.profiles) {
startActivity(ProfilesActivity::class.intent)
}
}
Expand All @@ -133,7 +138,7 @@ class MainActivity : BaseActivity<MainDesign>() {
startClashService()
}
} catch (e: Exception) {
design?.showToast(R.string.unable_to_start_vpn, ToastDuration.Long)
design?.showToast(DesignR.string.unable_to_start_vpn, ToastDuration.Long)
}
}

Expand All @@ -157,5 +162,53 @@ class MainActivity : BaseActivity<MainDesign>() {
requestPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
}
}
setupShortcuts()
}

private fun setupShortcuts() {
// Skip dynamic shortcut setup when the app icon is hidden.
if (uiStore.hideAppIcon) return

val flags = Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or
Intent.FLAG_ACTIVITY_NO_ANIMATION

val toggle = ShortcutInfoCompat.Builder(this, "toggle_clash")
.setShortLabel(getString(DesignR.string.shortcut_toggle_short))
.setLongLabel(getString(DesignR.string.shortcut_toggle_long))
.setIcon(IconCompat.createWithResource(this, R.drawable.ic_toggle_all))
.setIntent(
Intent(Intents.ACTION_TOGGLE_CLASH)
.setClassName(this, ExternalControlActivity::class.java.name)
.addFlags(flags)
)
.setRank(0)
.build()

val start = ShortcutInfoCompat.Builder(this, "start_clash")
.setShortLabel(getString(DesignR.string.shortcut_start_short))
.setLongLabel(getString(DesignR.string.shortcut_start_long))
.setIcon(IconCompat.createWithResource(this, R.drawable.ic_toggle_on))
.setIntent(
Intent(Intents.ACTION_START_CLASH)
.setClassName(this, ExternalControlActivity::class.java.name)
.addFlags(flags)
)
.setRank(1)
.build()

val stop = ShortcutInfoCompat.Builder(this, "stop_clash")
.setShortLabel(getString(DesignR.string.shortcut_stop_short))
.setLongLabel(getString(DesignR.string.shortcut_stop_long))
.setIcon(IconCompat.createWithResource(this, R.drawable.ic_toggle_off))
.setIntent(
Intent(Intents.ACTION_STOP_CLASH)
.setClassName(this, ExternalControlActivity::class.java.name)
.addFlags(flags)
)
.setRank(2)
.build()

ShortcutManagerCompat.setDynamicShortcuts(this, listOf(toggle, start, stop))
}
}
71 changes: 10 additions & 61 deletions app/src/main/java/com/github/kr328/clash/MainApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,17 @@ package com.github.kr328.clash

import android.app.Application
import android.content.Context
import android.content.Intent
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.github.kr328.clash.common.Global
import com.github.kr328.clash.common.compat.currentProcessName
import com.github.kr328.clash.common.constants.Intents
import com.github.kr328.clash.common.log.Log
import com.github.kr328.clash.design.store.UiStore
import com.github.kr328.clash.remote.Remote
import com.github.kr328.clash.service.util.sendServiceRecreated
import com.github.kr328.clash.util.clashDir
import java.io.File
import java.io.FileOutputStream
import com.github.kr328.clash.design.R as DesignR


@Suppress("unused")
class MainApplication : Application() {
private val uiStore by lazy(LazyThreadSafetyMode.NONE) { UiStore(this) }

override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
Expand All @@ -39,63 +30,11 @@ class MainApplication : Application() {

if (processName == packageName) {
Remote.launch()
setupShortcuts()
} else {
sendServiceRecreated()
}
}

private fun setupShortcuts() {
if (uiStore.hideAppIcon) {
// Prevent launcher activity not found.
ShortcutManagerCompat.removeAllDynamicShortcuts(this)
return
}

val icon = IconCompat.createWithResource(this, R.mipmap.ic_launcher)
val flags = Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or
Intent.FLAG_ACTIVITY_NO_ANIMATION

val toggle = ShortcutInfoCompat.Builder(this, "toggle_clash")
.setShortLabel(getString(DesignR.string.shortcut_toggle_short))
.setLongLabel(getString(DesignR.string.shortcut_toggle_long))
.setIcon(icon)
.setIntent(
Intent(Intents.ACTION_TOGGLE_CLASH)
.setClassName(this, ExternalControlActivity::class.java.name)
.addFlags(flags)
)
.setRank(0)
.build()

val start = ShortcutInfoCompat.Builder(this, "start_clash")
.setShortLabel(getString(DesignR.string.shortcut_start_short))
.setLongLabel(getString(DesignR.string.shortcut_start_long))
.setIcon(icon)
.setIntent(
Intent(Intents.ACTION_START_CLASH)
.setClassName(this, ExternalControlActivity::class.java.name)
.addFlags(flags)
)
.setRank(1)
.build()

val stop = ShortcutInfoCompat.Builder(this, "stop_clash")
.setShortLabel(getString(DesignR.string.shortcut_stop_short))
.setLongLabel(getString(DesignR.string.shortcut_stop_long))
.setIcon(icon)
.setIntent(
Intent(Intents.ACTION_STOP_CLASH)
.setClassName(this, ExternalControlActivity::class.java.name)
.addFlags(flags)
)
.setRank(2)
.build()

ShortcutManagerCompat.setDynamicShortcuts(this, listOf(toggle, start, stop))
}

private fun extractGeoFiles() {
clashDir.mkdirs()

Expand Down Expand Up @@ -129,6 +68,16 @@ class MainApplication : Application() {
assets.open("ASN.mmdb").copyTo(it)
}
}

val bundleMRSFile = File(clashDir, "BundleMRS.7z")
if (bundleMRSFile.exists() && bundleMRSFile.lastModified() < updateDate) {
bundleMRSFile.delete()
}
if (!bundleMRSFile.exists()) {
FileOutputStream(bundleMRSFile).use {
assets.open("BundleMRS.7z").copyTo(it)
}
}
}

fun finalize() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class PropertiesActivity : BaseActivity<PropertiesDesign>() {

if (!canceled && profile != original) {
withProfile {
patch(profile.uuid, profile.name, profile.source, profile.interval)
patch(profile.uuid, profile.name, profile.source, profile.interval, profile.ageSecretKey)
}
}
}
Expand Down Expand Up @@ -92,7 +92,7 @@ class PropertiesActivity : BaseActivity<PropertiesDesign>() {
try {
withProcessing { updateStatus ->
withProfile {
patch(profile.uuid, profile.name, profile.source, profile.interval)
patch(profile.uuid, profile.name, profile.source, profile.interval, profile.ageSecretKey)

coroutineScope {
commit(profile.uuid) {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/github/kr328/clash/ProxyActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class ProxyActivity : BaseActivity<ProxyDesign>() {
design.updateGroup(
it.index,
group.proxies,
group.type == Proxy.Type.Selector,
group.type == "Selector",
state,
unorderedStates
)
Expand Down
Loading
Loading