Commit a755b669 authored by Mygod's avatar Mygod

Fix code style issues

parent 9fb18095
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
[![Build Status](https://api.travis-ci.org/shadowsocks/shadowsocks-android.svg)](https://travis-ci.org/shadowsocks/shadowsocks-android) [![Build Status](https://api.travis-ci.org/shadowsocks/shadowsocks-android.svg)](https://travis-ci.org/shadowsocks/shadowsocks-android)
[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21) [![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21)
[![Releases](https://img.shields.io/github/downloads/shadowsocks/shadowsocks-android/total.svg)](https://github.com/shadowsocks/shadowsocks-android/releases) [![Releases](https://img.shields.io/github/downloads/shadowsocks/shadowsocks-android/total.svg)](https://github.com/shadowsocks/shadowsocks-android/releases)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/1a21d48d466644cdbcb57a1889abea5b)](https://www.codacy.com/app/shadowsocks/shadowsocks-android?utm_source=github.com&utm_medium=referral&utm_content=shadowsocks/shadowsocks-android&utm_campaign=Badge_Grade)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
A [shadowsocks](http://shadowsocks.org) client for Android, written in Kotlin. A [shadowsocks](http://shadowsocks.org) client for Android, written in Kotlin.
......
#!/usr/bin/python #!/usr/bin/python
# -*- encoding: utf8 -*- # -*- encoding: utf8 -*-
import itertools
import math
import sys import sys
import IPy import IPy
......
...@@ -28,8 +28,7 @@ complexity: ...@@ -28,8 +28,7 @@ complexity:
threshold: 5 threshold: 5
ignoreDefaultParameters: true ignoreDefaultParameters: true
MethodOverloading: MethodOverloading:
active: true active: false
threshold: 5
NestedBlockDepth: NestedBlockDepth:
active: true active: true
threshold: 3 threshold: 3
......
...@@ -44,7 +44,6 @@ import android.support.v7.widget.Toolbar ...@@ -44,7 +44,6 @@ import android.support.v7.widget.Toolbar
import android.view.* import android.view.*
import android.widget.ImageView import android.widget.ImageView
import android.widget.Switch import android.widget.Switch
import android.widget.Toast
import com.futuremind.recyclerviewfastscroll.FastScroller import com.futuremind.recyclerviewfastscroll.FastScroller
import com.futuremind.recyclerviewfastscroll.SectionTitleProvider import com.futuremind.recyclerviewfastscroll.SectionTitleProvider
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
...@@ -264,11 +263,9 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener { ...@@ -264,11 +263,9 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
return false return false
} }
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { override fun onKeyUp(keyCode: Int, event: KeyEvent?) = if (keyCode == KeyEvent.KEYCODE_MENU)
return if (keyCode == KeyEvent.KEYCODE_MENU) if (toolbar.isOverflowMenuShowing) toolbar.hideOverflowMenu() else toolbar.showOverflowMenu()
if (toolbar.isOverflowMenuShowing) toolbar.hideOverflowMenu() else toolbar.showOverflowMenu() else super.onKeyUp(keyCode, event)
else super.onKeyUp(keyCode, event)
}
override fun onDestroy() { override fun onDestroy() {
instance = null instance = null
......
...@@ -26,7 +26,6 @@ import android.os.Bundle ...@@ -26,7 +26,6 @@ import android.os.Bundle
import android.support.design.widget.Snackbar import android.support.design.widget.Snackbar
import android.support.v14.preference.SwitchPreference import android.support.v14.preference.SwitchPreference
import android.support.v7.preference.Preference import android.support.v7.preference.Preference
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.DirectBoot
......
...@@ -62,6 +62,7 @@ import com.mikepenz.materialdrawer.Drawer ...@@ -62,6 +62,7 @@ import com.mikepenz.materialdrawer.Drawer
import com.mikepenz.materialdrawer.DrawerBuilder import com.mikepenz.materialdrawer.DrawerBuilder
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.Proxy import java.net.Proxy
...@@ -178,8 +179,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe ...@@ -178,8 +179,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
val elapsed = SystemClock.elapsedRealtime() - start val elapsed = SystemClock.elapsedRealtime() - start
if (code == 204 || code == 200 && conn.responseLength == 0L) if (code == 204 || code == 200 && conn.responseLength == 0L)
Pair(true, getString(R.string.connection_test_available, elapsed)) Pair(true, getString(R.string.connection_test_available, elapsed))
else throw Exception(getString(R.string.connection_test_error_status_code, code)) else throw IOException(getString(R.string.connection_test_error_status_code, code))
} catch (e: Exception) { } catch (e: IOException) {
Pair(false, getString(R.string.connection_test_error, e.message)) Pair(false, getString(R.string.connection_test_error, e.message))
} finally { } finally {
conn.disconnect() conn.disconnect()
......
...@@ -179,27 +179,25 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu ...@@ -179,27 +179,25 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
} else super.onActivityResult(requestCode, resultCode, data) } else super.onActivityResult(requestCode, resultCode, data)
} }
override fun onMenuItemClick(item: MenuItem): Boolean { override fun onMenuItemClick(item: MenuItem) = when (item.itemId) {
return when (item.itemId) { R.id.action_delete -> {
R.id.action_delete -> { val activity = activity!!
val activity = activity!! AlertDialog.Builder(activity)
AlertDialog.Builder(activity) .setTitle(R.string.delete_confirm_prompt)
.setTitle(R.string.delete_confirm_prompt) .setPositiveButton(R.string.yes, { _, _ ->
.setPositiveButton(R.string.yes, { _, _ -> ProfileManager.delProfile(profile.id)
ProfileManager.delProfile(profile.id) activity.finish()
activity.finish() })
}) .setNegativeButton(R.string.no, null)
.setNegativeButton(R.string.no, null) .create()
.create() .show()
.show() true
true }
} R.id.action_apply -> {
R.id.action_apply -> { saveAndExit()
saveAndExit() true
true
}
else -> false
} }
else -> false
} }
override fun onDestroy() { override fun onDestroy() {
......
...@@ -37,7 +37,6 @@ import android.view.* ...@@ -37,7 +37,6 @@ import android.view.*
import android.widget.ImageView import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.bg.TrafficMonitor import com.github.shadowsocks.bg.TrafficMonitor
...@@ -374,9 +373,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { ...@@ -374,9 +373,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
Snackbar.LENGTH_LONG).show() Snackbar.LENGTH_LONG).show()
return true return true
} }
} catch (exc: Exception) { } catch (_: IndexOutOfBoundsException) { }
app.track(exc)
}
Snackbar.make(activity!!.findViewById(R.id.snackbar), R.string.action_import_err, Snackbar.LENGTH_LONG) Snackbar.make(activity!!.findViewById(R.id.snackbar), R.string.action_import_err, Snackbar.LENGTH_LONG)
.show() .show()
true true
......
...@@ -139,31 +139,29 @@ class ScannerActivity : AppCompatActivity(), ZXingScannerView.ResultHandler, Too ...@@ -139,31 +139,29 @@ class ScannerActivity : AppCompatActivity(), ZXingScannerView.ResultHandler, Too
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true), if (manual) REQUEST_IMPORT else REQUEST_IMPORT_OR_FINISH) .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true), if (manual) REQUEST_IMPORT else REQUEST_IMPORT_OR_FINISH)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) { when (requestCode) {
REQUEST_IMPORT, REQUEST_IMPORT_OR_FINISH -> { REQUEST_IMPORT, REQUEST_IMPORT_OR_FINISH -> if (resultCode == Activity.RESULT_OK) {
if (resultCode == Activity.RESULT_OK) { var list = listOfNotNull(data?.data)
var list = listOfNotNull(data?.data) val clipData = data?.clipData
val clipData = data?.clipData if (clipData != null) list += (0 until clipData.itemCount).map { clipData.getItemAt(it).uri }
if (clipData != null) list += (0 until clipData.itemCount).map { clipData.getItemAt(it).uri } val resolver = contentResolver
val resolver = contentResolver val reader = MultiFormatReader()
val reader = MultiFormatReader() var success = false
var success = false for (uri in list) try {
for (uri in list) try { val bitmap = BitmapFactory.decodeStream(resolver.openInputStream(uri))
val bitmap = BitmapFactory.decodeStream(resolver.openInputStream(uri)) val pixels = IntArray(bitmap.width * bitmap.height)
val pixels = IntArray(bitmap.width * bitmap.height) bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) Profile.findAll(reader.decode(BinaryBitmap(HybridBinarizer(
Profile.findAll(reader.decode(BinaryBitmap(HybridBinarizer( RGBLuminanceSource(bitmap.width, bitmap.height, pixels)))).text).forEach {
RGBLuminanceSource(bitmap.width, bitmap.height, pixels)))).text).forEach { ProfileManager.createProfile(it)
ProfileManager.createProfile(it) success = true
success = true
}
} catch (e: Exception) {
app.track(e)
} }
Toast.makeText(this, if (success) R.string.action_import_msg else R.string.action_import_err, } catch (e: Exception) {
Toast.LENGTH_SHORT).show() app.track(e)
finish() }
} else if (requestCode == REQUEST_IMPORT_OR_FINISH) finish() Toast.makeText(this, if (success) R.string.action_import_msg else R.string.action_import_err,
} Toast.LENGTH_SHORT).show()
finish()
} else if (requestCode == REQUEST_IMPORT_OR_FINISH) finish()
else -> super.onActivityResult(requestCode, resultCode, data) else -> super.onActivityResult(requestCode, resultCode, data)
} }
} }
......
...@@ -124,7 +124,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener, ...@@ -124,7 +124,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
override fun afterTextChanged(s: Editable) = validate(value = s) override fun afterTextChanged(s: Editable) = validate(value = s)
override fun onNothingSelected(parent: AdapterView<*>?) = throw IllegalStateException() override fun onNothingSelected(parent: AdapterView<*>?) = check(false)
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) = validate(position) override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) = validate(position)
private fun validate(template: Int = templateSelector.selectedItemPosition, value: Editable = editText.text) { private fun validate(template: Int = templateSelector.selectedItemPosition, value: Editable = editText.text) {
...@@ -228,16 +228,14 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener, ...@@ -228,16 +228,14 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun getItemCount(): Int = acl.subnets.size() + acl.hostnames.size() + acl.urls.size() override fun getItemCount(): Int = acl.subnets.size() + acl.hostnames.size() + acl.urls.size()
override fun getSectionTitle(i: Int): String { override fun getSectionTitle(i: Int): String {
val j = i - acl.subnets.size() val j = i - acl.subnets.size()
return try { return (if (j < 0) acl.subnets[i].address.hostAddress.substring(0, 1) else {
(if (j < 0) acl.subnets[i].address.hostAddress.substring(0, 1) else { val k = j - acl.hostnames.size()
val k = j - acl.hostnames.size() if (k < 0) {
if (k < 0) { val hostname = acl.hostnames[j]
val hostname = acl.hostnames[j] // don't convert IDN yet
// don't convert IDN yet PATTERN_DOMAIN.find(hostname)?.value?.replace("\\.", ".") ?: hostname
PATTERN_DOMAIN.find(hostname)?.value?.replace("\\.", ".") ?: hostname } else acl.urls[k].host
} else acl.urls[k].host }).firstOrNull()?.toString() ?: " "
}).substring(0, 1)
} catch (_: IndexOutOfBoundsException) { " " }
} }
private fun apply() { private fun apply() {
......
...@@ -31,7 +31,6 @@ import android.os.RemoteCallbackList ...@@ -31,7 +31,6 @@ import android.os.RemoteCallbackList
import android.support.v4.os.UserManagerCompat import android.support.v4.os.UserManagerCompat
import android.util.Base64 import android.util.Base64
import android.util.Log import android.util.Log
import android.widget.Toast
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R import com.github.shadowsocks.R
import com.github.shadowsocks.acl.Acl import com.github.shadowsocks.acl.Acl
...@@ -146,18 +145,18 @@ object BaseService { ...@@ -146,18 +145,18 @@ object BaseService {
} }
internal fun updateTrafficTotal(tx: Long, rx: Long) { internal fun updateTrafficTotal(tx: Long, rx: Long) {
val profile = profile ?: return // this.profile may have host, etc. modified and thus a re-fetch is necessary (possible race condition)
val p = ProfileManager.getProfile(profile.id) ?: return // profile may have host, etc. modified val profile = ProfileManager.getProfile((profile ?: return).id) ?: return
p.tx += tx profile.tx += tx
p.rx += rx profile.rx += rx
ProfileManager.updateProfile(p) ProfileManager.updateProfile(profile)
app.handler.post { app.handler.post {
if (bandwidthListeners.isNotEmpty()) { if (bandwidthListeners.isNotEmpty()) {
val n = callbacks.beginBroadcast() val n = callbacks.beginBroadcast()
for (i in 0 until n) { for (i in 0 until n) {
try { try {
val item = callbacks.getBroadcastItem(i) val item = callbacks.getBroadcastItem(i)
if (bandwidthListeners.contains(item.asBinder())) item.trafficPersisted(p.id) if (bandwidthListeners.contains(item.asBinder())) item.trafficPersisted(profile.id)
} catch (_: Exception) { } // ignore } catch (_: Exception) { } // ignore
} }
callbacks.finishBroadcast() callbacks.finishBroadcast()
...@@ -182,9 +181,9 @@ object BaseService { ...@@ -182,9 +181,9 @@ object BaseService {
.put("plugin_opts", plugin.toString()) .put("plugin_opts", plugin.toString())
} }
// sensitive Shadowsocks config is stored in // sensitive Shadowsocks config is stored in
val file = File((if (UserManagerCompat.isUserUnlocked(app)) app.filesDir else @TargetApi(24) { val file = File(if (UserManagerCompat.isUserUnlocked(app)) app.filesDir else @TargetApi(24) {
app.deviceContext.noBackupFilesDir // only API 24+ will be in locked state app.deviceContext.noBackupFilesDir // only API 24+ will be in locked state
}), CONFIG_FILE) }, CONFIG_FILE)
shadowsocksConfigFile = file shadowsocksConfigFile = file
file.writeText(config.toString()) file.writeText(config.toString())
return file return file
...@@ -218,9 +217,9 @@ object BaseService { ...@@ -218,9 +217,9 @@ object BaseService {
false false
} else true } else true
fun forceLoad() { fun forceLoad() {
val p = app.currentProfile val profile = app.currentProfile
?: return stopRunner(true, (this as Context).getString(R.string.profile_empty)) ?: return stopRunner(true, (this as Context).getString(R.string.profile_empty))
if (!checkProfile(p)) return if (!checkProfile(profile)) return
val s = data.state val s = data.state
when (s) { when (s) {
STOPPED -> startRunner() STOPPED -> startRunner()
......
...@@ -24,22 +24,19 @@ import android.util.Log ...@@ -24,22 +24,19 @@ import android.util.Log
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.BuildConfig import com.github.shadowsocks.BuildConfig
import org.xbill.DNS.* import org.xbill.DNS.*
import java.net.Inet6Address import java.io.IOException
import java.net.InetAddress import java.net.*
import java.net.NetworkInterface
import java.net.UnknownHostException
import okhttp3.Dns as Okdns
object Dns { object Dns {
private const val TAG = "Dns" private const val TAG = "Dns"
private val hasIPv6Support get() = try { private val hasIPv6Support get() = try {
val result = NetworkInterface.getNetworkInterfaces().asSequence().flatMap { it.inetAddresses.asSequence() } val result = NetworkInterface.getNetworkInterfaces().asSequence().flatMap { it.inetAddresses.asSequence() }
.count { it is Inet6Address && !it.isLoopbackAddress && !it.isLinkLocalAddress } > 0 .any { it is Inet6Address && !it.isLoopbackAddress && !it.isLinkLocalAddress }
if (result && BuildConfig.DEBUG) Log.d(TAG, "IPv6 address detected") if (result && BuildConfig.DEBUG) Log.d(TAG, "IPv6 address detected")
result result
} catch (ex: Exception) { } catch (ex: SocketException) {
Log.e(TAG, "Failed to get interfaces' addresses.") Log.e(TAG, "Failed to get interfaces' addresses.", ex)
app.track(ex) app.track(ex)
false false
} }
...@@ -60,7 +57,7 @@ object Dns { ...@@ -60,7 +57,7 @@ object Dns {
Type.AAAA -> return (r as AAAARecord).address.hostAddress Type.AAAA -> return (r as AAAARecord).address.hostAddress
} }
} }
} catch (_: Exception) { } } catch (_: IOException) { }
return null return null
} }
private fun resolve(host: String): String? = try { private fun resolve(host: String): String? = try {
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
package com.github.shadowsocks.bg package com.github.shadowsocks.bg
import android.content.Context
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.acl.Acl import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
...@@ -50,10 +49,10 @@ object LocalDnsService { ...@@ -50,10 +49,10 @@ object LocalDnsService {
fun makeDns(name: String, address: String, timeout: Int, edns: Boolean = true): JSONObject { fun makeDns(name: String, address: String, timeout: Int, edns: Boolean = true): JSONObject {
val dns = JSONObject() val dns = JSONObject()
.put("Name", name) .put("Name", name)
.put("Address", (when (address.parseNumericAddress()) { .put("Address", when (address.parseNumericAddress()) {
is Inet6Address -> "[$address]" is Inet6Address -> "[$address]"
else -> address else -> address
})) })
.put("Timeout", timeout) .put("Timeout", timeout)
.put("EDNSClientSubnet", JSONObject().put("Policy", "disable")) .put("EDNSClientSubnet", JSONObject().put("Policy", "disable"))
if (edns) dns if (edns) dns
......
...@@ -23,7 +23,6 @@ package com.github.shadowsocks.bg ...@@ -23,7 +23,6 @@ package com.github.shadowsocks.bg
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.os.IBinder
import com.github.shadowsocks.database.Profile
/** /**
* Shadowsocks service at its minimum. * Shadowsocks service at its minimum.
......
...@@ -44,7 +44,7 @@ object TrafficMonitor { ...@@ -44,7 +44,7 @@ object TrafficMonitor {
private val units = arrayOf("KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB", "NB", "DB", "CB") private val units = arrayOf("KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB", "NB", "DB", "CB")
private val numberFormat = DecimalFormat("@@@") private val numberFormat = DecimalFormat("@@@")
fun formatTraffic(size: Long): String { fun formatTraffic(size: Long): String {
var n: Double = size.toDouble() var n = size.toDouble()
var i = -1 var i = -1
while (n >= 999.5) { while (n >= 999.5) {
n /= 1024 n /= 1024
......
...@@ -38,7 +38,7 @@ class TrafficMonitorThread : LocalSocketListener("TrafficMonitorThread") { ...@@ -38,7 +38,7 @@ class TrafficMonitorThread : LocalSocketListener("TrafficMonitorThread") {
val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN) val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN)
TrafficMonitor.update(stat.getLong(0), stat.getLong(8)) TrafficMonitor.update(stat.getLong(0), stat.getLong(8))
socket.outputStream.write(0) socket.outputStream.write(0)
} catch (e: Exception) { } catch (e: IOException) {
Log.e(tag, "Error when recv traffic stat", e) Log.e(tag, "Error when recv traffic stat", e)
app.track(e) app.track(e)
} }
......
...@@ -38,6 +38,7 @@ import com.github.shadowsocks.utils.Subnet ...@@ -38,6 +38,7 @@ import com.github.shadowsocks.utils.Subnet
import com.github.shadowsocks.utils.parseNumericAddress import com.github.shadowsocks.utils.parseNumericAddress
import java.io.File import java.io.File
import java.io.FileDescriptor import java.io.FileDescriptor
import java.io.IOException
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util.* import java.util.*
import android.net.VpnService as BaseVpnService import android.net.VpnService as BaseVpnService
...@@ -55,18 +56,24 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -55,18 +56,24 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
override val socketFile: File = File(app.deviceContext.filesDir, "protect_path") override val socketFile: File = File(app.deviceContext.filesDir, "protect_path")
override fun accept(socket: LocalSocket) { override fun accept(socket: LocalSocket) {
var success = false
try { try {
socket.inputStream.read() socket.inputStream.read()
val fds = socket.ancillaryFileDescriptors val fds = socket.ancillaryFileDescriptors
if (fds.isEmpty()) return if (fds.isEmpty()) return
val fd = getInt.invoke(fds.first()) as Int val fd = getInt.invoke(fds.first()) as Int
val ret = protect(fd) success = protect(fd)
JniHelper.close(fd) // Trick to close file decriptor JniHelper.close(fd) // Trick to close file decriptor
socket.outputStream.write(if (ret) 0 else 1)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(tag, "Error when protect socket", e) Log.e(tag, "Error when protect socket", e)
app.track(e) app.track(e)
} }
try {
socket.outputStream.write(if (success) 0 else 1)
} catch (e: IOException) {
Log.e(tag, "Error when returning result in protect", e)
app.track(e)
}
} }
} }
class NullConnectionException : NullPointerException() class NullConnectionException : NullPointerException()
...@@ -118,7 +125,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -118,7 +125,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
super.startNativeProcesses() super.startNativeProcesses()
val fd = startVpn() val fd = startVpn()
if (!sendFd(fd)) throw Exception("sendFd failed") if (!sendFd(fd)) throw IOException("sendFd failed")
} }
override fun buildAdditionalArguments(cmd: ArrayList<String>): ArrayList<String> { override fun buildAdditionalArguments(cmd: ArrayList<String>): ArrayList<String> {
......
...@@ -72,10 +72,10 @@ object PrivateDatabase : OrmLiteSqliteOpenHelper(app, Key.DB_PROFILE, null, 25) ...@@ -72,10 +72,10 @@ object PrivateDatabase : OrmLiteSqliteOpenHelper(app, Key.DB_PROFILE, null, 25)
profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;") profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;")
TableUtils.createTable(connectionSource, Profile::class.java) TableUtils.createTable(connectionSource, Profile::class.java)
profileDao.executeRawNoArgs( profileDao.executeRawNoArgs(
"INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," + "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route," +
" udpdns, ipv6, individual) " + " proxyApps, bypass, udpdns, ipv6, individual) " +
"SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global, bypass, udpdns, ipv6," + "SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global," +
" individual FROM `tmp`;") " bypass, udpdns, ipv6, individual FROM `tmp`;")
profileDao.executeRawNoArgs("DROP TABLE `tmp`;") profileDao.executeRawNoArgs("DROP TABLE `tmp`;")
profileDao.executeRawNoArgs("COMMIT;") profileDao.executeRawNoArgs("COMMIT;")
} else if (oldVersion < 13) { } else if (oldVersion < 13) {
......
...@@ -36,6 +36,7 @@ import java.util.* ...@@ -36,6 +36,7 @@ import java.util.*
class Profile : Serializable { class Profile : Serializable {
companion object { companion object {
private const val TAG = "ShadowParser" private const val TAG = "ShadowParser"
private const val serialVersionUID = 0L
private val pattern = """(?i)ss://[-a-zA-Z0-9+&@#/%?=~_|!:,.;\[\]]*[-a-zA-Z0-9+&@#/%=~_|\[\]]""".toRegex() private val pattern = """(?i)ss://[-a-zA-Z0-9+&@#/%?=~_|!:,.;\[\]]*[-a-zA-Z0-9+&@#/%=~_|\[\]]""".toRegex()
private val userInfoPattern = "^(.+?):(.*)$".toRegex() private val userInfoPattern = "^(.+?):(.*)$".toRegex()
private val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)$".toRegex() private val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)$".toRegex()
......
...@@ -25,79 +25,69 @@ import com.github.shadowsocks.App.Companion.app ...@@ -25,79 +25,69 @@ import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.ProfilesFragment import com.github.shadowsocks.ProfilesFragment
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.DirectBoot
import java.sql.SQLException
/**
* SQLExceptions are not caught (and therefore will cause crash) for insert/update transactions
* to ensure we are in a consistent state.
*/
object ProfileManager { object ProfileManager {
private const val TAG = "ProfileManager" private const val TAG = "ProfileManager"
@Throws(SQLException::class)
fun createProfile(p: Profile? = null): Profile { fun createProfile(p: Profile? = null): Profile {
val profile = p ?: Profile() val profile = p ?: Profile()
profile.id = 0 profile.id = 0
try { val oldProfile = app.currentProfile
val oldProfile = app.currentProfile if (oldProfile != null) {
if (oldProfile != null) { // Copy Feature Settings from old profile
// Copy Feature Settings from old profile profile.route = oldProfile.route
profile.route = oldProfile.route profile.ipv6 = oldProfile.ipv6
profile.ipv6 = oldProfile.ipv6 profile.proxyApps = oldProfile.proxyApps
profile.proxyApps = oldProfile.proxyApps profile.bypass = oldProfile.bypass
profile.bypass = oldProfile.bypass profile.individual = oldProfile.individual
profile.individual = oldProfile.individual profile.udpdns = oldProfile.udpdns
profile.udpdns = oldProfile.udpdns
}
val last = PrivateDatabase.profileDao.queryRaw(PrivateDatabase.profileDao.queryBuilder()
.selectRaw("MAX(userOrder)").prepareStatementString()).firstResult
if (last != null && last.size == 1 && last[0] != null) profile.userOrder = last[0].toLong() + 1
PrivateDatabase.profileDao.createOrUpdate(profile)
ProfilesFragment.instance?.profilesAdapter?.add(profile)
} catch (ex: Exception) {
Log.e(TAG, "addProfile", ex)
app.track(ex)
} }
val last = PrivateDatabase.profileDao.queryRaw(PrivateDatabase.profileDao.queryBuilder()
.selectRaw("MAX(userOrder)").prepareStatementString()).firstResult
if (last != null && last.size == 1 && last[0] != null) profile.userOrder = last[0].toLong() + 1
PrivateDatabase.profileDao.createOrUpdate(profile)
ProfilesFragment.instance?.profilesAdapter?.add(profile)
return profile return profile
} }
/** /**
* Note: It's caller's responsibility to update DirectBoot profile if necessary. * Note: It's caller's responsibility to update DirectBoot profile if necessary.
*/ */
fun updateProfile(profile: Profile): Boolean = try { @Throws(SQLException::class)
PrivateDatabase.profileDao.update(profile) fun updateProfile(profile: Profile) = PrivateDatabase.profileDao.update(profile)
true
} catch (ex: Exception) {
Log.e(TAG, "updateProfile", ex)
app.track(ex)
false
}
fun getProfile(id: Int): Profile? = try { fun getProfile(id: Int): Profile? = try {
PrivateDatabase.profileDao.queryForId(id) PrivateDatabase.profileDao.queryForId(id)
} catch (ex: Exception) { } catch (ex: SQLException) {
Log.e(TAG, "getProfile", ex) Log.e(TAG, "getProfile", ex)
app.track(ex) app.track(ex)
null null
} }
fun delProfile(id: Int): Boolean = try { @Throws(SQLException::class)
fun delProfile(id: Int) {
PrivateDatabase.profileDao.deleteById(id) PrivateDatabase.profileDao.deleteById(id)
ProfilesFragment.instance?.profilesAdapter?.removeId(id) ProfilesFragment.instance?.profilesAdapter?.removeId(id)
if (id == DataStore.profileId && DataStore.directBootAware) DirectBoot.clean() if (id == DataStore.profileId && DataStore.directBootAware) DirectBoot.clean()
true
} catch (ex: Exception) {
Log.e(TAG, "delProfile", ex)
app.track(ex)
false
} }
fun getFirstProfile(): Profile? = try { fun getFirstProfile(): Profile? = try {
val result = PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().limit(1L).prepare()) PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().limit(1L).prepare()).singleOrNull()
if (result.size == 1) result[0] else null } catch (ex: SQLException) {
} catch (ex: Exception) { Log.e(TAG, "getFirstProfile", ex)
Log.e(TAG, "getAllProfiles", ex)
app.track(ex) app.track(ex)
null null
} }
fun getAllProfiles(): List<Profile>? = try { fun getAllProfiles(): List<Profile>? = try {
PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().orderBy("userOrder", true).prepare()) PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().orderBy("userOrder", true).prepare())
} catch (ex: Exception) { } catch (ex: SQLException) {
Log.e(TAG, "getAllProfiles", ex) Log.e(TAG, "getAllProfiles", ex)
app.track(ex) app.track(ex)
null null
......
...@@ -52,7 +52,7 @@ object DataStore { ...@@ -52,7 +52,7 @@ object DataStore {
/** /**
* Setter is defined in MainActivity.onPreferenceDataStoreChanged. * Setter is defined in MainActivity.onPreferenceDataStoreChanged.
*/ */
val directBootAware: Boolean get() = BootReceiver.enabled && (publicStore.getBoolean(Key.directBootAware) ?: false) val directBootAware: Boolean get() = BootReceiver.enabled && publicStore.getBoolean(Key.directBootAware) == true
var serviceMode: String var serviceMode: String
get() = publicStore.getString(Key.serviceMode) ?: Key.modeVpn get() = publicStore.getString(Key.serviceMode) ?: Key.modeVpn
set(value) = publicStore.putString(Key.serviceMode, value) set(value) = publicStore.putString(Key.serviceMode, value)
......
...@@ -28,11 +28,7 @@ import android.util.AttributeSet ...@@ -28,11 +28,7 @@ import android.util.AttributeSet
class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) { class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) {
var entryIcons: Array<Drawable?>? = null var entryIcons: Array<Drawable?>? = null
val selectedEntry: Int get() = entryValues.indexOf(value) val selectedEntry: Int get() = entryValues.indexOf(value)
val entryIcon: Drawable? get() = try { val entryIcon: Drawable? get() = entryIcons?.getOrNull(selectedEntry)
entryIcons?.get(selectedEntry)
} catch (_: ArrayIndexOutOfBoundsException) {
null
}
// fun setEntryIcons(@ArrayRes entryIconsResId: Int) { // fun setEntryIcons(@ArrayRes entryIconsResId: Int) {
// val array = getContext().getResources().obtainTypedArray(entryIconsResId) // val array = getContext().getResources().obtainTypedArray(entryIconsResId)
// entryIcons = Array(array.length(), { i -> array.getDrawable(i) }) // entryIcons = Array(array.length(), { i -> array.getDrawable(i) })
...@@ -49,7 +45,7 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr ...@@ -49,7 +45,7 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
} }
init { init {
super.setOnPreferenceChangeListener({ preference, newValue -> super.setOnPreferenceChangeListener { preference, newValue ->
val listener = listener val listener = listener
if (listener == null || listener.onPreferenceChange(preference, newValue)) { if (listener == null || listener.onPreferenceChange(preference, newValue)) {
value = newValue.toString() value = newValue.toString()
...@@ -57,7 +53,7 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr ...@@ -57,7 +53,7 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
if (entryIcons != null) icon = entryIcon if (entryIcons != null) icon = entryIcon
true true
} else false } else false
}) }
// val a = context.obtainStyledAttributes(attrs, R.styleable.IconListPreference) // val a = context.obtainStyledAttributes(attrs, R.styleable.IconListPreference)
// val entryIconsResId: Int = a.getResourceId(R.styleable.IconListPreference_entryIcons, -1) // val entryIconsResId: Int = a.getResourceId(R.styleable.IconListPreference_entryIcons, -1)
// if (entryIconsResId != -1) entryIcons = entryIconsResId // if (entryIconsResId != -1) entryIcons = entryIconsResId
......
...@@ -85,12 +85,12 @@ class ConfigActivity : AppCompatActivity() { ...@@ -85,12 +85,12 @@ class ConfigActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
try { val intent = intent
taskerOption = Settings.fromIntent(intent!!) if (intent == null) {
} catch (_: Exception) {
finish() finish()
return return
} }
taskerOption = Settings.fromIntent(intent)
setContentView(R.layout.layout_tasker) setContentView(R.layout.layout_tasker)
val toolbar = findViewById<Toolbar>(R.id.toolbar) val toolbar = findViewById<Toolbar>(R.id.toolbar)
......
...@@ -44,8 +44,8 @@ class Settings(bundle: Bundle?) { ...@@ -44,8 +44,8 @@ class Settings(bundle: Bundle?) {
if (profileId >= 0) bundle.putInt(KEY_PROFILE_ID, profileId) if (profileId >= 0) bundle.putInt(KEY_PROFILE_ID, profileId)
val profile = ProfileManager.getProfile(profileId) val profile = ProfileManager.getProfile(profileId)
return Intent().putExtra(ApiIntent.EXTRA_BUNDLE, bundle).putExtra(ApiIntent.EXTRA_STRING_BLURB, return Intent().putExtra(ApiIntent.EXTRA_BUNDLE, bundle).putExtra(ApiIntent.EXTRA_STRING_BLURB,
if (profile != null) if (profile != null) context.getString(if (switchOn) R.string.start_service else R.string.stop_service,
context.getString(if (switchOn) R.string.start_service else R.string.stop_service, profile.formattedName) profile.formattedName)
else context.getString(if (switchOn) R.string.start_service_default else R.string.stop)) else context.getString(if (switchOn) R.string.start_service_default else R.string.stop))
} }
} }
...@@ -20,9 +20,7 @@ ...@@ -20,9 +20,7 @@
package com.github.shadowsocks.utils package com.github.shadowsocks.utils
import java.util.ArrayList import java.util.*
import java.util.Arrays
import java.util.StringTokenizer
/** /**
* Commandline objects help handling command lines specifying processes to * Commandline objects help handling command lines specifying processes to
...@@ -86,9 +84,7 @@ object Commandline { ...@@ -86,9 +84,7 @@ object Commandline {
* @return empty string for null or no command, else every argument split * @return empty string for null or no command, else every argument split
* by spaces and quoted by quoting rules. * by spaces and quoted by quoting rules.
*/ */
fun toString(args: Array<String>): String { fun toString(args: Array<String>) = toString(args.asIterable()) // thanks to Java, arrays aren't iterable
return toString(Arrays.asList(*args)) // thanks to Java, arrays aren't iterable
}
/** /**
* Crack a command line. * Crack a command line.
......
...@@ -7,7 +7,7 @@ import com.github.shadowsocks.database.Profile ...@@ -7,7 +7,7 @@ import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.IOException
import java.io.ObjectInputStream import java.io.ObjectInputStream
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
...@@ -17,7 +17,7 @@ object DirectBoot { ...@@ -17,7 +17,7 @@ object DirectBoot {
fun getDeviceProfile(): Profile? = try { fun getDeviceProfile(): Profile? = try {
ObjectInputStream(file.inputStream()).use { it.readObject() as Profile } ObjectInputStream(file.inputStream()).use { it.readObject() as Profile }
} catch (_: FileNotFoundException) { null } } catch (_: IOException) { null }
fun clean() { fun clean() {
file.delete() file.delete()
......
...@@ -28,8 +28,8 @@ fun String.parseNumericAddress(): InetAddress? { ...@@ -28,8 +28,8 @@ fun String.parseNumericAddress(): InetAddress? {
} }
fun parsePort(str: String?, default: Int, min: Int = 1025): Int { fun parsePort(str: String?, default: Int, min: Int = 1025): Int {
val x = str?.toIntOrNull() ?: default val value = str?.toIntOrNull() ?: default
return if (x < min || x > 65535) default else x return if (value < min || value > 65535) default else value
} }
fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver = object : BroadcastReceiver() { fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver = object : BroadcastReceiver() {
...@@ -72,6 +72,6 @@ private class SortedListIterable<out T>(private val list: SortedList<T>) : Itera ...@@ -72,6 +72,6 @@ private class SortedListIterable<out T>(private val list: SortedList<T>) : Itera
private class SortedListIterator<out T>(private val list: SortedList<T>) : Iterator<T> { private class SortedListIterator<out T>(private val list: SortedList<T>) : Iterator<T> {
private var count = 0 private var count = 0
override fun hasNext() = count < list.size() override fun hasNext() = count < list.size()
override fun next(): T = list[count++] override fun next(): T = if (hasNext()) list[count++] else throw NoSuchElementException()
} }
fun <T> SortedList<T>.asIterable(): Iterable<T> = SortedListIterable(this) fun <T> SortedList<T>.asIterable(): Iterable<T> = SortedListIterable(this)
...@@ -29,7 +29,6 @@ import android.support.graphics.drawable.AnimatedVectorDrawableCompat ...@@ -29,7 +29,6 @@ import android.support.graphics.drawable.AnimatedVectorDrawableCompat
import android.support.v7.widget.TooltipCompat import android.support.v7.widget.TooltipCompat
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R import com.github.shadowsocks.R
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import java.util.* import java.util.*
......
...@@ -70,8 +70,8 @@ abstract class NativePluginProvider : ContentProvider() { ...@@ -70,8 +70,8 @@ abstract class NativePluginProvider : ContentProvider() {
/** /**
* Returns executable entry absolute path. This is used if plugin is sharing UID with the host. * Returns executable entry absolute path. This is used if plugin is sharing UID with the host.
* *
* Default behavior is throwing UnsupportedOperationException. If you don't wish to use this feature, use the default * Default behavior is throwing UnsupportedOperationException. If you don't wish to use this feature, use the
* behavior. * default behavior.
* *
* @return Absolute path for executable entry. * @return Absolute path for executable entry.
*/ */
......
...@@ -29,13 +29,11 @@ import android.widget.Toast ...@@ -29,13 +29,11 @@ import android.widget.Toast
* Activity that's capable of getting EXTRA_OPTIONS input. * Activity that's capable of getting EXTRA_OPTIONS input.
*/ */
abstract class OptionsCapableActivity : AppCompatActivity() { abstract class OptionsCapableActivity : AppCompatActivity() {
protected fun pluginOptions(intent: Intent = this.intent): PluginOptions { protected fun pluginOptions(intent: Intent = this.intent) = try {
return try { PluginOptions(intent.getStringExtra(PluginContract.EXTRA_OPTIONS))
PluginOptions(intent.getStringExtra(PluginContract.EXTRA_OPTIONS)) } catch (exc: IllegalArgumentException) {
} catch (exc: IllegalArgumentException) { Toast.makeText(this, exc.message, Toast.LENGTH_SHORT).show()
Toast.makeText(this, exc.message, Toast.LENGTH_SHORT).show() PluginOptions()
PluginOptions()
}
} }
/** /**
......
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