Commit 424e1bd1 authored by Mygod's avatar Mygod

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