Commit ef162cd4 authored by Mygod's avatar Mygod

Reload apps if a change is detected

parent 569f056a
...@@ -39,8 +39,11 @@ ...@@ -39,8 +39,11 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.content.pm.PackageManager import java.util.concurrent.atomic.AtomicBoolean
import android.Manifest.permission
import android.content._ import android.content._
import android.content.pm.PackageManager
import android.graphics.PixelFormat import android.graphics.PixelFormat
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.{Bundle, Handler} import android.os.{Bundle, Handler}
...@@ -54,7 +57,6 @@ import android.view._ ...@@ -54,7 +57,6 @@ import android.view._
import android.widget.AbsListView.OnScrollListener import android.widget.AbsListView.OnScrollListener
import android.widget.CompoundButton.OnCheckedChangeListener import android.widget.CompoundButton.OnCheckedChangeListener
import android.widget._ import android.widget._
import android.Manifest.permission
import com.github.shadowsocks.utils.{Key, Utils} import com.github.shadowsocks.utils.{Key, Utils}
import scala.collection.JavaConversions._ import scala.collection.JavaConversions._
...@@ -65,6 +67,8 @@ object AppManager { ...@@ -65,6 +67,8 @@ object AppManager {
case class ProxiedApp(name: String, packageName: String, icon: Drawable) case class ProxiedApp(name: String, packageName: String, icon: Drawable)
private case class ListEntry(switch: Switch, text: TextView, icon: ImageView) private case class ListEntry(switch: Switch, text: TextView, icon: ImageView)
private var instance: AppManager = _
private var receiverRegistered: Boolean = _ private var receiverRegistered: Boolean = _
private var cachedApps: Array[ProxiedApp] = _ private var cachedApps: Array[ProxiedApp] = _
private def getApps(pm: PackageManager) = { private def getApps(pm: PackageManager) = {
...@@ -73,8 +77,12 @@ object AppManager { ...@@ -73,8 +77,12 @@ object AppManager {
filter.addAction(Intent.ACTION_PACKAGE_REMOVED) filter.addAction(Intent.ACTION_PACKAGE_REMOVED)
filter.addDataScheme("package") filter.addDataScheme("package")
ShadowsocksApplication.instance.registerReceiver((context: Context, intent: Intent) => ShadowsocksApplication.instance.registerReceiver((context: Context, intent: Intent) =>
if (intent.getAction != Intent.ACTION_PACKAGE_REMOVED || !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) if (intent.getAction != Intent.ACTION_PACKAGE_REMOVED ||
synchronized(cachedApps = null), filter) !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
synchronized(cachedApps = null)
val instance = AppManager.instance
if (instance != null) instance.reloadApps()
}, filter)
receiverRegistered = true receiverRegistered = true
} }
synchronized { synchronized {
...@@ -98,43 +106,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -98,43 +106,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
private var loadingView: View = _ private var loadingView: View = _
private var overlay: TextView = _ private var overlay: TextView = _
private var adapter: ListAdapter = _ private var adapter: ListAdapter = _
@volatile private var appsLoading: Boolean = _ private val appsLoading = new AtomicBoolean
def loadApps() {
appsLoading = true
proxiedApps = ShadowsocksApplication.settings.getString(Key.proxied, "").split('\n').to[mutable.HashSet]
apps = getApps(getPackageManager).sortWith((a, b) => {
val aProxied = proxiedApps.contains(a.packageName)
if (aProxied ^ proxiedApps.contains(b.packageName)) aProxied else a.name.compareToIgnoreCase(b.name) < 0
})
adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) {
override def getView(position: Int, view: View, parent: ViewGroup): View = {
var convertView = view
var entry: ListEntry = null
if (convertView == null) {
convertView = getLayoutInflater.inflate(R.layout.layout_apps_item, parent, false)
entry = new ListEntry(convertView.findViewById(R.id.itemcheck).asInstanceOf[Switch],
convertView.findViewById(R.id.itemtext).asInstanceOf[TextView],
convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView])
convertView.setOnClickListener(AppManager.this)
convertView.setTag(entry)
entry.switch.setOnCheckedChangeListener(AppManager.this)
} else {
entry = convertView.getTag.asInstanceOf[ListEntry]
}
val app: ProxiedApp = apps(position)
entry.text.setText(app.name)
entry.icon.setImageDrawable(app.icon)
val switch = entry.switch
switch.setTag(app)
switch.setChecked(proxiedApps.contains(app.packageName))
entry.text.setTag(switch)
convertView
}
}
}
private def setProxied(pn: String, proxied: Boolean) = if (proxied) proxiedApps.add(pn) else proxiedApps.remove(pn) private def setProxied(pn: String, proxied: Boolean) = if (proxied) proxiedApps.add(pn) else proxiedApps.remove(pn)
...@@ -157,6 +129,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -157,6 +129,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
override def onDestroy() { override def onDestroy() {
instance = null
super.onDestroy() super.onDestroy()
if (handler != null) { if (handler != null) {
handler.removeCallbacksAndMessages(null) handler.removeCallbacksAndMessages(null)
...@@ -198,7 +171,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -198,7 +171,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
// Restart activity // Restart activity
appListView.setVisibility(View.GONE) appListView.setVisibility(View.GONE)
loadingView.setVisibility(View.VISIBLE) loadingView.setVisibility(View.VISIBLE)
if (appsLoading) appsLoading = false else loadAppsAsync() reloadApps()
return true return true
} }
} }
...@@ -264,13 +237,49 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -264,13 +237,49 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
} }
}) })
instance = this
loadAppsAsync() loadAppsAsync()
} }
def reloadApps() = if (!appsLoading.compareAndSet(true, false)) loadAppsAsync()
def loadAppsAsync() { def loadAppsAsync() {
if (!appsLoading.compareAndSet(false, true)) return
ThrowableFuture { ThrowableFuture {
while (!appsLoading) loadApps() do {
appsLoading = false proxiedApps = ShadowsocksApplication.settings.getString(Key.proxied, "").split('\n').to[mutable.HashSet]
appsLoading.set(true)
apps = getApps(getPackageManager).sortWith((a, b) => {
val aProxied = proxiedApps.contains(a.packageName)
if (aProxied ^ proxiedApps.contains(b.packageName)) aProxied else a.name.compareToIgnoreCase(b.name) < 0
})
adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) {
override def getView(position: Int, view: View, parent: ViewGroup): View = {
var convertView = view
var entry: ListEntry = null
if (convertView == null) {
convertView = getLayoutInflater.inflate(R.layout.layout_apps_item, parent, false)
entry = new ListEntry(convertView.findViewById(R.id.itemcheck).asInstanceOf[Switch],
convertView.findViewById(R.id.itemtext).asInstanceOf[TextView],
convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView])
convertView.setOnClickListener(AppManager.this)
convertView.setTag(entry)
entry.switch.setOnCheckedChangeListener(AppManager.this)
} else {
entry = convertView.getTag.asInstanceOf[ListEntry]
}
val app: ProxiedApp = apps(position)
entry.text.setText(app.name)
entry.icon.setImageDrawable(app.icon)
val switch = entry.switch
switch.setTag(app)
switch.setChecked(proxiedApps.contains(app.packageName))
entry.text.setTag(switch)
convertView
}
}
} while (!appsLoading.compareAndSet(true, false))
handler.post(() => { handler.post(() => {
appListView.setAdapter(adapter) appListView.setAdapter(adapter)
Utils.crossFade(AppManager.this, loadingView, appListView) Utils.crossFade(AppManager.this, loadingView, appListView)
...@@ -279,7 +288,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -279,7 +288,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
def saveAppSettings(context: Context) { def saveAppSettings(context: Context) {
if (!appsLoading) ShadowsocksApplication.settings.edit.putString(Key.proxied, proxiedApps.mkString("\n")).apply if (!appsLoading.get) ShadowsocksApplication.settings.edit.putString(Key.proxied, proxiedApps.mkString("\n")).apply
} }
var handler: Handler = null var handler: Handler = null
......
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