Commit 42f507ec authored by Mygod's avatar Mygod

Rework listenForPackageChanges to ensure unregistration

parent 230d75b2
......@@ -25,10 +25,8 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.admin.DevicePolicyManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.net.ConnectivityManager
......@@ -152,20 +150,4 @@ object Core {
fun startService() = ContextCompat.startForegroundService(app, Intent(app, ShadowsocksConnection.serviceClass))
fun reloadService() = app.sendBroadcast(Intent(Action.RELOAD))
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
import com.github.shadowsocks.Core
import com.github.shadowsocks.Core.app
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.utils.listenForPackageChanges
import com.github.shadowsocks.utils.printLog
import com.github.shadowsocks.utils.signaturesCompat
import java.io.File
......@@ -101,7 +102,7 @@ object PluginManager {
private var receiver: BroadcastReceiver? = null
private var cachedPlugins: Map<String, Plugin>? = null
fun fetchPlugins(): Map<String, Plugin> = synchronized(this) {
if (receiver == null) receiver = Core.listenForPackageChanges {
if (receiver == null) receiver = app.listenForPackageChanges {
synchronized(this) {
receiver = null
cachedPlugins = null
......
......@@ -21,10 +21,7 @@
package com.github.shadowsocks.utils
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.*
import android.content.pm.PackageInfo
import android.content.res.Resources
import android.graphics.BitmapFactory
......@@ -103,6 +100,20 @@ fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver =
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) =
if (Build.VERSION.SDK_INT >= 28) ImageDecoder.decodeBitmap(ImageDecoder.createSource(this, uri))
else BitmapFactory.decodeStream(openInputStream(uri))
......
......@@ -42,6 +42,7 @@ import androidx.annotation.UiThread
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import androidx.core.util.set
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
......@@ -51,6 +52,7 @@ import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot
import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.SingleInstanceActivity
import com.github.shadowsocks.utils.listenForPackageChanges
import com.github.shadowsocks.widget.ListHolderListener
import com.github.shadowsocks.widget.ListListener
import com.google.android.material.snackbar.Snackbar
......@@ -68,7 +70,7 @@ class AppManager : AppCompatActivity() {
private var receiver: BroadcastReceiver? = null
private var cachedApps: Map<String, PackageInfo>? = null
private fun getCachedApps(pm: PackageManager) = synchronized(AppManager) {
if (receiver == null) receiver = Core.listenForPackageChanges {
if (receiver == null) receiver = app.listenForPackageChanges {
synchronized(AppManager) {
receiver = null
cachedApps = null
......@@ -201,7 +203,7 @@ class AppManager : AppCompatActivity() {
@UiThread
private fun loadApps() {
loader?.cancel()
loader = GlobalScope.launch(Dispatchers.Main.immediate) {
loader = lifecycleScope.launchWhenCreated {
loading.crossFadeFrom(list)
val adapter = list.adapter as AppsAdapter
withContext(Dispatchers.IO) { adapter.reload() }
......
......@@ -22,6 +22,7 @@ package com.github.shadowsocks
import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.os.Build
......@@ -30,8 +31,8 @@ import android.os.Parcelable
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import androidx.preference.*
import com.github.shadowsocks.Core.app
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.plugin.*
......@@ -40,6 +41,8 @@ import com.github.shadowsocks.utils.*
import com.github.shadowsocks.widget.ListListener
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.parcel.Parcelize
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class ProfileConfigFragment : PreferenceFragmentCompat(),
Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener {
......@@ -109,7 +112,6 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
pluginConfigure.setOnBindEditTextListener(EditTextPreferenceModifiers.Monospace)
pluginConfigure.onPreferenceChangeListener = this
initPlugins()
receiver = Core.listenForPackageChanges(false) { initPlugins() }
udpFallback = findPreference(Key.udpFallback)!!
DataStore.privateStore.registerChangeListener(this)
}
......@@ -149,6 +151,15 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
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() {
super.onResume()
isProxyApps.isChecked = DataStore.proxyApps // fetch proxyApps updated by AppManager
......@@ -221,9 +232,13 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
else -> false
}
override fun onDetach() {
requireContext().unregisterReceiver(receiver)
super.onDetach()
}
override fun onDestroy() {
DataStore.privateStore.unregisterChangeListener(this)
app.unregisterReceiver(receiver)
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