Commit 42f507ec authored by Mygod's avatar Mygod

Rework listenForPackageChanges to ensure unregistration

parent 230d75b2
...@@ -25,10 +25,8 @@ import android.app.NotificationChannel ...@@ -25,10 +25,8 @@ import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.ConnectivityManager import android.net.ConnectivityManager
...@@ -152,20 +150,4 @@ object Core { ...@@ -152,20 +150,4 @@ object Core {
fun startService() = ContextCompat.startForegroundService(app, Intent(app, ShadowsocksConnection.serviceClass)) fun startService() = ContextCompat.startForegroundService(app, Intent(app, ShadowsocksConnection.serviceClass))
fun reloadService() = app.sendBroadcast(Intent(Action.RELOAD)) fun reloadService() = app.sendBroadcast(Intent(Action.RELOAD))
fun stopService() = app.sendBroadcast(Intent(Action.CLOSE)) fun stopService() = app.sendBroadcast(Intent(Action.CLOSE))
fun listenForPackageChanges(onetime: Boolean = true, callback: () -> Unit) = object : BroadcastReceiver() {
init {
app.registerReceiver(this, IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addDataScheme("package")
})
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) return
callback()
if (onetime) app.unregisterReceiver(this)
}
}
} }
...@@ -37,6 +37,7 @@ import com.crashlytics.android.Crashlytics ...@@ -37,6 +37,7 @@ import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.Core import com.github.shadowsocks.Core
import com.github.shadowsocks.Core.app import com.github.shadowsocks.Core.app
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.utils.listenForPackageChanges
import com.github.shadowsocks.utils.printLog import com.github.shadowsocks.utils.printLog
import com.github.shadowsocks.utils.signaturesCompat import com.github.shadowsocks.utils.signaturesCompat
import java.io.File import java.io.File
...@@ -101,7 +102,7 @@ object PluginManager { ...@@ -101,7 +102,7 @@ object PluginManager {
private var receiver: BroadcastReceiver? = null private var receiver: BroadcastReceiver? = null
private var cachedPlugins: Map<String, Plugin>? = null private var cachedPlugins: Map<String, Plugin>? = null
fun fetchPlugins(): Map<String, Plugin> = synchronized(this) { fun fetchPlugins(): Map<String, Plugin> = synchronized(this) {
if (receiver == null) receiver = Core.listenForPackageChanges { if (receiver == null) receiver = app.listenForPackageChanges {
synchronized(this) { synchronized(this) {
receiver = null receiver = null
cachedPlugins = null cachedPlugins = null
......
...@@ -21,10 +21,7 @@ ...@@ -21,10 +21,7 @@
package com.github.shadowsocks.utils package com.github.shadowsocks.utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.BroadcastReceiver import android.content.*
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.res.Resources import android.content.res.Resources
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
...@@ -103,6 +100,20 @@ fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver = ...@@ -103,6 +100,20 @@ fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver =
override fun onReceive(context: Context, intent: Intent) = callback(context, intent) override fun onReceive(context: Context, intent: Intent) = callback(context, intent)
} }
fun Context.listenForPackageChanges(onetime: Boolean = true, callback: () -> Unit) = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) return
callback()
if (onetime) context.unregisterReceiver(this)
}
}.apply {
registerReceiver(this, IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addDataScheme("package")
})
}
fun ContentResolver.openBitmap(uri: Uri) = fun ContentResolver.openBitmap(uri: Uri) =
if (Build.VERSION.SDK_INT >= 28) ImageDecoder.decodeBitmap(ImageDecoder.createSource(this, uri)) if (Build.VERSION.SDK_INT >= 28) ImageDecoder.decodeBitmap(ImageDecoder.createSource(this, uri))
else BitmapFactory.decodeStream(openInputStream(uri)) else BitmapFactory.decodeStream(openInputStream(uri))
......
...@@ -42,6 +42,7 @@ import androidx.annotation.UiThread ...@@ -42,6 +42,7 @@ import androidx.annotation.UiThread
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.util.set import androidx.core.util.set
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
...@@ -51,6 +52,7 @@ import com.github.shadowsocks.preference.DataStore ...@@ -51,6 +52,7 @@ import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.DirectBoot
import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.SingleInstanceActivity import com.github.shadowsocks.utils.SingleInstanceActivity
import com.github.shadowsocks.utils.listenForPackageChanges
import com.github.shadowsocks.widget.ListHolderListener import com.github.shadowsocks.widget.ListHolderListener
import com.github.shadowsocks.widget.ListListener import com.github.shadowsocks.widget.ListListener
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
...@@ -68,7 +70,7 @@ class AppManager : AppCompatActivity() { ...@@ -68,7 +70,7 @@ class AppManager : AppCompatActivity() {
private var receiver: BroadcastReceiver? = null private var receiver: BroadcastReceiver? = null
private var cachedApps: Map<String, PackageInfo>? = null private var cachedApps: Map<String, PackageInfo>? = null
private fun getCachedApps(pm: PackageManager) = synchronized(AppManager) { private fun getCachedApps(pm: PackageManager) = synchronized(AppManager) {
if (receiver == null) receiver = Core.listenForPackageChanges { if (receiver == null) receiver = app.listenForPackageChanges {
synchronized(AppManager) { synchronized(AppManager) {
receiver = null receiver = null
cachedApps = null cachedApps = null
...@@ -201,7 +203,7 @@ class AppManager : AppCompatActivity() { ...@@ -201,7 +203,7 @@ class AppManager : AppCompatActivity() {
@UiThread @UiThread
private fun loadApps() { private fun loadApps() {
loader?.cancel() loader?.cancel()
loader = GlobalScope.launch(Dispatchers.Main.immediate) { loader = lifecycleScope.launchWhenCreated {
loading.crossFadeFrom(list) loading.crossFadeFrom(list)
val adapter = list.adapter as AppsAdapter val adapter = list.adapter as AppsAdapter
withContext(Dispatchers.IO) { adapter.reload() } withContext(Dispatchers.IO) { adapter.reload() }
......
...@@ -22,6 +22,7 @@ package com.github.shadowsocks ...@@ -22,6 +22,7 @@ package com.github.shadowsocks
import android.app.Activity import android.app.Activity
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
...@@ -30,8 +31,8 @@ import android.os.Parcelable ...@@ -30,8 +31,8 @@ import android.os.Parcelable
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import androidx.preference.* import androidx.preference.*
import com.github.shadowsocks.Core.app
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.plugin.* import com.github.shadowsocks.plugin.*
...@@ -40,6 +41,8 @@ import com.github.shadowsocks.utils.* ...@@ -40,6 +41,8 @@ import com.github.shadowsocks.utils.*
import com.github.shadowsocks.widget.ListListener import com.github.shadowsocks.widget.ListListener
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class ProfileConfigFragment : PreferenceFragmentCompat(), class ProfileConfigFragment : PreferenceFragmentCompat(),
Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener { Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener {
...@@ -109,7 +112,6 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), ...@@ -109,7 +112,6 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
pluginConfigure.setOnBindEditTextListener(EditTextPreferenceModifiers.Monospace) pluginConfigure.setOnBindEditTextListener(EditTextPreferenceModifiers.Monospace)
pluginConfigure.onPreferenceChangeListener = this pluginConfigure.onPreferenceChangeListener = this
initPlugins() initPlugins()
receiver = Core.listenForPackageChanges(false) { initPlugins() }
udpFallback = findPreference(Key.udpFallback)!! udpFallback = findPreference(Key.udpFallback)!!
DataStore.privateStore.registerChangeListener(this) DataStore.privateStore.registerChangeListener(this)
} }
...@@ -149,6 +151,15 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), ...@@ -149,6 +151,15 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
requireActivity().finish() requireActivity().finish()
} }
override fun onAttach(context: Context) {
super.onAttach(context)
receiver = context.listenForPackageChanges(false) {
lifecycleScope.launch(Dispatchers.Main) { // wait until changes were flushed
lifecycleScope.launchWhenCreated { initPlugins() }
}
}
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
isProxyApps.isChecked = DataStore.proxyApps // fetch proxyApps updated by AppManager isProxyApps.isChecked = DataStore.proxyApps // fetch proxyApps updated by AppManager
...@@ -221,9 +232,13 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), ...@@ -221,9 +232,13 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
else -> false else -> false
} }
override fun onDetach() {
requireContext().unregisterReceiver(receiver)
super.onDetach()
}
override fun onDestroy() { override fun onDestroy() {
DataStore.privateStore.unregisterChangeListener(this) DataStore.privateStore.unregisterChangeListener(this)
app.unregisterReceiver(receiver)
super.onDestroy() super.onDestroy()
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment