Update to Android O preview 2
* Update support library to beta1; * Adapt to new foreground service policy; * Add a separate notification channel for NAT service; * Adapt to `findViewById` method signature changes. Possible issues: NAT notification will possibly not hide in lockscreen.
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ jdk:
|
||||
|
||||
env:
|
||||
global:
|
||||
- NDK_VERSION=r14
|
||||
- NDK_VERSION=r15-beta2
|
||||
- NDK_CCACHE=ccache
|
||||
- GOROOT_BOOTSTRAP=$GOROOT
|
||||
- ANDROID_NDK_HOME=$HOME/.android/android-ndk-${NDK_VERSION}
|
||||
|
||||
@@ -18,10 +18,12 @@ lazy val commonSettings = Seq(
|
||||
shrinkResources := true,
|
||||
typedResources := false,
|
||||
|
||||
resConfigs := Seq("ja", "ko", "ru", "zh-rCN", "zh-rTW")
|
||||
resConfigs := Seq("ja", "ko", "ru", "zh-rCN", "zh-rTW"),
|
||||
|
||||
resolvers += "google" at "https://maven.google.com"
|
||||
)
|
||||
|
||||
val supportLibsVersion = "26.0.0-alpha1"
|
||||
val supportLibsVersion = "26.0.0-beta1"
|
||||
lazy val root = Project(id = "shadowsocks-android", base = file("."))
|
||||
.settings(commonSettings)
|
||||
.aggregate(plugin, mobile)
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
<string name="udp_dns_summary">Forward all DNS requests to remote</string>
|
||||
|
||||
<!-- notification category -->
|
||||
<string name="service">Service</string>
|
||||
<string name="service_vpn">VPN Service</string>
|
||||
<string name="service_nat">NAT Service</string>
|
||||
<string name="forward_success">Shadowsocks started.</string>
|
||||
<string name="invalid_server">Invalid server name</string>
|
||||
<string name="service_failed">Failed to connect the remote server</string>
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.net.Inet6Address
|
||||
import android.app.Service
|
||||
import android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
|
||||
import android.os.{Handler, IBinder, RemoteCallbackList}
|
||||
import android.support.v4.os.BuildCompat
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
@@ -65,6 +66,7 @@ trait BaseService extends Service {
|
||||
lazy val handler = new Handler(getMainLooper)
|
||||
lazy val restartHanlder = new Handler(getMainLooper)
|
||||
|
||||
private var notification: ShadowsocksNotification = _
|
||||
private val closeReceiver: BroadcastReceiver = (context: Context, _: Intent) => {
|
||||
Toast.makeText(context, R.string.stopping, Toast.LENGTH_SHORT).show()
|
||||
stopRunner(stopService = true)
|
||||
@@ -160,10 +162,12 @@ trait BaseService extends Service {
|
||||
pluginPath = PluginManager.init(plugin)
|
||||
}
|
||||
|
||||
def createNotification(): ShadowsocksNotification
|
||||
def startRunner(profile: Profile) {
|
||||
this.profile = profile
|
||||
|
||||
startService(new Intent(this, getClass))
|
||||
if (BuildCompat.isAtLeastO) startForegroundService(new Intent(this, getClass))
|
||||
else startService(new Intent(this, getClass))
|
||||
TrafficMonitor.reset()
|
||||
trafficMonitorThread = new TrafficMonitorThread(getApplicationContext)
|
||||
trafficMonitorThread.start()
|
||||
@@ -177,6 +181,7 @@ trait BaseService extends Service {
|
||||
closeReceiverRegistered = true
|
||||
}
|
||||
|
||||
notification = createNotification()
|
||||
app.track(getClass.getSimpleName, "start")
|
||||
|
||||
changeState(State.CONNECTING)
|
||||
@@ -198,6 +203,8 @@ trait BaseService extends Service {
|
||||
closeReceiverRegistered = false
|
||||
}
|
||||
|
||||
if (notification != null) notification.destroy()
|
||||
|
||||
// Make sure update total traffic when stopping the runner
|
||||
updateTrafficTotal(TrafficMonitor.txTotal, TrafficMonitor.rxTotal)
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ class MainActivity extends Activity with ServiceBoundContext with Drawer.OnDrawe
|
||||
txRateText = findViewById(R.id.txRate).asInstanceOf[TextView]
|
||||
rxText = findViewById(R.id.rx).asInstanceOf[TextView]
|
||||
rxRateText = findViewById(R.id.rxRate).asInstanceOf[TextView]
|
||||
findViewById(R.id.stat).setOnClickListener(_ => if (state == State.CONNECTED && app.isVpnEnabled) {
|
||||
findViewById[View](R.id.stat).setOnClickListener(_ => if (state == State.CONNECTED && app.isVpnEnabled) {
|
||||
testCount += 1
|
||||
statusText.setText(R.string.connection_test_testing)
|
||||
val id = testCount // it would change by other code
|
||||
|
||||
@@ -44,6 +44,7 @@ import com.j256.ormlite.logger.LocalLog
|
||||
import eu.chainfire.libsuperuser.Shell
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.collection.JavaConversions._
|
||||
|
||||
object ShadowsocksApplication {
|
||||
var app: ShadowsocksApplication = _
|
||||
@@ -156,8 +157,10 @@ class ShadowsocksApplication extends Application {
|
||||
|
||||
TcpFastOpen.enabled(settings.getBoolean(Key.tfo, TcpFastOpen.sendEnabled))
|
||||
|
||||
if (BuildCompat.isAtLeastO) getSystemService(classOf[NotificationManager]).createNotificationChannel(
|
||||
new NotificationChannel("service", getText(R.string.service), NotificationManager.IMPORTANCE_MIN))
|
||||
if (BuildCompat.isAtLeastO) getSystemService(classOf[NotificationManager]).createNotificationChannels(List(
|
||||
new NotificationChannel("service-vpn", getText(R.string.service_vpn), NotificationManager.IMPORTANCE_MIN),
|
||||
new NotificationChannel("service-nat", getText(R.string.service_nat), NotificationManager.IMPORTANCE_LOW)
|
||||
))
|
||||
}
|
||||
|
||||
def crashRecovery() {
|
||||
|
||||
@@ -43,7 +43,6 @@ class ShadowsocksNatService extends BaseService {
|
||||
val CMD_IPTABLES_DNAT_ADD_SOCKS =
|
||||
"iptables -t nat -A OUTPUT -p tcp -j DNAT --to-destination 127.0.0.1:8123"
|
||||
|
||||
private var notification: ShadowsocksNotification = _
|
||||
val myUid: Int = android.os.Process.myUid()
|
||||
|
||||
var sslocalProcess: GuardedProcess = _
|
||||
@@ -204,12 +203,11 @@ class ShadowsocksNatService extends BaseService {
|
||||
AclSyncJob.schedule(profile.route)
|
||||
|
||||
changeState(State.CONNECTED)
|
||||
notification = new ShadowsocksNotification(this, profile.name, true)
|
||||
}
|
||||
|
||||
override def stopRunner(stopService: Boolean, msg: String = null) {
|
||||
override def createNotification() = new ShadowsocksNotification(this, profile.name, "service-nat", true)
|
||||
|
||||
if (notification != null) notification.destroy()
|
||||
override def stopRunner(stopService: Boolean, msg: String = null) {
|
||||
|
||||
// channge the state
|
||||
changeState(State.STOPPING)
|
||||
|
||||
@@ -35,7 +35,8 @@ import com.github.shadowsocks.utils.{Action, State, TrafficMonitor, Utils}
|
||||
/**
|
||||
* @author Mygod
|
||||
*/
|
||||
class ShadowsocksNotification(private val service: BaseService, profileName: String, visible: Boolean = false) {
|
||||
class ShadowsocksNotification(private val service: BaseService, profileName: String,
|
||||
channel: String, visible: Boolean = false) {
|
||||
private val keyGuard = service.getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager]
|
||||
private lazy val nm = service.getSystemService(Context.NOTIFICATION_SERVICE).asInstanceOf[NotificationManager]
|
||||
private lazy val callback = new Stub {
|
||||
@@ -61,7 +62,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
|
||||
.setContentIntent(PendingIntent.getActivity(service, 0, new Intent(service, classOf[MainActivity])
|
||||
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0))
|
||||
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
|
||||
.setChannel("service")
|
||||
.setChannel(channel)
|
||||
if (Build.VERSION.SDK_INT < 24) builder.addAction(R.drawable.ic_navigation_close,
|
||||
service.getString(R.string.stop), PendingIntent.getBroadcast(service, 0, new Intent(Action.CLOSE), 0))
|
||||
private lazy val style = new BigTextStyle(builder)
|
||||
@@ -99,9 +100,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
|
||||
show()
|
||||
} else if (forceShow) show()
|
||||
|
||||
def show(): Unit =
|
||||
if (BuildCompat.isAtLeastO) nm.startServiceInForeground(new Intent(service, service.getClass), 1, builder.build())
|
||||
else service.startForeground(1, builder.build)
|
||||
def show(): Unit = service.startForeground(1, builder.build)
|
||||
|
||||
def destroy() {
|
||||
if (lockReceiver != null) {
|
||||
|
||||
@@ -42,7 +42,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s"
|
||||
var conn: ParcelFileDescriptor = _
|
||||
var vpnThread: ShadowsocksVpnThread = _
|
||||
private var notification: ShadowsocksNotification = _
|
||||
|
||||
var sslocalProcess: GuardedProcess = _
|
||||
var overtureProcess: GuardedProcess = _
|
||||
@@ -69,8 +68,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
vpnThread = null
|
||||
}
|
||||
|
||||
if (notification != null) notification.destroy()
|
||||
|
||||
// channge the state
|
||||
changeState(State.STOPPING)
|
||||
|
||||
@@ -117,6 +114,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
super.startRunner(profile)
|
||||
}
|
||||
|
||||
override def createNotification() = new ShadowsocksNotification(this, profile.name, "service-vpn")
|
||||
|
||||
override def connect() {
|
||||
super.connect()
|
||||
|
||||
@@ -137,8 +136,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
if (profile.route != Acl.ALL && profile.route != Acl.CUSTOM_RULES)
|
||||
AclSyncJob.schedule(profile.route)
|
||||
|
||||
notification = new ShadowsocksNotification(this, profile.name)
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
|
||||
Reference in New Issue
Block a user