Commit 9541ac01 authored by Max Lv's avatar Max Lv

Merge pull request #467 from Mygod/master

Cache proxied apps for even better performance
parents d2a10272 ac98caa4
resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns) 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/" resolvers += "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.7.0-SNAPSHOT") addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.7.0-SNAPSHOT")
......
...@@ -109,6 +109,14 @@ ...@@ -109,6 +109,14 @@
</intent-filter> </intent-filter>
</service> </service>
<receiver android:name=".AppManagerReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package"/>
</intent-filter>
</receiver>
<receiver android:name=".ShadowsocksReceiver"> <receiver android:name=".ShadowsocksReceiver">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.BOOT_COMPLETED"/>
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
<string name="auto_connect">自动连接</string> <string name="auto_connect">自动连接</string>
<string name="auto_connect_summary">随系统启动后台服务</string> <string name="auto_connect_summary">随系统启动后台服务</string>
<string name="forward_success">后台服务已开始运行。</string> <string name="forward_success">后台服务已开始运行。</string>
<string name="service_running">%s</string>
<string name="service_failed">无法连接远程服务器</string> <string name="service_failed">无法连接远程服务器</string>
<string name="stop">停止服务</string> <string name="stop">停止服务</string>
<string name="stopping">正在关闭……</string> <string name="stopping">正在关闭……</string>
......
...@@ -60,7 +60,6 @@ ...@@ -60,7 +60,6 @@
<!-- notification category --> <!-- notification category -->
<string name="forward_success">Shadowsocks started.</string> <string name="forward_success">Shadowsocks started.</string>
<string name="service_running">%s</string>
<string name="service_failed">Failed to connect the remote server</string> <string name="service_failed">Failed to connect the remote server</string>
<string name="stop">Stop the service</string> <string name="stop">Stop the service</string>
<string name="stopping">Shutting down…</string> <string name="stopping">Shutting down…</string>
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.content.pm.PackageManager 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.PixelFormat
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.{Bundle, Handler} import android.os.{Bundle, Handler}
...@@ -50,101 +50,49 @@ import android.support.v7.widget.Toolbar ...@@ -50,101 +50,49 @@ import android.support.v7.widget.Toolbar
import android.support.v7.widget.Toolbar.OnMenuItemClickListener import android.support.v7.widget.Toolbar.OnMenuItemClickListener
import android.view.View.OnClickListener import android.view.View.OnClickListener
import android.view.ViewGroup.LayoutParams import android.view.ViewGroup.LayoutParams
import android.view.{MenuItem, View, ViewGroup, WindowManager} 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 com.github.shadowsocks.utils.{Key, Utils} import com.github.shadowsocks.utils.{Key, Utils}
import scala.collection.JavaConversions._
import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future import scala.concurrent.Future
import scala.language.implicitConversions 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 { object AppManager {
case class ProxiedApp(uid: Int, name: String, packageName: String, icon: Drawable)
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a) private case class ListEntry(switch: Switch, text: TextView, icon: ImageView)
def getProxiedApps(context: Context, proxiedAppString: String): Array[ProxiedApp] = { var cachedApps: Array[ProxiedApp] = _
private def getApps(pm: PackageManager) = {
val proxiedApps = proxiedAppString.split('|').sortWith(_ < _) 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
import scala.collection.JavaConversions._ cachedApps
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 class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnClickListener
with OnMenuItemClickListener { with OnMenuItemClickListener {
import AppManager._
val MSG_LOAD_START = 1 private var apps: Array[ProxiedApp] = _
val MSG_LOAD_FINISH = 2 private var proxiedApps: mutable.HashSet[Int] = _
val STUB = android.R.drawable.sym_def_app_icon private var toolbar: Toolbar = _
private var appListView: ListView = _
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a) private var loadingView: View = _
private var overlay: TextView = _
var apps: Array[ProxiedApp] = _ private var adapter: ListAdapter = _
var appListView: ListView = _ @volatile private var appsLoading: Boolean = _
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
}
def loadApps() { def loadApps() {
appsLoading = true appsLoading = true
apps = loadApps(this).sortWith((a, b) => { proxiedApps = ShadowsocksApplication.settings.getString(Key.proxied, "").split('|').map(_.toInt).to[mutable.HashSet]
if (a == null || b == null || a.name == null || b.name == null) { apps = getApps(getPackageManager).sortWith((a, b) => {
true val aProxied = proxiedApps.contains(a.uid)
} else if (a.proxied == b.proxied) { if (aProxied ^ proxiedApps.contains(b.uid)) aProxied else a.name < b.name
a.name < b.name
} else if (a.proxied) {
true
} else {
false
}
}) })
adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) { adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) {
override def getView(position: Int, view: View, parent: ViewGroup): View = { override def getView(position: Int, view: View, parent: ViewGroup): View = {
...@@ -152,10 +100,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -152,10 +100,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
var entry: ListEntry = null var entry: ListEntry = null
if (convertView == null) { if (convertView == null) {
convertView = getLayoutInflater.inflate(R.layout.layout_apps_item, parent, false) convertView = getLayoutInflater.inflate(R.layout.layout_apps_item, parent, false)
val icon = convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView] entry = new ListEntry(convertView.findViewById(R.id.itemcheck).asInstanceOf[Switch],
val switch = convertView.findViewById(R.id.itemcheck).asInstanceOf[Switch] convertView.findViewById(R.id.itemtext).asInstanceOf[TextView],
val text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView] convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView])
entry = new ListEntry(switch, text, icon)
convertView.setOnClickListener(AppManager.this) convertView.setOnClickListener(AppManager.this)
convertView.setTag(entry) convertView.setTag(entry)
entry.switch.setOnCheckedChangeListener(AppManager.this) entry.switch.setOnCheckedChangeListener(AppManager.this)
...@@ -169,19 +116,19 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -169,19 +116,19 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
entry.icon.setImageDrawable(app.icon) entry.icon.setImageDrawable(app.icon)
val switch = entry.switch val switch = entry.switch
switch.setTag(app) switch.setTag(app)
switch.setChecked(app.proxied) switch.setChecked(proxiedApps.contains(app.uid))
entry.text.setTag(switch) entry.text.setTag(switch)
convertView convertView
} }
} }
} }
private def setProxied(uid: Int, proxied: Boolean) = if (proxied) proxiedApps.add(uid) else proxiedApps.remove(uid)
/** Called an application is check/unchecked */ /** Called an application is check/unchecked */
def onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { def onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
val app: ProxiedApp = buttonView.getTag.asInstanceOf[ProxiedApp] val app: ProxiedApp = buttonView.getTag.asInstanceOf[ProxiedApp]
if (app != null) { if (app != null) setProxied(app.uid, isChecked)
app.proxied = isChecked
}
saveAppSettings(this) saveAppSettings(this)
} }
...@@ -189,8 +136,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -189,8 +136,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
val switch = v.getTag.asInstanceOf[ListEntry].switch val switch = v.getTag.asInstanceOf[ListEntry].switch
val app: ProxiedApp = switch.getTag.asInstanceOf[ProxiedApp] val app: ProxiedApp = switch.getTag.asInstanceOf[ProxiedApp]
if (app != null) { if (app != null) {
app.proxied = !app.proxied val proxied = !proxiedApps.contains(app.uid)
switch.setChecked(app.proxied) setProxied(app.uid, proxied)
switch.setChecked(proxied)
} }
saveAppSettings(this) saveAppSettings(this)
} }
...@@ -250,7 +198,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -250,7 +198,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
handler = new Handler() handler = new Handler()
this.setContentView(R.layout.layout_apps) 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.setTitle(R.string.proxied_apps)
toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha) toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha)
toolbar.setNavigationOnClickListener((v: View) => { toolbar.setNavigationOnClickListener((v: View) => {
...@@ -285,12 +233,8 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -285,12 +233,8 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int,
totalItemCount: Int) { totalItemCount: Int) {
if (visible) { if (visible) {
val name: String = apps(firstVisibleItem).name val name = apps(firstVisibleItem).name
if (name != null && name.length > 1) { overlay.setText(if (name != null && name.length > 1) name(0).toString else "*")
overlay.setText(apps(firstVisibleItem).name.substring(0, 1))
} else {
overlay.setText("*")
}
overlay.setVisibility(View.VISIBLE) overlay.setVisibility(View.VISIBLE)
} }
} }
...@@ -316,18 +260,14 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -316,18 +260,14 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
def saveAppSettings(context: Context) { def saveAppSettings(context: Context) {
if (apps == null) return if (!appsLoading) ShadowsocksApplication.settings.edit.putString(Key.proxied, proxiedApps.mkString("|")).apply
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
} }
var handler: Handler = null 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)
}
} }
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
}
...@@ -67,11 +67,13 @@ trait ServiceBoundContext extends Context { ...@@ -67,11 +67,13 @@ trait ServiceBoundContext extends Context {
} catch { } catch {
case ignored: RemoteException => // Nothing case ignored: RemoteException => // Nothing
} }
callback = null
} }
if (connection != null) { if (connection != null) {
unbindService(connection) unbindService(connection)
connection = null connection = null
} }
bgService = null
} }
} }
} }
...@@ -157,6 +157,54 @@ class Shadowsocks ...@@ -157,6 +157,54 @@ class Shadowsocks
// Services // Services
var currentServiceName = classOf[ShadowsocksNatService].getName 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() { override def onServiceConnected() {
// Update the UI // Update the UI
...@@ -188,14 +236,6 @@ class Shadowsocks ...@@ -188,14 +236,6 @@ class Shadowsocks
if (fab != null) fab.setEnabled(false) 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 = private lazy val preferences =
getFragmentManager.findFragmentById(android.R.id.content).asInstanceOf[ShadowsocksSettings] getFragmentManager.findFragmentById(android.R.id.content).asInstanceOf[ShadowsocksSettings]
private var adView: AdView = _ private var adView: AdView = _
...@@ -377,16 +417,7 @@ class Shadowsocks ...@@ -377,16 +417,7 @@ class Shadowsocks
}) })
// Bind to the service // Bind to the service
handler.post(() => { handler.post(() => attachService)
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)
}
})
})
} }
def reloadProfile() { def reloadProfile() {
...@@ -447,7 +478,7 @@ class Shadowsocks ...@@ -447,7 +478,7 @@ class Shadowsocks
// Check if current profile changed // Check if current profile changed
if (ShadowsocksApplication.profileId != currentProfile.id) reloadProfile() if (ShadowsocksApplication.profileId != currentProfile.id) reloadProfile()
trafficUpdated(TrafficMonitor.getTxRate, TrafficMonitor.getRxRate, callback.trafficUpdated(TrafficMonitor.getTxRate, TrafficMonitor.getRxRate,
TrafficMonitor.getTxTotal, TrafficMonitor.getRxTotal) TrafficMonitor.getTxTotal, TrafficMonitor.getRxTotal)
} }
...@@ -584,42 +615,4 @@ class Shadowsocks ...@@ -584,42 +615,4 @@ class Shadowsocks
progressTag = -1 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
})
}
} }
...@@ -54,7 +54,6 @@ import com.github.shadowsocks.aidl.Config ...@@ -54,7 +54,6 @@ import com.github.shadowsocks.aidl.Config
import com.github.shadowsocks.utils._ import com.github.shadowsocks.utils._
import scala.collection.JavaConversions._ import scala.collection.JavaConversions._
import scala.collection._
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future import scala.concurrent.Future
...@@ -68,15 +67,14 @@ class ShadowsocksNatService extends BaseService { ...@@ -68,15 +67,14 @@ class ShadowsocksNatService extends BaseService {
"-j DNAT --to-destination 127.0.0.1:8123" "-j DNAT --to-destination 127.0.0.1:8123"
private var notification: ShadowsocksNotification = _ private var notification: ShadowsocksNotification = _
var closeReceiver: BroadcastReceiver = null var closeReceiver: BroadcastReceiver = _
var connReceiver: BroadcastReceiver = null var connReceiver: BroadcastReceiver = _
var apps: Array[ProxiedApp] = null
val myUid = android.os.Process.myUid() val myUid = android.os.Process.myUid()
var sslocalProcess: Process = null var sslocalProcess: Process = _
var sstunnelProcess: Process = null var sstunnelProcess: Process = _
var redsocksProcess: Process = null var redsocksProcess: Process = _
var pdnsdProcess: Process = null var pdnsdProcess: Process = _
private val dnsAddressCache = new SparseArray[String] private val dnsAddressCache = new SparseArray[String]
...@@ -378,16 +376,7 @@ class ShadowsocksNatService extends BaseService { ...@@ -378,16 +376,7 @@ class ShadowsocksNatService extends BaseService {
http_sb.append(Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS) http_sb.append(Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS)
} }
if (config.isProxyApps) { if (config.isProxyApps) {
if (apps == null || apps.length <= 0) { for (uid <- config.proxiedAppString.split('|').distinct) {
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) {
if (!config.isBypassApps) { if (!config.isBypassApps) {
http_sb.append((Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS).replace("-t nat", "-t nat -m owner --uid-owner " + uid)) http_sb.append((Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS).replace("-t nat", "-t nat -m owner --uid-owner " + uid))
} else { } else {
......
...@@ -32,7 +32,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str ...@@ -32,7 +32,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
.setWhen(0) .setWhen(0)
.setColor(ContextCompat.getColor(service, R.color.material_accent_500)) .setColor(ContextCompat.getColor(service, R.color.material_accent_500))
.setTicker(service.getString(R.string.forward_success)) .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]) .setContentIntent(PendingIntent.getActivity(service, 0, new Intent(service, classOf[Shadowsocks])
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0)) .setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0))
.setSmallIcon(R.drawable.ic_stat_shadowsocks) .setSmallIcon(R.drawable.ic_stat_shadowsocks)
......
...@@ -43,9 +43,6 @@ import android.content.{BroadcastReceiver, Context, Intent} ...@@ -43,9 +43,6 @@ import android.content.{BroadcastReceiver, Context, Intent}
import com.github.shadowsocks.utils._ import com.github.shadowsocks.utils._
class ShadowsocksReceiver extends BroadcastReceiver { class ShadowsocksReceiver extends BroadcastReceiver {
val TAG = "Shadowsocks"
def onReceive(context: Context, intent: Intent) { def onReceive(context: Context, intent: Intent) {
if (ShadowsocksApplication.settings.getBoolean(Key.isAutoConnect, false)) { if (ShadowsocksApplication.settings.getBoolean(Key.isAutoConnect, false)) {
Utils.startSsService(context) Utils.startSsService(context)
......
...@@ -67,7 +67,7 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan ...@@ -67,7 +67,7 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
}) })
} }
override def onResume = { override def onResume {
super.onResume super.onResume
isProxyApps.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isProxyApps, false)) // update isProxyApps.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isProxyApps, false)) // update
} }
...@@ -75,9 +75,8 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan ...@@ -75,9 +75,8 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
def onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) = key match { def onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) = key match {
case Key.isNAT => if (ShadowsocksApplication.isRoot && activity != null) { case Key.isNAT => if (ShadowsocksApplication.isRoot && activity != null) {
activity.handler.post(() => { activity.handler.post(() => {
val intent = activity.getIntent activity.deattachService
activity.finish() activity.attachService
startActivity(intent)
}) })
} }
case _ => case _ =>
......
...@@ -54,7 +54,6 @@ import com.github.shadowsocks.utils._ ...@@ -54,7 +54,6 @@ import com.github.shadowsocks.utils._
import org.apache.commons.net.util.SubnetUtils import org.apache.commons.net.util.SubnetUtils
import scala.collection.JavaConversions._ import scala.collection.JavaConversions._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future import scala.concurrent.Future
...@@ -64,16 +63,15 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -64,16 +63,15 @@ class ShadowsocksVpnService extends VpnService with BaseService {
val VPN_MTU = 1500 val VPN_MTU = 1500
val PRIVATE_VLAN = "26.26.26.%s" val PRIVATE_VLAN = "26.26.26.%s"
val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s" val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s"
var conn: ParcelFileDescriptor = null var conn: ParcelFileDescriptor = _
var apps: Array[ProxiedApp] = null var vpnThread: ShadowsocksVpnThread = _
var vpnThread: ShadowsocksVpnThread = null
private var notification: ShadowsocksNotification = _ private var notification: ShadowsocksNotification = _
var closeReceiver: BroadcastReceiver = null var closeReceiver: BroadcastReceiver = _
var sslocalProcess: Process = null var sslocalProcess: Process = _
var sstunnelProcess: Process = null var sstunnelProcess: Process = _
var pdnsdProcess: Process = null var pdnsdProcess: Process = _
var tun2socksProcess: Process = null var tun2socksProcess: Process = _
def isByass(net: SubnetUtils): Boolean = { def isByass(net: SubnetUtils): Boolean = {
val info = net.getInfo val info = net.getInfo
...@@ -392,14 +390,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -392,14 +390,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
if (Utils.isLollipopOrAbove) { if (Utils.isLollipopOrAbove) {
if (config.isProxyApps) { if (config.isProxyApps) {
val apps = AppManager.getProxiedApps(this, config.proxiedAppString) for (pkg <- config.proxiedAppString.split('|').distinct) {
val pkgSet: mutable.HashSet[String] = new mutable.HashSet[String]
for (app <- apps) {
if (app.proxied) {
pkgSet.add(app.packageName)
}
}
for (pkg <- pkgSet) {
if (!config.isBypassApps) { if (!config.isBypassApps) {
builder.addAllowedApplication(pkg) builder.addAllowedApplication(pkg)
} else { } else {
......
...@@ -44,7 +44,6 @@ import com.github.shadowsocks.{R, ShadowsocksApplication} ...@@ -44,7 +44,6 @@ import com.github.shadowsocks.{R, ShadowsocksApplication}
import com.twofortyfouram.locale.api.{Intent => ApiIntent} import com.twofortyfouram.locale.api.{Intent => ApiIntent}
object TaskerSettings { object TaskerSettings {
private val KEY_ACTION = "action"
private val KEY_SWITCH_ON = "switch_on" private val KEY_SWITCH_ON = "switch_on"
private val KEY_PROFILE_ID = "profile_id" private val KEY_PROFILE_ID = "profile_id"
......
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