Commit 99a6c4ff authored by Mygod's avatar Mygod

Extract notification logic

parent 19c49107
......@@ -41,14 +41,13 @@ package com.github.shadowsocks
import java.util.{Timer, TimerTask}
import android.app.Notification
import android.app.Service
import android.content.Context
import android.os.{Handler, RemoteCallbackList}
import android.util.Log
import com.github.shadowsocks.aidl.{Config, IShadowsocksService, IShadowsocksServiceCallback}
import com.github.shadowsocks.utils.{State, TrafficMonitor, TrafficMonitorThread}
trait BaseService {
trait BaseService extends Service {
@volatile private var state = State.INIT
@volatile private var callbackCount = 0
......@@ -197,8 +196,4 @@ trait BaseService {
state = s
})
}
def initSoundVibrateLights(notification: Notification) {
notification.sound = null
}
}
......@@ -44,13 +44,10 @@ import java.lang.Process
import java.net.{Inet6Address, InetAddress}
import java.util.Locale
import android.app._
import android.content._
import android.content.pm.{PackageInfo, PackageManager}
import android.net.{ConnectivityManager, Network}
import android.os._
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import android.util.{Log, SparseArray}
import android.widget.Toast
import com.github.shadowsocks.aidl.Config
......@@ -62,7 +59,7 @@ import scala.collection.mutable.ArrayBuffer
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
class ShadowsocksNatService extends Service with BaseService {
class ShadowsocksNatService extends BaseService {
val TAG = "ShadowsocksNatService"
......@@ -70,7 +67,7 @@ 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"
var lockReceiver: BroadcastReceiver = null
private var notification: ShadowsocksNotification = _
var closeReceiver: BroadcastReceiver = null
var connReceiver: BroadcastReceiver = null
var apps: Array[ProxiedApp] = null
......@@ -324,33 +321,6 @@ class ShadowsocksNatService extends Service with BaseService {
true
}
def notifyForegroundAlert(title: String, info: String, visible: Boolean) {
val openIntent = new Intent(this, classOf[Shadowsocks])
openIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
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)
.setColor(ContextCompat.getColor(this, R.color.material_accent_500))
.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)
}
def onBind(intent: Intent): IBinder = {
Log.d(TAG, "onBind")
if (Action.SERVICE == intent.getAction) {
......@@ -443,30 +413,6 @@ class ShadowsocksNatService extends Service with BaseService {
}
registerReceiver(closeReceiver, filter)
if (Utils.isLollipopOrAbove) {
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 (getState == State.CONNECTED) {
val action = intent.getAction
if (action == Intent.ACTION_SCREEN_OFF) {
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), false)
} else if (action == Intent.ACTION_SCREEN_ON) {
val keyGuard = getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager]
if (!keyGuard.inKeyguardRestrictedInputMode) {
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), true)
}
} else if (action == Intent.ACTION_USER_PRESENT) {
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), true)
}
}
registerReceiver(lockReceiver, screenFilter)
}
ShadowsocksApplication.track(TAG, "start")
changeState(State.CONNECTING)
......@@ -507,8 +453,7 @@ class ShadowsocksNatService extends Service with BaseService {
// Set DNS
flushDns()
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), true)
notification = new ShadowsocksNotification(this, config.profileName, true)
changeState(State.CONNECTED)
} else {
changeState(State.STOPPED, getString(R.string.service_failed))
......@@ -531,12 +476,7 @@ class ShadowsocksNatService extends Service with BaseService {
closeReceiver = null
}
if (Utils.isLollipopOrAbove) {
if (lockReceiver != null) {
unregisterReceiver(lockReceiver)
lockReceiver = null
}
}
notification.destroy()
ShadowsocksApplication.track(TAG, "stop")
......@@ -548,8 +488,6 @@ class ShadowsocksNatService extends Service with BaseService {
stopSelf()
}
stopForeground(true)
// change the state
changeState(State.STOPPED)
}
......
package com.github.shadowsocks
import java.util.Locale
import android.app.{KeyguardManager, PendingIntent}
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.utils.{Action, State, Utils}
/**
* @author Mygod
*/
class ShadowsocksNotification(private val service: BaseService, profileName: String, visible: Boolean = false) {
private lazy val keyGuard = service.getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager]
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))
.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) {
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)
}
setVisible(visible).show()
def setVisible(visible: Boolean) = {
builder.setPriority(if (visible) NotificationCompat.PRIORITY_DEFAULT else NotificationCompat.PRIORITY_MIN)
this
}
def notification = style.build()
def show() = service.startForeground(1, notification)
def destroy() = {
if (lockReceiver != null) {
service.unregisterReceiver(lockReceiver)
lockReceiver = null
}
service.stopForeground(true)
}
}
......@@ -43,13 +43,10 @@ import java.io.File
import java.lang.Process
import java.util.Locale
import android.app._
import android.content._
import android.content.pm.{PackageInfo, PackageManager}
import android.net.VpnService
import android.os._
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import android.util.Log
import android.widget.Toast
import com.github.shadowsocks.aidl.Config
......@@ -70,6 +67,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
var conn: ParcelFileDescriptor = null
var apps: Array[ProxiedApp] = null
var vpnThread: ShadowsocksVpnThread = null
private var notification: ShadowsocksNotification = _
var closeReceiver: BroadcastReceiver = null
var sslocalProcess: Process = null
......@@ -108,32 +106,6 @@ 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)
.setColor(ContextCompat.getColor(this, R.color.material_accent_500))
.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)
......@@ -152,7 +124,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
vpnThread = null
}
stopForeground(true)
notification.destroy()
// channge the state
changeState(State.STOPPING)
......@@ -275,8 +247,7 @@ 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)
notification = new ShadowsocksNotification(this, config.profileName)
changeState(State.CONNECTED)
} else {
changeState(State.STOPPED, getString(R.string.service_failed))
......
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