From 0a05d768509fb2833e8d3be6f79fa71de1b99028 Mon Sep 17 00:00:00 2001
From: Kr328 <39107975+Kr328@users.noreply.github.com>
Date: Mon, 2 Dec 2019 23:55:00 +0800
Subject: [PATCH] application settings & start on boot
---
app/src/main/AndroidManifest.xml | 15 ++++
.../kr328/clash/BootCompleteReceiver.kt | 19 +++++
.../github/kr328/clash/ClashStartService.kt | 85 +++++++++++++++++++
.../com/github/kr328/clash/MainActivity.kt | 40 ++++++++-
.../com/github/kr328/clash/ProxyActivity.kt | 13 +--
.../kr328/clash/SettingAccessActivity.kt | 53 ++++++------
.../kr328/clash/SettingApplicationActivity.kt | 82 ++++++++++++++++++
.../kr328/clash/SettingProxyActivity.kt | 14 +--
.../kr328/clash/adapter/ProxyAdapter.kt | 42 +++++----
.../com/github/kr328/clash/model/ListProxy.kt | 11 ++-
app/src/main/res/drawable/ic_boot.xml | 9 ++
app/src/main/res/drawable/ic_cloud.xml | 10 +--
app/src/main/res/drawable/ic_expand_less.xml | 10 +--
app/src/main/res/drawable/ic_expand_more.xml | 10 +--
app/src/main/res/drawable/ic_settings.xml | 10 +--
.../main/res/drawable/ic_settings_color.xml | 10 +--
app/src/main/res/drawable/ic_url_test.xml | 10 +--
app/src/main/res/drawable/ic_vert.xml | 10 +--
app/src/main/res/layout/activity_proxies.xml | 1 +
.../res/layout/activity_setting_access.xml | 14 +--
.../layout/activity_setting_application.xml | 23 +++++
.../main/res/layout/activity_setting_main.xml | 4 +-
.../res/layout/activity_setting_proxy.xml | 9 +-
.../main/res/layout/adapter_access_app.xml | 6 +-
.../main/res/layout/adapter_proxy_item.xml | 5 +-
.../main/res/layout/preference_proxy_item.xml | 4 +-
app/src/main/res/layout/view_title.xml | 3 +-
app/src/main/res/values/attrs.xml | 8 +-
app/src/main/res/values/strings.xml | 7 ++
app/src/main/res/xml/setting_application.xml | 11 +++
app/src/main/res/xml/setting_main.xml | 11 ++-
app/src/main/res/xml/setting_proxy.xml | 5 +-
.../kr328/clash/service/ClashService.kt | 6 +-
.../github/kr328/clash/service/TunService.kt | 4 +
34 files changed, 457 insertions(+), 117 deletions(-)
create mode 100644 app/src/main/java/com/github/kr328/clash/BootCompleteReceiver.kt
create mode 100644 app/src/main/java/com/github/kr328/clash/ClashStartService.kt
create mode 100644 app/src/main/java/com/github/kr328/clash/SettingApplicationActivity.kt
create mode 100644 app/src/main/res/drawable/ic_boot.xml
create mode 100644 app/src/main/res/layout/activity_setting_application.xml
create mode 100644 app/src/main/res/xml/setting_application.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4a0ebfa..31bfcad 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
package="com.github.kr328.clash">
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/github/kr328/clash/BootCompleteReceiver.kt b/app/src/main/java/com/github/kr328/clash/BootCompleteReceiver.kt
new file mode 100644
index 0000000..bc334bc
--- /dev/null
+++ b/app/src/main/java/com/github/kr328/clash/BootCompleteReceiver.kt
@@ -0,0 +1,19 @@
+package com.github.kr328.clash
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+
+class BootCompleteReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (Intent.ACTION_BOOT_COMPLETED != intent?.action || context == null)
+ return
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ context.startForegroundService(Intent(context, ClashStartService::class.java))
+ } else {
+ context.startService(Intent(context, ClashStartService::class.java))
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/kr328/clash/ClashStartService.kt b/app/src/main/java/com/github/kr328/clash/ClashStartService.kt
new file mode 100644
index 0000000..f8412b6
--- /dev/null
+++ b/app/src/main/java/com/github/kr328/clash/ClashStartService.kt
@@ -0,0 +1,85 @@
+package com.github.kr328.clash
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.net.VpnService
+import android.os.Binder
+import android.os.Build
+import android.os.IBinder
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import com.github.kr328.clash.service.ClashService
+import com.github.kr328.clash.service.TunService
+import kotlin.concurrent.thread
+
+class ClashStartService : Service() {
+ companion object {
+ private const val NOTIFICATION_CHANNEL_ID = "clash_start_service_notification_channel"
+ private const val NOTIFICATION_ID = 142
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ NotificationManagerCompat.from(this).apply {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ createNotificationChannel(NotificationChannel(NOTIFICATION_CHANNEL_ID,
+ getString(R.string.clash_start_service_notification_channel),
+ NotificationManager.IMPORTANCE_DEFAULT))
+ }
+ }
+
+ val notification = NotificationCompat
+ .Builder(this, NOTIFICATION_CHANNEL_ID)
+ .setContentTitle(getString(R.string.clash_start_service_notification))
+ .setSmallIcon(R.drawable.ic_notification_icon)
+ .build()
+
+ startForeground(NOTIFICATION_ID, notification)
+
+ thread {
+ getSharedPreferences("application", Context.MODE_PRIVATE).apply {
+ when (getString(
+ MainApplication.KEY_PROXY_MODE,
+ MainApplication.PROXY_MODE_VPN
+ )) {
+ MainApplication.PROXY_MODE_VPN -> {
+ if (VpnService.prepare(this@ClashStartService) == null)
+ startService(
+ Intent(
+ this@ClashStartService,
+ TunService::class.java
+ )
+ )
+ }
+ MainApplication.PROXY_MODE_PROXY_ONLY -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(
+ Intent(
+ this@ClashStartService,
+ ClashService::class.java
+ )
+ )
+ } else {
+ startService(
+ Intent(
+ this@ClashStartService,
+ ClashService::class.java
+ )
+ )
+ }
+ }
+ }
+ }
+
+ stopSelf()
+ }
+
+ return START_NOT_STICKY
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return Binder()
+ }
+}
\ No newline at end of file
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 5d55efc..11e9e9e 100644
--- a/app/src/main/java/com/github/kr328/clash/MainActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/MainActivity.kt
@@ -1,8 +1,10 @@
package com.github.kr328.clash
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.net.VpnService
+import android.os.Build
import android.os.Bundle
import android.view.View
import com.github.kr328.clash.core.event.BandwidthEvent
@@ -10,6 +12,7 @@ import com.github.kr328.clash.core.event.Event
import com.github.kr328.clash.core.event.ProcessEvent
import com.github.kr328.clash.core.event.ProfileChangedEvent
import com.github.kr328.clash.core.utils.ByteFormatter
+import com.github.kr328.clash.service.ClashService
import com.github.kr328.clash.service.TunService
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main_clash_status.*
@@ -56,9 +59,40 @@ class MainActivity : BaseActivity() {
it.stop()
}
else -> runOnUiThread {
- VpnService.prepare(this@MainActivity)?.apply {
- startActivityForResult(this, VPN_REQUEST_CODE)
- } ?: startService(Intent(this@MainActivity, TunService::class.java))
+ getSharedPreferences("application", Context.MODE_PRIVATE).apply {
+ when (getString(
+ MainApplication.KEY_PROXY_MODE,
+ MainApplication.PROXY_MODE_VPN
+ )) {
+ MainApplication.PROXY_MODE_VPN -> {
+ VpnService.prepare(this@MainActivity)?.apply {
+ startActivityForResult(this, VPN_REQUEST_CODE)
+ } ?: startService(
+ Intent(
+ this@MainActivity,
+ TunService::class.java
+ )
+ )
+ }
+ MainApplication.PROXY_MODE_PROXY_ONLY -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(
+ Intent(
+ this@MainActivity,
+ ClashService::class.java
+ )
+ )
+ } else {
+ startService(
+ Intent(
+ this@MainActivity,
+ ClashService::class.java
+ )
+ )
+ }
+ }
+ }
+ }
}
}
}
diff --git a/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt b/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt
index 4533a26..747d9f0 100644
--- a/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt
@@ -14,7 +14,7 @@ class ProxyActivity : BaseActivity() {
setSupportActionBar(activity_proxies_toolbar)
activity_proxies_list.also {
- it.adapter = ProxyAdapter(this) {p, s ->
+ it.adapter = ProxyAdapter(this) { p, s ->
runClash { clash ->
clash.setSelectProxy(p, s)
}
@@ -63,7 +63,8 @@ class ProxyActivity : BaseActivity() {
})
)
.flatMap {
- val header = ListProxy.ListProxyHeader(it.value.name, it.value.type, it.value.now)
+ val header =
+ ListProxy.ListProxyHeader(it.value.name, it.value.type, it.value.now)
sequenceOf(header) +
it.value.all
@@ -80,8 +81,8 @@ class ProxyActivity : BaseActivity() {
.asSequence()
}
.mapIndexed { index, listProxy ->
- if ( listProxy is ListProxy.ListProxyItem ) {
- if ( listProxy.name.hashCode() == listProxy.header.now )
+ if (listProxy is ListProxy.ListProxyItem) {
+ if (listProxy.name.hashCode() == listProxy.header.now)
listProxy.header.now = index
}
listProxy
@@ -97,11 +98,11 @@ class ProxyActivity : BaseActivity() {
.filterIsInstance()
.map { it.now }
- val changed = if ( listDataOldChanged.size != listDataChanged.size )
+ val changed = if (listDataOldChanged.size != listDataChanged.size)
(0..listData.size).toList()
else {
listDataChanged.mapIndexed { index, i ->
- if ( i == listDataOldChanged[index] )
+ if (i == listDataOldChanged[index])
emptyList()
else
listOf(listDataOldChanged[index], i)
diff --git a/app/src/main/java/com/github/kr328/clash/SettingAccessActivity.kt b/app/src/main/java/com/github/kr328/clash/SettingAccessActivity.kt
index 59ab08c..dd8f0b5 100644
--- a/app/src/main/java/com/github/kr328/clash/SettingAccessActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/SettingAccessActivity.kt
@@ -16,7 +16,7 @@ import kotlin.concurrent.thread
class SettingAccessActivity : BaseActivity() {
private data class AppInfo(val packageName: String, val name: String, val icon: Drawable)
- private class AppListAdapter(val context: Context):
+ private class AppListAdapter(val context: Context) :
RecyclerView.Adapter() {
var applications: List = emptyList()
@@ -30,8 +30,10 @@ class SettingAccessActivity : BaseActivity() {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
- return Holder(LayoutInflater.from(context)
- .inflate(R.layout.adapter_access_app, parent, false))
+ return Holder(
+ LayoutInflater.from(context)
+ .inflate(R.layout.adapter_access_app, parent, false)
+ )
}
override fun getItemCount(): Int {
@@ -47,7 +49,7 @@ class SettingAccessActivity : BaseActivity() {
holder.checkbox.isChecked = current.packageName in selected
holder.view.setOnClickListener {
- if ( holder.checkbox.isChecked )
+ if (holder.checkbox.isChecked)
selected.remove(current.packageName)
else
selected.add(current.packageName)
@@ -107,7 +109,7 @@ class SettingAccessActivity : BaseActivity() {
val settings = it.settingService
runOnUiThread {
- when ( settings.accessControlMode ) {
+ when (settings.accessControlMode) {
ClashSettingService.ACCESS_CONTROL_MODE_ALLOW_ALL ->
activity_setting_access_allow_all.performClick()
ClashSettingService.ACCESS_CONTROL_MODE_ALLOW ->
@@ -124,9 +126,11 @@ class SettingAccessActivity : BaseActivity() {
exclude.contains(it.packageName)
}
.map { app ->
- AppInfo(app.packageName,
+ AppInfo(
+ app.packageName,
app.loadLabel(packageManager).toString(),
- app.loadIcon(packageManager))
+ app.loadIcon(packageManager)
+ )
}
.sortedBy { app ->
app.name
@@ -164,10 +168,12 @@ class SettingAccessActivity : BaseActivity() {
else -> return@runClash
}
- if ( listLoaded )
- it.settingService.setAccessControl(mode,
+ if (listLoaded)
+ it.settingService.setAccessControl(
+ mode,
(activity_setting_access_app_list.adapter as AppListAdapter)
- .selected.toTypedArray())
+ .selected.toTypedArray()
+ )
}
}
@@ -177,9 +183,9 @@ class SettingAccessActivity : BaseActivity() {
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when ( item.itemId ) {
+ when (item.itemId) {
R.id.menu_setting_access_hide -> {
- if ( hidden ) {
+ if (hidden) {
activity_setting_access_allow_all.visibility = View.VISIBLE
activity_setting_access_allow.visibility = View.VISIBLE
activity_setting_access_disallow.visibility = View.VISIBLE
@@ -187,13 +193,12 @@ class SettingAccessActivity : BaseActivity() {
item.title = getString(R.string.access_setting_hide_header)
hidden = false
- }
- else {
- if ( !activity_setting_access_allow_all.isChecked )
+ } else {
+ if (!activity_setting_access_allow_all.isChecked)
activity_setting_access_allow_all.visibility = View.GONE
- if ( !activity_setting_access_allow.isChecked )
+ if (!activity_setting_access_allow.isChecked)
activity_setting_access_allow.visibility = View.GONE
- if ( !activity_setting_access_disallow.isChecked )
+ if (!activity_setting_access_disallow.isChecked)
activity_setting_access_disallow.visibility = View.GONE
item.title = getString(R.string.access_setting_show_header)
@@ -218,7 +223,8 @@ class SettingAccessActivity : BaseActivity() {
R.id.menu_setting_access_select_invert -> {
thread {
(activity_setting_access_app_list.adapter as AppListAdapter).apply {
- selected = (applications.map { it.packageName }.toSet() - selected).toMutableSet()
+ selected =
+ (applications.map { it.packageName }.toSet() - selected).toMutableSet()
}
runOnUiThread {
@@ -242,23 +248,22 @@ class SettingAccessActivity : BaseActivity() {
}
private fun updateListStatus() {
- if ( showList )
+ if (showList)
activity_setting_access_divider.visibility = View.VISIBLE
else
activity_setting_access_divider.visibility = View.GONE
- if ( showList ) {
- if ( listLoaded )
+ if (showList) {
+ if (listLoaded)
activity_setting_access_loading.visibility = View.GONE
else
activity_setting_access_loading.visibility = View.VISIBLE
- }
- else
+ } else
activity_setting_access_loading.visibility = View.GONE
- if ( showList && listLoaded )
+ if (showList && listLoaded)
activity_setting_access_app_list.visibility = View.VISIBLE
else
activity_setting_access_app_list.visibility = View.GONE
diff --git a/app/src/main/java/com/github/kr328/clash/SettingApplicationActivity.kt b/app/src/main/java/com/github/kr328/clash/SettingApplicationActivity.kt
new file mode 100644
index 0000000..af5b3b1
--- /dev/null
+++ b/app/src/main/java/com/github/kr328/clash/SettingApplicationActivity.kt
@@ -0,0 +1,82 @@
+package com.github.kr328.clash
+
+import android.content.ComponentName
+import android.content.SharedPreferences
+import android.content.pm.PackageManager
+import android.os.Bundle
+import androidx.preference.CheckBoxPreference
+import androidx.preference.PreferenceFragmentCompat
+import kotlinx.android.synthetic.main.activity_setting_application.*
+import kotlin.concurrent.thread
+
+class SettingApplicationActivity : BaseActivity() {
+ companion object {
+ const val KEY_START_ON_BOOT = "key_application_start_on_boot"
+ }
+
+ class Fragment : PreferenceFragmentCompat(),
+ SharedPreferences.OnSharedPreferenceChangeListener {
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.setting_application, rootKey)
+
+ preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ val status = requireContext().packageManager
+ .getComponentEnabledSetting(
+ ComponentName.createRelative(
+ requireContext(),
+ BootCompleteReceiver::class.java.name
+ )
+ )
+
+ findPreference(KEY_START_ON_BOOT)?.isChecked =
+ status == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ }
+
+ override fun onSharedPreferenceChanged(
+ sharedPreferences: SharedPreferences?,
+ key: String?
+ ) {
+ when (key) {
+ KEY_START_ON_BOOT -> {
+ val enabled = sharedPreferences!!.getBoolean(key, false)
+
+ thread {
+ if (enabled) {
+ requireContext().packageManager
+ .setComponentEnabledSetting(
+ ComponentName.createRelative(
+ requireContext(),
+ BootCompleteReceiver::class.java.name
+ ),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ } else {
+ requireContext().packageManager
+ .setComponentEnabledSetting(
+ ComponentName.createRelative(
+ requireContext(),
+ BootCompleteReceiver::class.java.name
+ ),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_setting_application)
+
+ setSupportActionBar(activity_setting_application_toolbar)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/kr328/clash/SettingProxyActivity.kt b/app/src/main/java/com/github/kr328/clash/SettingProxyActivity.kt
index 8bb3da8..f6da6ce 100644
--- a/app/src/main/java/com/github/kr328/clash/SettingProxyActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/SettingProxyActivity.kt
@@ -30,7 +30,8 @@ class SettingProxyActivity : BaseActivity() {
requireActivity().runOnUiThread {
findPreference(KEY_IPV6_SUPPORT)?.isChecked = ipv6
- findPreference(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked = privateNetwork
+ findPreference(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked =
+ privateNetwork
}
}
}
@@ -41,8 +42,11 @@ class SettingProxyActivity : BaseActivity() {
(requireActivity() as SettingProxyActivity).runClash {
val settings = it.settingService
- settings.isIPv6Enabled = findPreference(KEY_IPV6_SUPPORT)?.isChecked ?: true
- settings.isBypassPrivateNetwork = findPreference(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked ?: true
+ settings.isIPv6Enabled =
+ findPreference(KEY_IPV6_SUPPORT)?.isChecked ?: true
+ settings.isBypassPrivateNetwork =
+ findPreference(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked
+ ?: true
}
}
}
@@ -70,7 +74,7 @@ class SettingProxyActivity : BaseActivity() {
}
getSharedPreferences("application", Context.MODE_PRIVATE).apply {
- when ( getString(MainApplication.KEY_PROXY_MODE, MainApplication.PROXY_MODE_VPN) ) {
+ when (getString(MainApplication.KEY_PROXY_MODE, MainApplication.PROXY_MODE_VPN)) {
MainApplication.PROXY_MODE_VPN ->
activity_setting_proxy_vpn_mode.performClick()
MainApplication.PROXY_MODE_PROXY_ONLY ->
@@ -81,7 +85,7 @@ class SettingProxyActivity : BaseActivity() {
override fun onStop() {
super.onStop()
-
+
getSharedPreferences("application", Context.MODE_PRIVATE).edit {
when {
activity_setting_proxy_vpn_mode.isChecked ->
diff --git a/app/src/main/java/com/github/kr328/clash/adapter/ProxyAdapter.kt b/app/src/main/java/com/github/kr328/clash/adapter/ProxyAdapter.kt
index 268148b..3494ea6 100644
--- a/app/src/main/java/com/github/kr328/clash/adapter/ProxyAdapter.kt
+++ b/app/src/main/java/com/github/kr328/clash/adapter/ProxyAdapter.kt
@@ -13,11 +13,12 @@ import com.github.kr328.clash.core.model.ProxyPacket
import com.github.kr328.clash.model.ListProxy
import com.google.android.material.card.MaterialCardView
-class ProxyAdapter(private val context: Context, val listener: (String, String) -> Unit) : RecyclerView.Adapter() {
+class ProxyAdapter(private val context: Context, val listener: (String, String) -> Unit) :
+ RecyclerView.Adapter() {
var elements: List = emptyList()
var clickable: Boolean = false
- class HeaderHolder(view: View): RecyclerView.ViewHolder(view) {
+ class HeaderHolder(view: View) : RecyclerView.ViewHolder(view) {
val name: TextView = view.findViewById(R.id.adapter_proxy_header_name)
val test: View = view.findViewById(R.id.adapter_proxy_header_url_test)
}
@@ -30,7 +31,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
}
override fun getItemViewType(position: Int): Int {
- return when ( elements[position] ) {
+ return when (elements[position]) {
is ListProxy.ListProxyItem -> 1
is ListProxy.ListProxyHeader -> 2
else -> throw IllegalArgumentException("Invalid type")
@@ -39,8 +40,20 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
- 1 -> ItemHolder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy_item, parent, false))
- 2 -> HeaderHolder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy_header, parent, false))
+ 1 -> ItemHolder(
+ LayoutInflater.from(context).inflate(
+ R.layout.adapter_proxy_item,
+ parent,
+ false
+ )
+ )
+ 2 -> HeaderHolder(
+ LayoutInflater.from(context).inflate(
+ R.layout.adapter_proxy_header,
+ parent,
+ false
+ )
+ )
else -> throw IllegalArgumentException("Invalid type")
}
}
@@ -58,9 +71,9 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
fun getLayoutManager(): GridLayoutManager {
return GridLayoutManager(context, 2).apply {
- spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {
+ spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
- return when ( elements[position] ) {
+ return when (elements[position]) {
is ListProxy.ListProxyHeader -> 2
is ListProxy.ListProxyItem -> 1
else -> throw IllegalArgumentException("Invalid type")
@@ -71,20 +84,19 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
}
private fun bindItemView(holder: ItemHolder, current: ListProxy.ListProxyItem, position: Int) {
- if ( position == current.header.now ) {
+ if (position == current.header.now) {
holder.card.setCardBackgroundColor(context.getColor(R.color.colorAccent))
holder.name.setTextColor(Color.WHITE)
holder.type.setTextColor(Color.WHITE - 0x22222222)
holder.delay.setTextColor(Color.WHITE - 0x11111111)
- }
- else {
+ } else {
holder.card.setCardBackgroundColor(Color.WHITE)
holder.name.setTextColor(Color.BLACK)
holder.type.setTextColor(Color.LTGRAY)
holder.delay.setTextColor(Color.DKGRAY)
}
- if ( current.header.type == ProxyPacket.Type.SELECT ) {
+ if (current.header.type == ProxyPacket.Type.SELECT) {
holder.card.isFocusable = true
holder.card.isClickable = true
holder.card.setOnClickListener {
@@ -98,8 +110,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
listener(element.header.name, element.name)
}
- }
- else {
+ } else {
holder.card.setOnClickListener(null)
holder.card.isFocusable = false
holder.card.isClickable = false
@@ -111,7 +122,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
if (current.delay > 0) {
current.delay.toString()
} else {
- if ( current.header.type != ProxyPacket.Type.SELECT )
+ if (current.header.type != ProxyPacket.Type.SELECT)
"N/A"
else
""
@@ -121,6 +132,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
private fun bindHeaderView(holder: HeaderHolder, current: ListProxy.ListProxyHeader) {
holder.name.text = current.name
- holder.test.visibility = if ( current.type == ProxyPacket.Type.SELECT ) View.VISIBLE else View.GONE
+ holder.test.visibility =
+ if (current.type == ProxyPacket.Type.SELECT) View.VISIBLE else View.GONE
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/kr328/clash/model/ListProxy.kt b/app/src/main/java/com/github/kr328/clash/model/ListProxy.kt
index 1c98f9e..b86a8f2 100644
--- a/app/src/main/java/com/github/kr328/clash/model/ListProxy.kt
+++ b/app/src/main/java/com/github/kr328/clash/model/ListProxy.kt
@@ -3,6 +3,13 @@ package com.github.kr328.clash.model
import com.github.kr328.clash.core.model.ProxyPacket
interface ListProxy {
- data class ListProxyHeader(val name: String, val type: ProxyPacket.Type, var now: Int): ListProxy
- data class ListProxyItem(val name: String, val type: String, val delay: Long, val header: ListProxyHeader): ListProxy
+ data class ListProxyHeader(val name: String, val type: ProxyPacket.Type, var now: Int) :
+ ListProxy
+
+ data class ListProxyItem(
+ val name: String,
+ val type: String,
+ val delay: Long,
+ val header: ListProxyHeader
+ ) : ListProxy
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_boot.xml b/app/src/main/res/drawable/ic_boot.xml
new file mode 100644
index 0000000..b179b42
--- /dev/null
+++ b/app/src/main/res/drawable/ic_boot.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_cloud.xml b/app/src/main/res/drawable/ic_cloud.xml
index 0b9c887..ef9691d 100644
--- a/app/src/main/res/drawable/ic_cloud.xml
+++ b/app/src/main/res/drawable/ic_cloud.xml
@@ -1,9 +1,9 @@
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z" />
diff --git a/app/src/main/res/drawable/ic_expand_less.xml b/app/src/main/res/drawable/ic_expand_less.xml
index 3afdf96..7b6a656 100644
--- a/app/src/main/res/drawable/ic_expand_less.xml
+++ b/app/src/main/res/drawable/ic_expand_less.xml
@@ -1,9 +1,9 @@
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z" />
diff --git a/app/src/main/res/drawable/ic_expand_more.xml b/app/src/main/res/drawable/ic_expand_more.xml
index 8d57dbc..c1f391b 100644
--- a/app/src/main/res/drawable/ic_expand_more.xml
+++ b/app/src/main/res/drawable/ic_expand_more.xml
@@ -1,9 +1,9 @@
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z" />
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
index 24a5623..a671514 100644
--- a/app/src/main/res/drawable/ic_settings.xml
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -1,9 +1,9 @@
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z" />
diff --git a/app/src/main/res/drawable/ic_settings_color.xml b/app/src/main/res/drawable/ic_settings_color.xml
index b67a13a..b11ad71 100644
--- a/app/src/main/res/drawable/ic_settings_color.xml
+++ b/app/src/main/res/drawable/ic_settings_color.xml
@@ -1,9 +1,9 @@
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z" />
diff --git a/app/src/main/res/drawable/ic_url_test.xml b/app/src/main/res/drawable/ic_url_test.xml
index a3c81cc..4efdc7f 100644
--- a/app/src/main/res/drawable/ic_url_test.xml
+++ b/app/src/main/res/drawable/ic_url_test.xml
@@ -1,9 +1,9 @@
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ android:pathData="M7,2v11h3v9l7,-12h-4l4,-8z" />
diff --git a/app/src/main/res/drawable/ic_vert.xml b/app/src/main/res/drawable/ic_vert.xml
index 5176d8a..7b7f195 100644
--- a/app/src/main/res/drawable/ic_vert.xml
+++ b/app/src/main/res/drawable/ic_vert.xml
@@ -1,9 +1,9 @@
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
diff --git a/app/src/main/res/layout/activity_proxies.xml b/app/src/main/res/layout/activity_proxies.xml
index d1c73f1..396fe32 100644
--- a/app/src/main/res/layout/activity_proxies.xml
+++ b/app/src/main/res/layout/activity_proxies.xml
@@ -21,6 +21,7 @@
android:layout_marginEnd="15dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
+
-
+ android:layout_height="wrap_content" />
+ android:layout_height="wrap_content" />
+ android:layout_height="wrap_content" />
+ android:background="@color/lightGray" />
+ android:layout_height="wrap_content" />
+ android:visibility="gone" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_setting_application.xml b/app/src/main/res/layout/activity_setting_application.xml
new file mode 100644
index 0000000..fbaec5b
--- /dev/null
+++ b/app/src/main/res/layout/activity_setting_application.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_setting_main.xml b/app/src/main/res/layout/activity_setting_main.xml
index 912cb8b..8e13aee 100644
--- a/app/src/main/res/layout/activity_setting_main.xml
+++ b/app/src/main/res/layout/activity_setting_main.xml
@@ -7,6 +7,7 @@
+
-
+ android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_setting_proxy.xml b/app/src/main/res/layout/activity_setting_proxy.xml
index 04aeb32..e813a30 100644
--- a/app/src/main/res/layout/activity_setting_proxy.xml
+++ b/app/src/main/res/layout/activity_setting_proxy.xml
@@ -9,6 +9,7 @@
+
+ app:summary="@string/proxy_setting_vpn_mode_summary" />
+ app:summary="@string/proxy_setting_proxy_mode_summary" />
+ android:background="@color/lightGray" />
+ android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/adapter_access_app.xml b/app/src/main/res/layout/adapter_access_app.xml
index 35d15d6..468f61c 100644
--- a/app/src/main/res/layout/adapter_access_app.xml
+++ b/app/src/main/res/layout/adapter_access_app.xml
@@ -24,17 +24,19 @@
android:layout_toStartOf="@id/adapter_access_app_checkbox"
android:layout_centerVertical="true"
android:orientation="vertical">
+
+
+ android:layout_height="wrap_content" />
+ android:layout_height="70dp" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/adapter_proxy_item.xml b/app/src/main/res/layout/adapter_proxy_item.xml
index 45aa63b..a6f5bcd 100644
--- a/app/src/main/res/layout/adapter_proxy_item.xml
+++ b/app/src/main/res/layout/adapter_proxy_item.xml
@@ -12,6 +12,7 @@
app:cardUseCompatPadding="true"
app:cardElevation="2dp"
app:cardCornerRadius="5dp">
+
+ android:layout_alignParentStart="true" />
+ android:maxLines="1" />
+
+
+ android:layout_height="wrap_content" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_title.xml b/app/src/main/res/layout/view_title.xml
index 3509b84..d829e29 100644
--- a/app/src/main/res/layout/view_title.xml
+++ b/app/src/main/res/layout/view_title.xml
@@ -1,6 +1,7 @@
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 8cba8da..456fff9 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -13,9 +13,9 @@
-
-
-
-
+
+
+
+
\ 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 46693ec..8fe895f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -72,4 +72,11 @@
Select All
Select Invert
Clear Selection
+
+ Behavior
+ Start on Boot
+ Start clash on system boot
+
+ Clash Start Service
+ Starting Clash
diff --git a/app/src/main/res/xml/setting_application.xml b/app/src/main/res/xml/setting_application.xml
new file mode 100644
index 0000000..a91f2c2
--- /dev/null
+++ b/app/src/main/res/xml/setting_application.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/setting_main.xml b/app/src/main/res/xml/setting_main.xml
index 04a0cd7..f8528ce 100644
--- a/app/src/main/res/xml/setting_main.xml
+++ b/app/src/main/res/xml/setting_main.xml
@@ -1,10 +1,19 @@
+
+
+
-
\ No newline at end of file
diff --git a/app/src/main/res/xml/setting_proxy.xml b/app/src/main/res/xml/setting_proxy.xml
index 50317d9..cef26c4 100644
--- a/app/src/main/res/xml/setting_proxy.xml
+++ b/app/src/main/res/xml/setting_proxy.xml
@@ -4,7 +4,7 @@
+ android:summary="@string/proxy_setting_vpn_setting_bypass_private_network_summary" />
-
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 37fd0bd..41f75d1 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
@@ -85,7 +85,6 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
notification.setVpn(true)
clash.startTunDevice(fd.fileDescriptor, mtu)
- fd.close()
} catch (e: Exception) {
Log.e("Start tun failure", e)
@@ -93,6 +92,9 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
ErrorEvent(ErrorEvent.Type.START_FAILURE, e.toString())
)
}
+ finally {
+ fd.close()
+ }
}
override fun getEventService(): IClashEventService {
@@ -226,6 +228,8 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
eventService.preformBandwidthEvent(BandwidthEvent(0))
notification.cancel()
+
+ stopSelf()
}
}
}
diff --git a/service/src/main/java/com/github/kr328/clash/service/TunService.kt b/service/src/main/java/com/github/kr328/clash/service/TunService.kt
index a1fc76a..1f7dc8c 100644
--- a/service/src/main/java/com/github/kr328/clash/service/TunService.kt
+++ b/service/src/main/java/com/github/kr328/clash/service/TunService.kt
@@ -107,10 +107,14 @@ class TunService : VpnService(), IClashEventObserver {
clash.start()
else
stopSelf()
+
+ Log.i("STOPPED")
}
ProcessEvent.STARTED -> {
start = false
clash.startTunDevice(fileDescriptor, VPN_MTU)
+
+ Log.i("STARTED")
}
}
}