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)