From ab03e551da4e36f5af71759fbdbfce48bc7fe66f Mon Sep 17 00:00:00 2001
From: Kr328 <39107975+Kr328@users.noreply.github.com>
Date: Wed, 19 Feb 2020 15:28:32 +0800
Subject: [PATCH] add package list
---
app/build.gradle | 2 +-
app/src/main/AndroidManifest.xml | 5 +
.../clash/AccessControlPackagesActivity.kt | 68 +++++++++++
.../kr328/clash/adapter/PackagesAdapter.kt | 107 ++++++++++++++++++
.../kr328/clash/settings/BehaviorFragment.kt | 9 ++
.../kr328/clash/settings/NetworkFragment.kt | 12 +-
.../activity_access_control_packages.xml | 34 ++++++
app/src/main/res/layout/adapter_package.xml | 51 +++++++++
app/src/main/res/xml/settings_network.xml | 1 +
.../kr328/clash/service/ClashNotification.kt | 15 ++-
service/src/main/res/values-zh/strings.xml | 2 +-
11 files changed, 297 insertions(+), 9 deletions(-)
create mode 100644 app/src/main/java/com/github/kr328/clash/AccessControlPackagesActivity.kt
create mode 100644 app/src/main/java/com/github/kr328/clash/adapter/PackagesAdapter.kt
create mode 100644 app/src/main/res/layout/activity_access_control_packages.xml
create mode 100644 app/src/main/res/layout/adapter_package.xml
diff --git a/app/build.gradle b/app/build.gradle
index fe2fa11..fa9b2c1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,7 +11,7 @@ android {
applicationId "com.github.kr328.clash"
minSdkVersion 24
targetSdkVersion 29
- versionCode 10035
+ versionCode 10100
versionName "1.1.0"
}
buildTypes {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 56ea3bd..efefaa2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -83,6 +83,11 @@
android:label="@string/interface_"
android:exported="false"
android:configChanges="uiMode" />
+
(Channel.CONFLATED)
+
+ private var keyword: String = ""
+ private var sort: PackagesAdapter.Sort = PackagesAdapter.Sort.NAME
+ private var decrease: Boolean = false
+ private var systemApp: Boolean = true
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.activity_access_control_packages)
+ setSupportActionBar(toolbar)
+
+ launch {
+ val apps = withContext(Dispatchers.IO) {
+ val pm = packageManager
+ val packages = pm.getInstalledPackages(0)
+
+ packages.parallelStream()
+ .map {
+ PackagesAdapter.AppInfo(
+ it.packageName,
+ it.applicationInfo.loadLabel(pm).toString(),
+ it.applicationInfo.loadIcon(pm),
+ it.firstInstallTime, it.lastUpdateTime,
+ it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0)
+ }
+ .sorted(compareBy(PackagesAdapter.AppInfo::label))
+ .toList()
+ }
+
+ val adapter = PackagesAdapter(activity, apps)
+
+ mainList.adapter = adapter
+ mainList.layoutManager = LinearLayoutManager(activity)
+
+ progress.visibility = View.GONE
+
+ refreshChannel.send(Unit)
+
+ while ( isActive ) {
+ refreshChannel.receive()
+
+ adapter.applyFilter(keyword, sort, decrease, systemApp)
+
+ delay(200)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/kr328/clash/adapter/PackagesAdapter.kt b/app/src/main/java/com/github/kr328/clash/adapter/PackagesAdapter.kt
new file mode 100644
index 0000000..7776fd0
--- /dev/null
+++ b/app/src/main/java/com/github/kr328/clash/adapter/PackagesAdapter.kt
@@ -0,0 +1,107 @@
+package com.github.kr328.clash.adapter
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import android.graphics.drawable.Drawable
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.github.kr328.clash.R
+import com.google.android.material.checkbox.MaterialCheckBox
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import kotlin.streams.toList
+
+class PackagesAdapter(private val context: Context,
+ private val apps: List) :
+ RecyclerView.Adapter() {
+ data class AppInfo(val packageName: String, val label: String, val icon: Drawable,
+ val installTime: Long, val updateTime: Long, val isSystem: Boolean)
+
+ enum class Sort {
+ NAME, PACKAGE, INSTALL_TIME, UPDATE_TIME
+ }
+
+ private var filteredCache: List = apps
+
+ inner class Holder(view: View) : RecyclerView.ViewHolder(view) {
+ val root: View = view.findViewById(R.id.root)
+ val icon: ImageView = view.findViewById(R.id.icon)
+ val label: TextView = view.findViewById(R.id.label)
+ val packageName: TextView = view.findViewById(R.id.packageName)
+ val checkbox: MaterialCheckBox = view.findViewById(R.id.checkbox)
+ }
+
+ suspend fun applyFilter(keyword: String, sort: Sort, decrease: Boolean, systemApp: Boolean) {
+ withContext(Dispatchers.Default) {
+ val newList = apps.parallelStream()
+ .filter {
+ it.label.contains(keyword, true)
+ || it.packageName.contains(keyword, true)
+ || systemApp
+ || it.isSystem
+ }
+ .sorted { a, b ->
+ val result = when (sort) {
+ Sort.NAME -> a.label.compareTo(b.label, true)
+ Sort.PACKAGE -> a.packageName.compareTo(b.packageName)
+ Sort.INSTALL_TIME -> (a.installTime - b.installTime).toInt()
+ Sort.UPDATE_TIME -> (a.updateTime - b.updateTime).toInt()
+ }
+
+ if (decrease) -result else result
+ }
+ .toList()
+ val oldList = filteredCache
+
+ val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ return oldList[oldItemPosition].packageName == newList[newItemPosition].packageName
+ }
+
+ override fun getOldListSize(): Int {
+ return oldList.size
+ }
+
+ override fun getNewListSize(): Int {
+ return newList.size
+ }
+
+ override fun areContentsTheSame(
+ oldItemPosition: Int,
+ newItemPosition: Int
+ ): Boolean {
+ return areItemsTheSame(oldItemPosition, newItemPosition)
+ }
+
+ })
+
+ withContext(Dispatchers.Main) {
+ filteredCache = newList
+ result.dispatchUpdatesTo(this@PackagesAdapter)
+ }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
+ return Holder(LayoutInflater.from(context).inflate(R.layout.adapter_package, parent, false))
+ }
+
+ override fun getItemCount(): Int {
+ return filteredCache.size
+ }
+
+ override fun onBindViewHolder(holder: Holder, position: Int) {
+ val current = filteredCache[position]
+
+ holder.icon.setImageDrawable(current.icon)
+ holder.label.text = current.label
+ holder.packageName.text = current.packageName
+ }
+}
\ No newline at end of file
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 00465bc..1a54c2e 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
@@ -1,8 +1,11 @@
package com.github.kr328.clash.settings
import android.content.pm.PackageManager
+import android.os.Bundle
+import com.github.kr328.clash.BaseActivity
import com.github.kr328.clash.OnBootReceiver
import com.github.kr328.clash.R
+import com.github.kr328.clash.remote.Broadcasts
import com.github.kr328.clash.service.settings.ServiceSettings
import com.github.kr328.clash.service.util.componentName
@@ -19,6 +22,12 @@ class BehaviorFragment: BaseSettingFragment() {
}
}
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ findPreference(KEY_SHOW_TRAFFIC).isEnabled = !Broadcasts.clashRunning
+ }
+
override val xmlResourceId: Int
get() = R.xml.settings_behavior
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 6c84bec..1396c0e 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,10 +1,13 @@
package com.github.kr328.clash.settings
import android.os.Bundle
+import com.github.kr328.clash.AccessControlPackagesActivity
import com.github.kr328.clash.BaseActivity
import com.github.kr328.clash.R
import com.github.kr328.clash.preference.UiSettings
+import com.github.kr328.clash.remote.Broadcasts
import com.github.kr328.clash.service.settings.ServiceSettings
+import com.github.kr328.clash.service.util.intent
class NetworkFragment: BaseSettingFragment() {
companion object {
@@ -15,13 +18,18 @@ class NetworkFragment: BaseSettingFragment() {
private const val KEY_DNS_OVERRIDE = "dns_override"
private const val KEY_APPEND_SYS_DNS = "append_system_dns"
private const val KEY_ACCESS_CONTROL_MODE = "access_control_mode"
+ private const val KEY_ACCESS_CONTROL_PACKAGES = "access_control_packages"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if ((requireActivity() as BaseActivity).clashRunning)
- preferenceScreen.isEnabled = false
+ preferenceScreen.isEnabled = !Broadcasts.clashRunning
+
+ findPreference(KEY_ACCESS_CONTROL_PACKAGES).setOnPreferenceClickListener {
+ startActivity(AccessControlPackagesActivity::class.intent)
+ true
+ }
}
override fun onCreateDataStore(): SettingsDataStore {
diff --git a/app/src/main/res/layout/activity_access_control_packages.xml b/app/src/main/res/layout/activity_access_control_packages.xml
new file mode 100644
index 0000000..63bc4ce
--- /dev/null
+++ b/app/src/main/res/layout/activity_access_control_packages.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/adapter_package.xml b/app/src/main/res/layout/adapter_package.xml
new file mode 100644
index 0000000..aa546c5
--- /dev/null
+++ b/app/src/main/res/layout/adapter_package.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/settings_network.xml b/app/src/main/res/xml/settings_network.xml
index 489c9fd..c2a0335 100644
--- a/app/src/main/res/xml/settings_network.xml
+++ b/app/src/main/res/xml/settings_network.xml
@@ -40,6 +40,7 @@
android:entryValues="@array/access_control_mode_value"
android:defaultValue="access_control_mode_all" />
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 aab95b2..afb182a 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
@@ -19,7 +19,7 @@ import com.github.kr328.clash.core.utils.asSpeedString
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
-class ClashNotification(private val context: ClashService, enableRefresh: Boolean) :
+class ClashNotification(private val context: ClashService, private val enableRefresh: Boolean) :
CoroutineScope by context {
companion object {
private const val CLASH_STATUS_NOTIFICATION_CHANNEL = "clash_status_channel"
@@ -63,7 +63,7 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
init {
createNotificationChannel()
- notifyBaseNotification()
+ updateBase()
if (enableRefresh) {
launch {
@@ -119,7 +119,9 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
}
fun destroy() {
- context.unregisterReceiver(observer)
+ if ( enableRefresh )
+ context.unregisterReceiver(observer)
+
context.stopForeground(true)
}
@@ -127,11 +129,14 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
launch {
this@ClashNotification.profile = profile
- update()
+ if ( enableRefresh )
+ update()
+ else
+ updateBase()
}
}
- private fun notifyBaseNotification() {
+ private fun updateBase() {
val notification = baseBuilder
.setContentTitle(profile)
.setContentText(context.getText(R.string.running))
diff --git a/service/src/main/res/values-zh/strings.xml b/service/src/main/res/values-zh/strings.xml
index 83e2ced..ffaf39a 100644
--- a/service/src/main/res/values-zh/strings.xml
+++ b/service/src/main/res/values-zh/strings.xml
@@ -12,5 +12,5 @@
更新 %s 失败
正在更新 %s
正在运行
- Tun 服务
+ Tun 设备服务
\ No newline at end of file