diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml
index 1ba7a282..f1690588 100755
--- a/src/main/res/values-zh/strings.xml
+++ b/src/main/res/values-zh/strings.xml
@@ -46,6 +46,7 @@
后台服务已停止。
无法连接远程服务器
停止服务
+ 正在关闭影梭
后台服务启动失败:\"%s\"。
确定
端口号应大于1024
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index bcd4bdf5..05536625 100755
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -57,6 +57,7 @@
Shadowsocks stopped.
Failed to connect the remote server
Stop the service
+ Shutting down Shadowsocks
Error: \"%s\".
diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala
index ad4661e1..3df85df0 100644
--- a/src/main/scala/com/github/shadowsocks/AppManager.scala
+++ b/src/main/scala/com/github/shadowsocks/AppManager.scala
@@ -46,7 +46,6 @@ import android.content.pm.PackageManager
import android.graphics.{Bitmap, PixelFormat}
import android.os.Bundle
import android.os.Handler
-import android.os.Message
import android.preference.PreferenceManager
import android.view.View
import android.view.View.OnClickListener
@@ -62,7 +61,9 @@ import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader,
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer
import com.github.shadowsocks.utils.{Utils, Scheme, Key}
-case class ProxiedApp(uid: Int, name: String, var proxied: Boolean)
+import scala.language.implicitConversions
+
+case class ProxiedApp(uid: Int, name: String, packageName: String, var proxied: Boolean)
class ObjectArrayTools[T <: AnyRef](a: Array[T]) {
def binarySearch(key: T) = {
@@ -74,7 +75,7 @@ case class ListEntry(box: CheckBox, text: TextView, icon: ImageView)
object AppManager {
- implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new ObjectArrayTools(a)
+ implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a)
def getProxiedApps(context: Context, proxiedAppString: String): Array[ProxiedApp] = {
@@ -86,13 +87,13 @@ object AppManager {
val appList = packageManager.getInstalledApplications(0)
appList.filter(_.uid >= 10000).map {
- case a => {
+ 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, packageName, proxied)
- }
+ new ProxiedApp(uid, name, packageName, proxied)
}.toArray
}
}
@@ -103,7 +104,7 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
val MSG_LOAD_FINISH = 2
val STUB = android.R.drawable.sym_def_app_icon
- implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new ObjectArrayTools(a)
+ implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a)
var apps: Array[ProxiedApp] = null
var appListView: ListView = null
@@ -129,8 +130,9 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
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, proxied)
+ new ProxiedApp(uid, name, packageName, proxied)
}.toArray
}
@@ -175,7 +177,7 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
.cacheOnDisc()
.displayer(new FadeInBitmapDisplayer(300))
.build()
- ImageLoader.getInstance().displayImage(Scheme.APP + app.uid, entry.icon, options)
+ ImageLoader.getInstance().displayImage(Scheme.APP + app.packageName, entry.icon, options)
entry.text.setText(app.name)
val box: CheckBox = entry.box
@@ -319,8 +321,8 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
}
override def getStreamFromOtherSource(imageUri: String, extra: AnyRef): InputStream = {
- val uid = imageUri.substring(Scheme.APP.length).toInt
- val drawable = Utils.getAppIcon(getBaseContext, uid)
+ val packageName = imageUri.substring(Scheme.APP.length)
+ val drawable = Utils.getAppIcon(getBaseContext, packageName)
val bitmap = Utils.drawableToBitmap(drawable)
val os = new ByteArrayOutputStream()
diff --git a/src/main/scala/com/github/shadowsocks/BaseService.scala b/src/main/scala/com/github/shadowsocks/BaseService.scala
index 19da9814..67813e3c 100644
--- a/src/main/scala/com/github/shadowsocks/BaseService.scala
+++ b/src/main/scala/com/github/shadowsocks/BaseService.scala
@@ -81,11 +81,15 @@ trait BaseService {
}
override def stop() {
- stopRunner()
+ if (state != State.CONNECTING && state != State.STOPPING) {
+ stopRunner()
+ }
}
override def start(config: Config) {
- startRunner(config)
+ if (state != State.CONNECTING && state != State.STOPPING) {
+ startRunner(config)
+ }
}
}
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
index d991dcd3..86730640 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
@@ -49,6 +49,7 @@ import android.net.{Network, ConnectivityManager}
import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log
+import android.widget.Toast
import com.github.shadowsocks.aidl.Config
import com.github.shadowsocks.utils._
import com.google.android.gms.analytics.HitBuilders
@@ -459,6 +460,7 @@ class ShadowsocksNatService extends Service with BaseService {
filter.addAction(Action.CLOSE)
closeReceiver = new BroadcastReceiver() {
def onReceive(p1: Context, p2: Intent) {
+ Toast.makeText(p1, R.string.stopping, Toast.LENGTH_SHORT)
stopRunner()
}
}
@@ -521,6 +523,9 @@ class ShadowsocksNatService extends Service with BaseService {
override def stopRunner() {
+ // channge the state
+ changeState(State.STOPPING)
+
// clean up recevier
if (closeReceiver != null) {
unregisterReceiver(closeReceiver)
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
index 30bde077..572dc701 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
@@ -47,6 +47,7 @@ import android.content.pm.{PackageInfo, PackageManager}
import android.net.VpnService
import android.os._
import android.util.Log
+import android.widget.Toast
import com.github.shadowsocks.aidl.Config
import com.github.shadowsocks.utils._
import com.google.android.gms.analytics.HitBuilders
@@ -190,7 +191,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
val pkgSet: mutable.HashSet[String] = new mutable.HashSet[String]
for (app <- apps) {
if (app.proxied) {
- pkgSet.add(app.name)
+ pkgSet.add(app.packageName)
}
}
for (pkg <- pkgSet) {
@@ -396,6 +397,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
filter.addAction(Intent.ACTION_SHUTDOWN)
receiver = new BroadcastReceiver {
def onReceive(p1: Context, p2: Intent) {
+ Toast.makeText(p1, R.string.stopping, Toast.LENGTH_SHORT)
stopRunner()
}
}
@@ -448,7 +450,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
override def stopRunner() {
// channge the state
- changeState(State.STOPPED)
+ changeState(State.STOPPING)
// send event
application.tracker.send(new HitBuilders.EventBuilder()
@@ -476,6 +478,9 @@ class ShadowsocksVpnService extends VpnService with BaseService {
unregisterReceiver(receiver)
receiver = null
}
+
+ // channge the state
+ changeState(State.STOPPED)
}
override def stopBackgroundService() {
diff --git a/src/main/scala/com/github/shadowsocks/utils/Constants.scala b/src/main/scala/com/github/shadowsocks/utils/Constants.scala
index 679cec50..1f2a3405 100644
--- a/src/main/scala/com/github/shadowsocks/utils/Constants.scala
+++ b/src/main/scala/com/github/shadowsocks/utils/Constants.scala
@@ -101,7 +101,8 @@ object State {
val INIT = 0
val CONNECTING = 1
val CONNECTED = 2
- val STOPPED = 3
+ val STOPPING = 3
+ val STOPPED = 4
def isAvailable(state: Int): Boolean = state != CONNECTED && state != CONNECTING
}
diff --git a/src/main/scala/com/github/shadowsocks/utils/Utils.scala b/src/main/scala/com/github/shadowsocks/utils/Utils.scala
index fd62d047..f0f4b102 100644
--- a/src/main/scala/com/github/shadowsocks/utils/Utils.scala
+++ b/src/main/scala/com/github/shadowsocks/utils/Utils.scala
@@ -332,6 +332,16 @@ object Utils {
bitmap
}
+ def getAppIcon(c: Context, packageName: String): Drawable = {
+ val pm: PackageManager = c.getPackageManager
+ val icon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon)
+ try {
+ pm.getApplicationIcon(packageName)
+ } catch {
+ case e: PackageManager.NameNotFoundException => icon
+ }
+ }
+
def getAppIcon(c: Context, uid: Int): Drawable = {
val pm: PackageManager = c.getPackageManager
val icon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon)