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:
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. */
......
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