diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index 57046599..3b993fbe 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -69,25 +69,13 @@ class ShadowsocksNatService extends Service with BaseService { val CMD_IPTABLES_DNAT_ADD_SOCKS = " -t nat -A OUTPUT -p tcp " + "-j DNAT --to-destination 127.0.0.1:8123" - private val mStartForegroundSignature = Array[Class[_]](classOf[Int], classOf[Notification]) - private val mStopForegroundSignature = Array[Class[_]](classOf[Boolean]) - private val mSetForegroundSignature = Array[Class[_]](classOf[Boolean]) - private val mSetForegroundArgs = new Array[AnyRef](1) - private val mStartForegroundArgs = new Array[AnyRef](2) - private val mStopForegroundArgs = new Array[AnyRef](1) - var lockReceiver: BroadcastReceiver = null var closeReceiver: BroadcastReceiver = null var connReceiver: BroadcastReceiver = null - var notificationManager: NotificationManager = null var config: Config = null var apps: Array[ProxiedApp] = null val myUid = Process.myUid() - private var mSetForeground: Method = null - private var mStartForeground: Method = null - private var mStopForeground: Method = null - private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication] private val dnsAddressCache = new SparseArray[String] @@ -321,17 +309,6 @@ class ShadowsocksNatService extends Service with BaseService { true } - def invokeMethod(method: Method, args: Array[AnyRef]) { - try { - method.invoke(this, mStartForegroundArgs: _*) - } catch { - case e: InvocationTargetException => - Log.w(TAG, "Unable to invoke method", e) - case e: IllegalAccessException => - Log.w(TAG, "Unable to invoke method", e) - } - } - def notifyForegroundAlert(title: String, info: String, visible: Boolean) { val openIntent = new Intent(this, classOf[Shadowsocks]) openIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) @@ -355,7 +332,7 @@ class ShadowsocksNatService extends Service with BaseService { else builder.setPriority(NotificationCompat.PRIORITY_MIN) - startForegroundCompat(1, builder.build) + startForeground(1, builder.build) } def onBind(intent: Intent): IBinder = { @@ -369,29 +346,7 @@ class ShadowsocksNatService extends Service with BaseService { override def onCreate() { super.onCreate() - ConfigUtils.refresh(this) - - notificationManager = this - .getSystemService(Context.NOTIFICATION_SERVICE) - .asInstanceOf[NotificationManager] - try { - mStartForeground = getClass.getMethod("startForeground", mStartForegroundSignature: _*) - mStopForeground = getClass.getMethod("stopForeground", mStopForegroundSignature: _*) - } catch { - case e: NoSuchMethodException => - mStartForeground = { - mStopForeground = null - mStopForeground - } - } - try { - mSetForeground = getClass.getMethod("setForeground", mSetForegroundSignature: _*) - } catch { - case e: NoSuchMethodException => - throw new IllegalStateException( - "OS doesn't have Service.startForeground OR Service.setForeground!") - } } def killProcesses() { @@ -462,44 +417,6 @@ class ShadowsocksNatService extends Service with BaseService { Console.runRootCommand(http_sb.toArray) } - /** - * This is a wrapper around the new startForeground method, using the older - * APIs if it is not available. - */ - def startForegroundCompat(id: Int, notification: Notification) { - if (mStartForeground != null) { - mStartForegroundArgs(0) = int2Integer(id) - mStartForegroundArgs(1) = notification - invokeMethod(mStartForeground, mStartForegroundArgs) - return - } - mSetForegroundArgs(0) = boolean2Boolean(x = true) - invokeMethod(mSetForeground, mSetForegroundArgs) - notificationManager.notify(id, notification) - } - - /** - * This is a wrapper around the new stopForeground method, using the older - * APIs if it is not available. - */ - def stopForegroundCompat(id: Int) { - if (mStopForeground != null) { - mStopForegroundArgs(0) = boolean2Boolean(x = true) - try { - mStopForeground.invoke(this, mStopForegroundArgs: _*) - } catch { - case e: InvocationTargetException => - Log.w(TAG, "Unable to invoke stopForeground", e) - case e: IllegalAccessException => - Log.w(TAG, "Unable to invoke stopForeground", e) - } - return - } - notificationManager.cancel(id) - mSetForegroundArgs(0) = boolean2Boolean(x = false) - invokeMethod(mSetForeground, mSetForegroundArgs) - } - override def startRunner(c: Config) { config = c @@ -627,7 +544,7 @@ class ShadowsocksNatService extends Service with BaseService { stopSelf() } - stopForegroundCompat(1) + stopForeground(true) // change the state changeState(State.STOPPED) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 14abd751..ad17afc8 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._ import android.content.pm.{PackageInfo, PackageManager} import android.net.VpnService import android.os._ +import android.support.v4.app.NotificationCompat import android.util.Log import android.widget.Toast import com.github.shadowsocks.aidl.Config @@ -67,7 +68,6 @@ class ShadowsocksVpnService extends VpnService with BaseService { val PRIVATE_VLAN = "26.26.26.%s" val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s" var conn: ParcelFileDescriptor = null - var notificationManager: NotificationManager = null var receiver: BroadcastReceiver = null var apps: Array[ProxiedApp] = null var config: Config = null @@ -104,15 +104,34 @@ class ShadowsocksVpnService extends VpnService with BaseService { null } + def notifyForegroundAlert(title: String, info: String, visible: Boolean) { + val openIntent = new Intent(this, classOf[Shadowsocks]) + val contentIntent = PendingIntent.getActivity(this, 0, openIntent, 0) + val closeIntent = new Intent(Action.CLOSE) + val actionIntent = PendingIntent.getBroadcast(this, 0, closeIntent, 0) + val builder = new NotificationCompat.Builder(this) + + builder + .setWhen(0) + .setTicker(title) + .setContentTitle(getString(R.string.app_name)) + .setContentText(info) + .setContentIntent(contentIntent) + .setSmallIcon(R.drawable.ic_stat_shadowsocks) + .addAction(android.R.drawable.ic_menu_close_clear_cancel, getString(R.string.stop), + actionIntent) + + if (visible) + builder.setPriority(NotificationCompat.PRIORITY_DEFAULT) + else + builder.setPriority(NotificationCompat.PRIORITY_MIN) + + startForeground(1, builder.build) + } + override def onCreate() { - super.onCreate() - ConfigUtils.refresh(this) - - notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) - .asInstanceOf[NotificationManager] - } override def onRevoke() { @@ -126,6 +145,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { vpnThread = null } + stopForeground(true) + // channge the state changeState(State.STOPPING) @@ -248,6 +269,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { } if (resolved && handleConnection) { + notifyForegroundAlert(getString(R.string.forward_success), + getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), false) changeState(State.CONNECTED) } else { changeState(State.STOPPED, getString(R.string.service_failed))