diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index bb48c119..d90311cc 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,102 +1,107 @@ + package="com.github.shadowsocks" + android:versionCode="120" + android:versionName="2.8.3"> - - - - + + + + - + - + - + - - + + - + - - - - - - + + + + + + - - - - - - - - + + + + + + + + - - + + - - - - - - + + + + + + - - + + - - - - - + + - - - - - - + + + + + - + + + + + + + + diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala index 7a5a021a..6c2a3532 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala @@ -65,10 +65,15 @@ class ShadowsocksReceiver extends BroadcastReceiver { val isAutoConnect: Boolean = settings.getBoolean(Key.isAutoConnect, false) val isInstalled: Boolean = status.getBoolean(versionName, false) if (isAutoConnect && isInstalled) { - val intent = new Intent(context, classOf[ShadowsocksRunnerActivity]) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - context.startActivity(intent) + if (Utils.isLollipopOrAbove) { + val intent = new Intent(context, classOf[ShadowsocksRunnerService]) + context.startService(intent) + } else { + val intent = new Intent(context, classOf[ShadowsocksRunnerActivity]) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + context.startActivity(intent) + } } } } diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerService.scala new file mode 100644 index 00000000..981c5d30 --- /dev/null +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerService.scala @@ -0,0 +1,125 @@ +/* + * Shadowsocks - A shadowsocks client for Android + * Copyright (C) 2014 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * ___====-_ _-====___ + * _--^^^#####// \\#####^^^--_ + * _-^##########// ( ) \\##########^-_ + * -############// |\^^/| \\############- + * _/############// (@::@) \\############\_ + * /#############(( \\// ))#############\ + * -###############\\ (oo) //###############- + * -#################\\ / VV \ //#################- + * -###################\\/ \//###################- + * _#/|##########/\######( /\ )######/\##########|\#_ + * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| + * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' + * ` ` ` ` / | | | | \ ' ' ' ' + * ( | | | | ) + * __\ | | | | /__ + * (vvv(VVV)(VVV)vvv) + * + * HERE BE DRAGONS + * + */ + +package com.github.shadowsocks + +import android.app.Service +import android.content._ +import android.net.VpnService +import android.os._ +import android.preference.PreferenceManager +import com.github.shadowsocks.aidl.IShadowsocksService +import com.github.shadowsocks.utils._ + +class ShadowsocksRunnerService extends Service { + + private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this) + private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE) + + val handler = new Handler() + val connection = new ServiceConnection { + override def onServiceConnected(name: ComponentName, service: IBinder) { + bgService = IShadowsocksService.Stub.asInterface(service) + handler.postDelayed(() => if (bgService != null) startBackgroundService(), 1000) + } + override def onServiceDisconnected(name: ComponentName) { + bgService = null + } + } + + // Variables + var vpnEnabled = -1 + var bgService: IShadowsocksService = null + + def isVpnEnabled: Boolean = { + if (vpnEnabled < 0) { + vpnEnabled = if ((!Utils.isLollipopOrAbove || status.getBoolean(Key.isNAT, false)) && Console.isRoot) { + 0 + } else { + 1 + } + } + if (vpnEnabled == 1) true else false + } + + override def onBind(intent: Intent): IBinder = { + null + } + + def startBackgroundService() { + if (isVpnEnabled) { + val intent = VpnService.prepare(ShadowsocksRunnerService.this) + if (intent == null) { + if (bgService != null) { + bgService.start(ConfigUtils.load(settings)) + } + } + } else { + bgService.start(ConfigUtils.load(settings)) + } + stopSelf() + } + + def attachService() { + if (bgService == null) { + val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService] + val intent = new Intent(this, s) + intent.setAction(Action.SERVICE) + bindService(intent, connection, Context.BIND_AUTO_CREATE) + startService(new Intent(this, s)) + } + } + + def deattachService() { + if (bgService != null) { + unbindService(connection) + bgService = null + } + } + + override def onCreate() { + super.onCreate() + attachService() + } + + override def onDestroy() { + super.onDestroy() + deattachService() + } +}