Cache proxied apps for even better performance
This commit is contained in:
@@ -39,7 +39,8 @@
|
||||
|
||||
package com.github.shadowsocks
|
||||
|
||||
import android.content.{ClipData, ClipboardManager, Context, SharedPreferences}
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.{ClipData, ClipboardManager, Context}
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.{Bundle, Handler}
|
||||
@@ -61,14 +62,24 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import scala.language.implicitConversions
|
||||
|
||||
case class ProxiedApp(uid: Int, name: String, packageName: String, icon: Drawable, var proxied: Boolean)
|
||||
object AppManager {
|
||||
case class ProxiedApp(uid: Int, name: String, packageName: String, icon: Drawable)
|
||||
private case class ListEntry(switch: Switch, text: TextView, icon: ImageView)
|
||||
|
||||
case class ListEntry(switch: Switch, text: TextView, icon: ImageView)
|
||||
var cachedApps: Array[ProxiedApp] = _
|
||||
private def getApps(pm: PackageManager) = {
|
||||
if (cachedApps == null) cachedApps = pm.getInstalledApplications(0).filter(_.uid >= 10000)
|
||||
.map(a => new ProxiedApp(a.uid, pm.getApplicationLabel(a).toString, a.packageName, a.loadIcon(pm))).toArray
|
||||
cachedApps
|
||||
}
|
||||
}
|
||||
|
||||
class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnClickListener
|
||||
with OnMenuItemClickListener {
|
||||
import AppManager._
|
||||
|
||||
private var apps: mutable.Buffer[ProxiedApp] = _
|
||||
private var apps: Array[ProxiedApp] = _
|
||||
private var proxiedApps: mutable.HashSet[Int] = _
|
||||
private var toolbar: Toolbar = _
|
||||
private var appListView: ListView = _
|
||||
private var loadingView: View = _
|
||||
@@ -78,23 +89,10 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
|
||||
|
||||
def loadApps() {
|
||||
appsLoading = true
|
||||
val proxiedApps = ShadowsocksApplication.settings.getString(Key.proxied, "").split('|').toSet
|
||||
|
||||
val packageManager = getPackageManager
|
||||
apps = packageManager.getInstalledApplications(0).filter(_.uid >= 10000).map {
|
||||
case a =>
|
||||
val uid = a.uid
|
||||
val userName = uid.toString
|
||||
val name = packageManager.getApplicationLabel(a).toString
|
||||
val packageName = a.packageName
|
||||
val proxied = proxiedApps.contains(userName)
|
||||
new ProxiedApp(uid, name, packageName, a.loadIcon(packageManager), proxied)
|
||||
}.sortWith((a, b) => {
|
||||
if (a == null || b == null || a.name == null || b.name == null) {
|
||||
true
|
||||
} else if (a.proxied == b.proxied) {
|
||||
a.name < b.name
|
||||
} else a.proxied
|
||||
proxiedApps = ShadowsocksApplication.settings.getString(Key.proxied, "").split('|').map(_.toInt).to[mutable.HashSet]
|
||||
apps = getApps(getPackageManager).sortWith((a, b) => {
|
||||
val aProxied = proxiedApps.contains(a.uid)
|
||||
if (aProxied ^ proxiedApps.contains(b.uid)) aProxied else a.name < b.name
|
||||
})
|
||||
adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) {
|
||||
override def getView(position: Int, view: View, parent: ViewGroup): View = {
|
||||
@@ -102,10 +100,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
|
||||
var entry: ListEntry = null
|
||||
if (convertView == null) {
|
||||
convertView = getLayoutInflater.inflate(R.layout.layout_apps_item, parent, false)
|
||||
val icon = convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView]
|
||||
val switch = convertView.findViewById(R.id.itemcheck).asInstanceOf[Switch]
|
||||
val text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView]
|
||||
entry = new ListEntry(switch, text, icon)
|
||||
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)
|
||||
@@ -119,19 +116,19 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
|
||||
entry.icon.setImageDrawable(app.icon)
|
||||
val switch = entry.switch
|
||||
switch.setTag(app)
|
||||
switch.setChecked(app.proxied)
|
||||
switch.setChecked(proxiedApps.contains(app.uid))
|
||||
entry.text.setTag(switch)
|
||||
convertView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def setProxied(uid: Int, proxied: Boolean) = if (proxied) proxiedApps.add(uid) else proxiedApps.remove(uid)
|
||||
|
||||
/** Called an application is check/unchecked */
|
||||
def onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
|
||||
val app: ProxiedApp = buttonView.getTag.asInstanceOf[ProxiedApp]
|
||||
if (app != null) {
|
||||
app.proxied = isChecked
|
||||
}
|
||||
if (app != null) setProxied(app.uid, isChecked)
|
||||
saveAppSettings(this)
|
||||
}
|
||||
|
||||
@@ -139,8 +136,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
|
||||
val switch = v.getTag.asInstanceOf[ListEntry].switch
|
||||
val app: ProxiedApp = switch.getTag.asInstanceOf[ProxiedApp]
|
||||
if (app != null) {
|
||||
app.proxied = !app.proxied
|
||||
switch.setChecked(app.proxied)
|
||||
val proxied = !proxiedApps.contains(app.uid)
|
||||
setProxied(app.uid, proxied)
|
||||
switch.setChecked(proxied)
|
||||
}
|
||||
saveAppSettings(this)
|
||||
}
|
||||
@@ -235,12 +233,8 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
|
||||
def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int,
|
||||
totalItemCount: Int) {
|
||||
if (visible) {
|
||||
val name: String = apps(firstVisibleItem).name
|
||||
if (name != null && name.length > 1) {
|
||||
overlay.setText(apps(firstVisibleItem).name.substring(0, 1))
|
||||
} else {
|
||||
overlay.setText("*")
|
||||
}
|
||||
val name = apps(firstVisibleItem).name
|
||||
overlay.setText(if (name != null && name.length > 1) name(0).toString else "*")
|
||||
overlay.setVisibility(View.VISIBLE)
|
||||
}
|
||||
}
|
||||
@@ -266,16 +260,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
|
||||
}
|
||||
|
||||
def saveAppSettings(context: Context) {
|
||||
if (apps == null) return
|
||||
val proxiedApps = new StringBuilder
|
||||
apps.foreach(app =>
|
||||
if (app.proxied) {
|
||||
proxiedApps ++= app.uid.toString
|
||||
proxiedApps += '|'
|
||||
})
|
||||
val edit: SharedPreferences.Editor = ShadowsocksApplication.settings.edit
|
||||
edit.putString(Key.proxied, proxiedApps.toString())
|
||||
edit.apply
|
||||
if (!appsLoading) ShadowsocksApplication.settings.edit.putString(Key.proxied, proxiedApps.mkString("|")).apply
|
||||
}
|
||||
|
||||
var handler: Handler = null
|
||||
|
||||
Reference in New Issue
Block a user