diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala index 3d5da43d..4a80a5a3 100644 --- a/src/main/scala/com/github/shadowsocks/AppManager.scala +++ b/src/main/scala/com/github/shadowsocks/AppManager.scala @@ -39,7 +39,6 @@ package com.github.shadowsocks -import android.content.pm.PackageManager import android.content.{ClipData, ClipboardManager, Context, SharedPreferences} import android.graphics.PixelFormat import android.graphics.drawable.Drawable @@ -56,45 +55,16 @@ import android.widget.CompoundButton.OnCheckedChangeListener import android.widget._ import com.github.shadowsocks.utils.{Key, Utils} +import scala.collection.JavaConversions._ +import scala.collection.mutable 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) -class ObjectArrayTools[T <: AnyRef](a: Array[T]) { - def binarySearch(key: T) = { - java.util.Arrays.binarySearch(a.asInstanceOf[Array[AnyRef]], key) - } -} - case class ListEntry(switch: Switch, text: TextView, icon: ImageView) -object AppManager { - - implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a) - - def getProxiedApps(context: Context, proxiedAppString: String): Array[ProxiedApp] = { - - val proxiedApps = proxiedAppString.split('|').sortWith(_ < _) - - import scala.collection.JavaConversions._ - - val packageManager: PackageManager = context.getPackageManager - val appList = packageManager.getInstalledApplications(0) - - appList.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.binarySearch(userName) >= 0 - new ProxiedApp(uid, name, packageName, null, proxied) - }.toArray - } -} - class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnClickListener with OnMenuItemClickListener { @@ -102,49 +72,32 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC val MSG_LOAD_FINISH = 2 val STUB = android.R.drawable.sym_def_app_icon - implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a) - - var apps: Array[ProxiedApp] = _ + var apps: mutable.Buffer[ProxiedApp] = _ var appListView: ListView = _ var loadingView: View = _ var overlay: TextView = _ var adapter: ListAdapter = _ @volatile var appsLoading: Boolean = _ - def loadApps(context: Context): Array[ProxiedApp] = { - val proxiedAppString = ShadowsocksApplication.settings.getString(Key.proxied, "") - val proxiedApps = proxiedAppString.split('|').sortWith(_ < _) + def loadApps() { + appsLoading = true + val proxiedApps = ShadowsocksApplication.settings.getString(Key.proxied, "").split('|').toSet - import scala.collection.JavaConversions._ - - val packageManager: PackageManager = context.getPackageManager - val appList = packageManager.getInstalledApplications(0) - - appList.filter(a => a.uid >= 10000 - && packageManager.getApplicationLabel(a) != null - && packageManager.getApplicationIcon(a) != null).map { - a => + 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 binarySearch userName) >= 0 + val proxied = proxiedApps.contains(userName) new ProxiedApp(uid, name, packageName, a.loadIcon(packageManager), proxied) - }.toArray - } - - def loadApps() { - appsLoading = true - apps = loadApps(this).sortWith((a, b) => { + }.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 if (a.proxied) { - true - } else { - false - } + } else a.proxied }) adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) { override def getView(position: Int, view: View, parent: ViewGroup): View = { diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index 16bd2a42..865cc586 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -54,7 +54,6 @@ import com.github.shadowsocks.aidl.Config import com.github.shadowsocks.utils._ import scala.collection.JavaConversions._ -import scala.collection._ import scala.collection.mutable.ArrayBuffer import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -68,15 +67,14 @@ class ShadowsocksNatService extends BaseService { "-j DNAT --to-destination 127.0.0.1:8123" private var notification: ShadowsocksNotification = _ - var closeReceiver: BroadcastReceiver = null - var connReceiver: BroadcastReceiver = null - var apps: Array[ProxiedApp] = null + var closeReceiver: BroadcastReceiver = _ + var connReceiver: BroadcastReceiver = _ val myUid = android.os.Process.myUid() - var sslocalProcess: Process = null - var sstunnelProcess: Process = null - var redsocksProcess: Process = null - var pdnsdProcess: Process = null + var sslocalProcess: Process = _ + var sstunnelProcess: Process = _ + var redsocksProcess: Process = _ + var pdnsdProcess: Process = _ private val dnsAddressCache = new SparseArray[String] @@ -378,16 +376,7 @@ class ShadowsocksNatService extends BaseService { http_sb.append(Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS) } if (config.isProxyApps) { - if (apps == null || apps.length <= 0) { - apps = AppManager.getProxiedApps(this, config.proxiedAppString) - } - val uidSet: mutable.HashSet[Int] = new mutable.HashSet[Int] - for (app <- apps) { - if (app.proxied) { - uidSet.add(app.uid) - } - } - for (uid <- uidSet) { + for (uid <- config.proxiedAppString.split('|').distinct) { if (!config.isBypassApps) { http_sb.append((Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS).replace("-t nat", "-t nat -m owner --uid-owner " + uid)) } else { diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index ba0e2018..966d5440 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -54,7 +54,6 @@ import com.github.shadowsocks.utils._ import org.apache.commons.net.util.SubnetUtils import scala.collection.JavaConversions._ -import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -392,14 +391,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (Utils.isLollipopOrAbove) { if (config.isProxyApps) { - val apps = AppManager.getProxiedApps(this, config.proxiedAppString) - val pkgSet: mutable.HashSet[String] = new mutable.HashSet[String] - for (app <- apps) { - if (app.proxied) { - pkgSet.add(app.packageName) - } - } - for (pkg <- pkgSet) { + for (pkg <- config.proxiedAppString.split('|').distinct) { if (!config.isBypassApps) { builder.addAllowedApplication(pkg) } else {