From 5e0d52324b9f7699d0f2c779e8c1bfc505d44564 Mon Sep 17 00:00:00 2001 From: Mygod Date: Tue, 24 Nov 2015 19:25:41 +0800 Subject: [PATCH] Add traffic to notification --- src/main/res/values/strings.xml | 1 + .../com/github/shadowsocks/BaseService.scala | 2 +- .../com/github/shadowsocks/Shadowsocks.scala | 2 +- .../shadowsocks/ShadowsocksNatService.scala | 2 +- .../shadowsocks/ShadowsocksNotification.scala | 51 ++++++++++++------- .../shadowsocks/ShadowsocksVpnService.scala | 2 +- 6 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 02f32d08..444b5ddf 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -15,6 +15,7 @@ Network Traffic Sent: \t\t\t\t\t%3$s\t↑\t%1$s/s\nReceived: \t%4$s\t↓\t%2$s/s \n%1$s↑\t%2$s↓ + %1$s/s↑\t%2$s/s↓ Byte Bytes diff --git a/src/main/scala/com/github/shadowsocks/BaseService.scala b/src/main/scala/com/github/shadowsocks/BaseService.scala index a372066e..5b8a8314 100644 --- a/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -58,7 +58,7 @@ trait BaseService extends Service { final val callbacks = new RemoteCallbackList[IShadowsocksServiceCallback] - protected val binder = new IShadowsocksService.Stub { + val binder = new IShadowsocksService.Stub { override def getMode: Int = { getServiceMode } diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index aa6ecc75..32aba6a5 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -346,7 +346,7 @@ class Shadowsocks super.onCreate(savedInstanceState) setContentView(R.layout.layout_main) - // Initialize action bar + // Initialize Toolbar val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar] toolbar.setTitle(getString(R.string.screen_name)) toolbar.setTitleTextAppearance(toolbar.getContext, R.style.Toolbar_Logo) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index 9f87966a..16bd2a42 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -453,8 +453,8 @@ class ShadowsocksNatService extends BaseService { // Set DNS flushDns() - notification = new ShadowsocksNotification(this, config.profileName, true) changeState(State.CONNECTED) + notification = new ShadowsocksNotification(this, config.profileName, true) } else { changeState(State.STOPPED, getString(R.string.service_failed)) stopRunner() diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala index 8228f9c9..8a8b06bd 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala @@ -7,54 +7,66 @@ import android.content.{BroadcastReceiver, Context, Intent, IntentFilter} import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat.BigTextStyle import android.support.v4.content.ContextCompat +import com.github.shadowsocks.aidl.IShadowsocksServiceCallback.Stub import com.github.shadowsocks.utils.{Action, State, Utils} /** * @author Mygod */ -class ShadowsocksNotification(private val service: BaseService, profileName: String, visible: Boolean = false) { +class ShadowsocksNotification(private val service: BaseService, profileName: String, visible: Boolean = false, + private val showTraffic: Boolean = true) { private lazy val keyGuard = service.getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager] + private lazy val callback = new Stub { + override def stateChanged(state: Int, msg: String) = () // ignore + override def trafficUpdated(txRate: String, rxRate: String, txTotal: String, rxTotal: String) { + builder.setContentText(service.getString(R.string.traffic_summary).formatLocal(Locale.ENGLISH, txRate, rxRate)) + style.bigText(service.getString(R.string.stat_summary) + .formatLocal(Locale.ENGLISH, txRate, rxRate, txTotal, rxTotal)) + show() + } + } private var lockReceiver: BroadcastReceiver = _ private val builder = new NotificationCompat.Builder(service) .setWhen(0) .setColor(ContextCompat.getColor(service, R.color.material_accent_500)) .setTicker(service.getString(R.string.forward_success)) - .setContentTitle(service.getString(R.string.app_name)) - .setContentText(service.getString(R.string.service_running).formatLocal(Locale.ENGLISH, profileName)) + .setContentTitle(service.getString(R.string.app_name) + ": " + 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) .addAction(android.R.drawable.ic_menu_close_clear_cancel, service.getString(R.string.stop), PendingIntent.getBroadcast(service, 0, new Intent(Action.CLOSE), 0)) - private val style = new BigTextStyle(builder) - if (visible && Utils.isLollipopOrAbove) { + private lazy val style = new BigTextStyle(builder) + private val showOnUnlock = visible && Utils.isLollipopOrAbove + if (showOnUnlock || showTraffic) { + update(Intent.ACTION_USER_PRESENT) + lockReceiver = (context: Context, intent: Intent) => update(intent.getAction) val screenFilter = new IntentFilter() screenFilter.addAction(Intent.ACTION_SCREEN_ON) screenFilter.addAction(Intent.ACTION_SCREEN_OFF) screenFilter.addAction(Intent.ACTION_USER_PRESENT) - lockReceiver = (context: Context, intent: Intent) => if (service.getState == State.CONNECTED) { - val action = intent.getAction - if (action == Intent.ACTION_SCREEN_OFF) { - setVisible(false).show() - } else if (action == Intent.ACTION_SCREEN_ON) { - if (!keyGuard.inKeyguardRestrictedInputMode) { - setVisible(true).show() - } - } else if (action == Intent.ACTION_USER_PRESENT) { - setVisible(true).show() - } - } service.registerReceiver(lockReceiver, screenFilter) + } else setVisible(visible).show() + + private def update(action: String) = if (service.getState == State.CONNECTED) { + if (action == Intent.ACTION_SCREEN_OFF) { + if (showOnUnlock) setVisible(false) + if (showTraffic) service.binder.unregisterCallback(callback) + } else if (action == Intent.ACTION_USER_PRESENT || + action == Intent.ACTION_SCREEN_ON && !keyGuard.inKeyguardRestrictedInputMode) { + setVisible(showOnUnlock) + if (showTraffic) service.binder.registerCallback(callback) + } + show() } - setVisible(visible).show() def setVisible(visible: Boolean) = { builder.setPriority(if (visible) NotificationCompat.PRIORITY_DEFAULT else NotificationCompat.PRIORITY_MIN) this } - def notification = style.build() + def notification = if (showTraffic) style.build() else builder.build() def show() = service.startForeground(1, notification) def destroy() = { @@ -62,6 +74,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str service.unregisterReceiver(lockReceiver) lockReceiver = null } + if (showTraffic) service.binder.unregisterCallback(callback) service.stopForeground(true) } } diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index cc89cdc9..4a29ed6c 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -247,8 +247,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { } if (resolved && handleConnection) { - notification = new ShadowsocksNotification(this, config.profileName) changeState(State.CONNECTED) + notification = new ShadowsocksNotification(this, config.profileName) } else { changeState(State.STOPPED, getString(R.string.service_failed)) stopRunner()