diff --git a/project/build.properties b/project/build.properties deleted file mode 100644 index a6e117b6..00000000 --- a/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=0.13.8 diff --git a/project/plugins.sbt b/project/plugins.sbt index 217b0486..5388c040 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,5 @@ resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns) -addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.9") +addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.10") resolvers += "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/" addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.7.0-SNAPSHOT") diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 1a347e07..4a41d8a0 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -109,6 +109,14 @@ + + + + + + + + diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml index dcf31c04..c3910a87 100755 --- a/src/main/res/values-zh/strings.xml +++ b/src/main/res/values-zh/strings.xml @@ -33,7 +33,6 @@ 自动连接 随系统启动后台服务 后台服务已开始运行。 - %s 无法连接远程服务器 停止服务 正在关闭…… diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 018d7cc2..7c154a9f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -60,7 +60,6 @@ Shadowsocks started. - %s Failed to connect the remote server Stop the service Shutting down… diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala index 3d5da43d..d08e8acb 100644 --- a/src/main/scala/com/github/shadowsocks/AppManager.scala +++ b/src/main/scala/com/github/shadowsocks/AppManager.scala @@ -40,7 +40,7 @@ package com.github.shadowsocks import android.content.pm.PackageManager -import android.content.{ClipData, ClipboardManager, Context, SharedPreferences} +import android.content.{ClipData, ClipboardManager, Context} import android.graphics.PixelFormat import android.graphics.drawable.Drawable import android.os.{Bundle, Handler} @@ -50,101 +50,49 @@ import android.support.v7.widget.Toolbar import android.support.v7.widget.Toolbar.OnMenuItemClickListener import android.view.View.OnClickListener import android.view.ViewGroup.LayoutParams -import android.view.{MenuItem, View, ViewGroup, WindowManager} +import android.view._ import android.widget.AbsListView.OnScrollListener 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 { + case class ProxiedApp(uid: Int, name: String, packageName: String, icon: Drawable) + private case class ListEntry(switch: Switch, text: TextView, icon: ImageView) - 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 + 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._ - val MSG_LOAD_START = 1 - 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 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(_ < _) - - 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 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, a.loadIcon(packageManager), proxied) - }.toArray - } + private var apps: Array[ProxiedApp] = _ + private var proxiedApps: mutable.HashSet[Int] = _ + private var toolbar: Toolbar = _ + private var appListView: ListView = _ + private var loadingView: View = _ + private var overlay: TextView = _ + private var adapter: ListAdapter = _ + @volatile private var appsLoading: Boolean = _ def loadApps() { appsLoading = true - apps = loadApps(this).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 - } + 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 = { @@ -152,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) @@ -169,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) } @@ -189,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) } @@ -250,7 +198,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC handler = new Handler() this.setContentView(R.layout.layout_apps) - val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar] + toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar] toolbar.setTitle(R.string.proxied_apps) toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha) toolbar.setNavigationOnClickListener((v: View) => { @@ -285,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) } } @@ -316,18 +260,14 @@ 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 + override def onKeyUp(keyCode: Int, event: KeyEvent) = keyCode match { + case KeyEvent.KEYCODE_MENU => + if (toolbar.isOverflowMenuShowing) toolbar.hideOverflowMenu else toolbar.showOverflowMenu + case _ => super.onKeyUp(keyCode, event) + } } diff --git a/src/main/scala/com/github/shadowsocks/AppManagerReceiver.scala b/src/main/scala/com/github/shadowsocks/AppManagerReceiver.scala new file mode 100644 index 00000000..f754f11a --- /dev/null +++ b/src/main/scala/com/github/shadowsocks/AppManagerReceiver.scala @@ -0,0 +1,11 @@ +package com.github.shadowsocks + +import android.content.{Intent, Context, BroadcastReceiver} + +/** + * @author Mygod + */ +class AppManagerReceiver extends BroadcastReceiver { + override def onReceive(context: Context, intent: Intent) = if (intent.getAction != Intent.ACTION_PACKAGE_REMOVED || + !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) AppManager.cachedApps = null +} diff --git a/src/main/scala/com/github/shadowsocks/ServiceBoundContext.scala b/src/main/scala/com/github/shadowsocks/ServiceBoundContext.scala index e6cbbeaf..c304f559 100644 --- a/src/main/scala/com/github/shadowsocks/ServiceBoundContext.scala +++ b/src/main/scala/com/github/shadowsocks/ServiceBoundContext.scala @@ -67,11 +67,13 @@ trait ServiceBoundContext extends Context { } catch { case ignored: RemoteException => // Nothing } + callback = null } if (connection != null) { unbindService(connection) connection = null } + bgService = null } } } diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index 9b652522..37895f30 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -157,6 +157,54 @@ class Shadowsocks // Services var currentServiceName = classOf[ShadowsocksNatService].getName + private val callback = new IShadowsocksServiceCallback.Stub { + def stateChanged(s: Int, m: String) { + handler.post(() => if (state != s) { + s match { + case State.CONNECTING => + fab.setBackgroundTintList(greyTint) + fab.setImageResource(R.drawable.ic_cloud_queue) + fab.setEnabled(false) + fabProgressCircle.show() + setPreferenceEnabled(enabled = false) + case State.CONNECTED => + fab.setBackgroundTintList(greenTint) + if (state == State.CONNECTING) { + fabProgressCircle.beginFinalAnimation() + } else { + handler.postDelayed(() => fabProgressCircle.hide(), 1000) + } + fab.setEnabled(true) + changeSwitch(checked = true) + setPreferenceEnabled(enabled = false) + case State.STOPPED => + fab.setBackgroundTintList(greyTint) + handler.postDelayed(() => fabProgressCircle.hide(), 1000) + fab.setEnabled(true) + changeSwitch(checked = false) + if (m != null) Snackbar.make(findViewById(android.R.id.content), + getString(R.string.vpn_error).formatLocal(Locale.ENGLISH, m), Snackbar.LENGTH_LONG).show + setPreferenceEnabled(enabled = true) + case State.STOPPING => + fab.setBackgroundTintList(greyTint) + fab.setImageResource(R.drawable.ic_cloud_queue) + fab.setEnabled(false) + if (state == State.CONNECTED) fabProgressCircle.show() // ignore for stopped + setPreferenceEnabled(enabled = false) + } + state = s + }) + } + def trafficUpdated(txRate: String, rxRate: String, txTotal: String, rxTotal: String) { + val trafficStat = getString(R.string.stat_summary) + .formatLocal(Locale.ENGLISH, txRate, rxRate, txTotal, rxTotal) + handler.post(() => { + preferences.findPreference(Key.stat).setSummary(trafficStat) + }) + } + } + + def attachService: Unit = attachService(callback) override def onServiceConnected() { // Update the UI @@ -188,14 +236,6 @@ class Shadowsocks if (fab != null) fab.setEnabled(false) } - def trafficUpdated(txRate: String, rxRate: String, txTotal: String, rxTotal: String) { - val trafficStat = getString(R.string.stat_summary) - .formatLocal(Locale.ENGLISH, txRate, rxRate, txTotal, rxTotal) - handler.post(() => { - preferences.findPreference(Key.stat).setSummary(trafficStat) - }) - } - private lazy val preferences = getFragmentManager.findFragmentById(android.R.id.content).asInstanceOf[ShadowsocksSettings] private var adView: AdView = _ @@ -377,16 +417,7 @@ class Shadowsocks }) // Bind to the service - handler.post(() => { - attachService(new IShadowsocksServiceCallback.Stub { - override def stateChanged(state: Int, msg: String) { - onStateChanged(state, msg) - } - override def trafficUpdated(txRate: String, rxRate: String, txTotal: String, rxTotal: String) { - Shadowsocks.this.trafficUpdated(txRate, rxRate, txTotal, rxTotal) - } - }) - }) + handler.post(() => attachService) } def reloadProfile() { @@ -447,7 +478,7 @@ class Shadowsocks // Check if current profile changed if (ShadowsocksApplication.profileId != currentProfile.id) reloadProfile() - trafficUpdated(TrafficMonitor.getTxRate, TrafficMonitor.getRxRate, + callback.trafficUpdated(TrafficMonitor.getTxRate, TrafficMonitor.getRxRate, TrafficMonitor.getTxTotal, TrafficMonitor.getRxTotal) } @@ -584,42 +615,4 @@ class Shadowsocks progressTag = -1 } } - - def onStateChanged(s: Int, m: String) { - handler.post(() => if (state != s) { - s match { - case State.CONNECTING => - fab.setBackgroundTintList(greyTint) - fab.setImageResource(R.drawable.ic_cloud_queue) - fab.setEnabled(false) - fabProgressCircle.show() - setPreferenceEnabled(enabled = false) - case State.CONNECTED => - fab.setBackgroundTintList(greenTint) - if (state == State.CONNECTING) { - fabProgressCircle.beginFinalAnimation() - } else { - handler.postDelayed(() => fabProgressCircle.hide(), 1000) - } - fab.setEnabled(true) - changeSwitch(checked = true) - setPreferenceEnabled(enabled = false) - case State.STOPPED => - fab.setBackgroundTintList(greyTint) - handler.postDelayed(() => fabProgressCircle.hide(), 1000) - fab.setEnabled(true) - changeSwitch(checked = false) - if (m != null) Snackbar.make(findViewById(android.R.id.content), - getString(R.string.vpn_error).formatLocal(Locale.ENGLISH, m), Snackbar.LENGTH_LONG).show - setPreferenceEnabled(enabled = true) - case State.STOPPING => - fab.setBackgroundTintList(greyTint) - fab.setImageResource(R.drawable.ic_cloud_queue) - fab.setEnabled(false) - if (state == State.CONNECTED) fabProgressCircle.show() // ignore for stopped - setPreferenceEnabled(enabled = false) - } - state = s - }) - } } 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/ShadowsocksNotification.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala index 6d115bf8..f8f8b06e 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala @@ -32,7 +32,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str .setWhen(0) .setColor(ContextCompat.getColor(service, R.color.material_accent_500)) .setTicker(service.getString(R.string.forward_success)) - .setContentTitle(service.getString(R.string.service_running).formatLocal(Locale.ENGLISH, profileName)) + .setContentTitle(profileName) .setContentIntent(PendingIntent.getActivity(service, 0, new Intent(service, classOf[Shadowsocks]) .setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0)) .setSmallIcon(R.drawable.ic_stat_shadowsocks) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala index 5daa69ad..16bd4cd0 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala @@ -43,9 +43,6 @@ import android.content.{BroadcastReceiver, Context, Intent} import com.github.shadowsocks.utils._ class ShadowsocksReceiver extends BroadcastReceiver { - - val TAG = "Shadowsocks" - def onReceive(context: Context, intent: Intent) { if (ShadowsocksApplication.settings.getBoolean(Key.isAutoConnect, false)) { Utils.startSsService(context) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index 684fc0ed..b63c7d81 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -67,7 +67,7 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan }) } - override def onResume = { + override def onResume { super.onResume isProxyApps.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isProxyApps, false)) // update } @@ -75,9 +75,8 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan def onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) = key match { case Key.isNAT => if (ShadowsocksApplication.isRoot && activity != null) { activity.handler.post(() => { - val intent = activity.getIntent - activity.finish() - startActivity(intent) + activity.deattachService + activity.attachService }) } case _ => diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index ba0e2018..3140baaf 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 @@ -64,16 +63,15 @@ class ShadowsocksVpnService extends VpnService with BaseService { val VPN_MTU = 1500 val PRIVATE_VLAN = "26.26.26.%s" val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s" - var conn: ParcelFileDescriptor = null - var apps: Array[ProxiedApp] = null - var vpnThread: ShadowsocksVpnThread = null + var conn: ParcelFileDescriptor = _ + var vpnThread: ShadowsocksVpnThread = _ private var notification: ShadowsocksNotification = _ - var closeReceiver: BroadcastReceiver = null + var closeReceiver: BroadcastReceiver = _ - var sslocalProcess: Process = null - var sstunnelProcess: Process = null - var pdnsdProcess: Process = null - var tun2socksProcess: Process = null + var sslocalProcess: Process = _ + var sstunnelProcess: Process = _ + var pdnsdProcess: Process = _ + var tun2socksProcess: Process = _ def isByass(net: SubnetUtils): Boolean = { val info = net.getInfo @@ -392,14 +390,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 { diff --git a/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala b/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala index 8fadf78a..2b2f18e5 100644 --- a/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala +++ b/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala @@ -44,7 +44,6 @@ import com.github.shadowsocks.{R, ShadowsocksApplication} import com.twofortyfouram.locale.api.{Intent => ApiIntent} object TaskerSettings { - private val KEY_ACTION = "action" private val KEY_SWITCH_ON = "switch_on" private val KEY_PROFILE_ID = "profile_id"