Commit a755b669 authored by Mygod's avatar Mygod

Fix code style issues

parent 9fb18095
......@@ -3,6 +3,7 @@
[![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)
[![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)
A [shadowsocks](http://shadowsocks.org) client for Android, written in Kotlin.
......
#!/usr/bin/python
# -*- encoding: utf8 -*-
import itertools
import math
import sys
import IPy
......
......@@ -28,8 +28,7 @@ complexity:
threshold: 5
ignoreDefaultParameters: true
MethodOverloading:
active: true
threshold: 5
active: false
NestedBlockDepth:
active: true
threshold: 3
......
......@@ -44,7 +44,6 @@ import android.support.v7.widget.Toolbar
import android.view.*
import android.widget.ImageView
import android.widget.Switch
import android.widget.Toast
import com.futuremind.recyclerviewfastscroll.FastScroller
import com.futuremind.recyclerviewfastscroll.SectionTitleProvider
import com.github.shadowsocks.App.Companion.app
......@@ -264,11 +263,9 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
return false
}
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
return if (keyCode == KeyEvent.KEYCODE_MENU)
override fun onKeyUp(keyCode: Int, event: KeyEvent?) = if (keyCode == KeyEvent.KEYCODE_MENU)
if (toolbar.isOverflowMenuShowing) toolbar.hideOverflowMenu() else toolbar.showOverflowMenu()
else super.onKeyUp(keyCode, event)
}
override fun onDestroy() {
instance = null
......
......@@ -26,7 +26,6 @@ import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v14.preference.SwitchPreference
import android.support.v7.preference.Preference
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot
......
......@@ -62,6 +62,7 @@ import com.mikepenz.materialdrawer.Drawer
import com.mikepenz.materialdrawer.DrawerBuilder
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
import java.io.IOException
import java.net.HttpURLConnection
import java.net.InetSocketAddress
import java.net.Proxy
......@@ -178,8 +179,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
val elapsed = SystemClock.elapsedRealtime() - start
if (code == 204 || code == 200 && conn.responseLength == 0L)
Pair(true, getString(R.string.connection_test_available, elapsed))
else throw Exception(getString(R.string.connection_test_error_status_code, code))
} catch (e: Exception) {
else throw IOException(getString(R.string.connection_test_error_status_code, code))
} catch (e: IOException) {
Pair(false, getString(R.string.connection_test_error, e.message))
} finally {
conn.disconnect()
......
......@@ -179,8 +179,7 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
} else super.onActivityResult(requestCode, resultCode, data)
}
override fun onMenuItemClick(item: MenuItem): Boolean {
return when (item.itemId) {
override fun onMenuItemClick(item: MenuItem) = when (item.itemId) {
R.id.action_delete -> {
val activity = activity!!
AlertDialog.Builder(activity)
......@@ -200,7 +199,6 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
}
else -> false
}
}
override fun onDestroy() {
DataStore.privateStore.unregisterChangeListener(this)
......
......@@ -37,7 +37,6 @@ import android.view.*
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.bg.TrafficMonitor
......@@ -374,9 +373,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
Snackbar.LENGTH_LONG).show()
return true
}
} catch (exc: Exception) {
app.track(exc)
}
} catch (_: IndexOutOfBoundsException) { }
Snackbar.make(activity!!.findViewById(R.id.snackbar), R.string.action_import_err, Snackbar.LENGTH_LONG)
.show()
true
......
......@@ -139,8 +139,7 @@ class ScannerActivity : AppCompatActivity(), ZXingScannerView.ResultHandler, Too
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true), if (manual) REQUEST_IMPORT else REQUEST_IMPORT_OR_FINISH)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_IMPORT, REQUEST_IMPORT_OR_FINISH -> {
if (resultCode == Activity.RESULT_OK) {
REQUEST_IMPORT, REQUEST_IMPORT_OR_FINISH -> if (resultCode == Activity.RESULT_OK) {
var list = listOfNotNull(data?.data)
val clipData = data?.clipData
if (clipData != null) list += (0 until clipData.itemCount).map { clipData.getItemAt(it).uri }
......@@ -163,7 +162,6 @@ class ScannerActivity : AppCompatActivity(), ZXingScannerView.ResultHandler, Too
Toast.LENGTH_SHORT).show()
finish()
} else if (requestCode == REQUEST_IMPORT_OR_FINISH) finish()
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
......
......@@ -124,7 +124,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
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)
private fun validate(template: Int = templateSelector.selectedItemPosition, value: Editable = editText.text) {
......@@ -228,16 +228,14 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun getItemCount(): Int = acl.subnets.size() + acl.hostnames.size() + acl.urls.size()
override fun getSectionTitle(i: Int): String {
val j = i - acl.subnets.size()
return try {
(if (j < 0) acl.subnets[i].address.hostAddress.substring(0, 1) else {
return (if (j < 0) acl.subnets[i].address.hostAddress.substring(0, 1) else {
val k = j - acl.hostnames.size()
if (k < 0) {
val hostname = acl.hostnames[j]
// don't convert IDN yet
PATTERN_DOMAIN.find(hostname)?.value?.replace("\\.", ".") ?: hostname
} else acl.urls[k].host
}).substring(0, 1)
} catch (_: IndexOutOfBoundsException) { " " }
}).firstOrNull()?.toString() ?: " "
}
private fun apply() {
......
......@@ -31,7 +31,6 @@ import android.os.RemoteCallbackList
import android.support.v4.os.UserManagerCompat
import android.util.Base64
import android.util.Log
import android.widget.Toast
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R
import com.github.shadowsocks.acl.Acl
......@@ -146,18 +145,18 @@ object BaseService {
}
internal fun updateTrafficTotal(tx: Long, rx: Long) {
val profile = profile ?: return
val p = ProfileManager.getProfile(profile.id) ?: return // profile may have host, etc. modified
p.tx += tx
p.rx += rx
ProfileManager.updateProfile(p)
// this.profile may have host, etc. modified and thus a re-fetch is necessary (possible race condition)
val profile = ProfileManager.getProfile((profile ?: return).id) ?: return
profile.tx += tx
profile.rx += rx
ProfileManager.updateProfile(profile)
app.handler.post {
if (bandwidthListeners.isNotEmpty()) {
val n = callbacks.beginBroadcast()
for (i in 0 until n) {
try {
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
}
callbacks.finishBroadcast()
......@@ -182,9 +181,9 @@ object BaseService {
.put("plugin_opts", plugin.toString())
}
// 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
}), CONFIG_FILE)
}, CONFIG_FILE)
shadowsocksConfigFile = file
file.writeText(config.toString())
return file
......@@ -218,9 +217,9 @@ object BaseService {
false
} else true
fun forceLoad() {
val p = app.currentProfile
val profile = app.currentProfile
?: return stopRunner(true, (this as Context).getString(R.string.profile_empty))
if (!checkProfile(p)) return
if (!checkProfile(profile)) return
val s = data.state
when (s) {
STOPPED -> startRunner()
......
......@@ -24,22 +24,19 @@ import android.util.Log
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.BuildConfig
import org.xbill.DNS.*
import java.net.Inet6Address
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.UnknownHostException
import okhttp3.Dns as Okdns
import java.io.IOException
import java.net.*
object Dns {
private const val TAG = "Dns"
private val hasIPv6Support get() = try {
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")
result
} catch (ex: Exception) {
Log.e(TAG, "Failed to get interfaces' addresses.")
} catch (ex: SocketException) {
Log.e(TAG, "Failed to get interfaces' addresses.", ex)
app.track(ex)
false
}
......@@ -60,7 +57,7 @@ object Dns {
Type.AAAA -> return (r as AAAARecord).address.hostAddress
}
}
} catch (_: Exception) { }
} catch (_: IOException) { }
return null
}
private fun resolve(host: String): String? = try {
......
......@@ -20,7 +20,6 @@
package com.github.shadowsocks.bg
import android.content.Context
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.preference.DataStore
......@@ -50,10 +49,10 @@ object LocalDnsService {
fun makeDns(name: String, address: String, timeout: Int, edns: Boolean = true): JSONObject {
val dns = JSONObject()
.put("Name", name)
.put("Address", (when (address.parseNumericAddress()) {
.put("Address", when (address.parseNumericAddress()) {
is Inet6Address -> "[$address]"
else -> address
}))
})
.put("Timeout", timeout)
.put("EDNSClientSubnet", JSONObject().put("Policy", "disable"))
if (edns) dns
......
......@@ -23,7 +23,6 @@ package com.github.shadowsocks.bg
import android.app.Service
import android.content.Intent
import android.os.IBinder
import com.github.shadowsocks.database.Profile
/**
* Shadowsocks service at its minimum.
......
......@@ -44,7 +44,7 @@ object TrafficMonitor {
private val units = arrayOf("KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB", "NB", "DB", "CB")
private val numberFormat = DecimalFormat("@@@")
fun formatTraffic(size: Long): String {
var n: Double = size.toDouble()
var n = size.toDouble()
var i = -1
while (n >= 999.5) {
n /= 1024
......
......@@ -38,7 +38,7 @@ class TrafficMonitorThread : LocalSocketListener("TrafficMonitorThread") {
val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN)
TrafficMonitor.update(stat.getLong(0), stat.getLong(8))
socket.outputStream.write(0)
} catch (e: Exception) {
} catch (e: IOException) {
Log.e(tag, "Error when recv traffic stat", e)
app.track(e)
}
......
......@@ -38,6 +38,7 @@ import com.github.shadowsocks.utils.Subnet
import com.github.shadowsocks.utils.parseNumericAddress
import java.io.File
import java.io.FileDescriptor
import java.io.IOException
import java.lang.reflect.Method
import java.util.*
import android.net.VpnService as BaseVpnService
......@@ -55,18 +56,24 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
override val socketFile: File = File(app.deviceContext.filesDir, "protect_path")
override fun accept(socket: LocalSocket) {
var success = false
try {
socket.inputStream.read()
val fds = socket.ancillaryFileDescriptors
if (fds.isEmpty()) return
val fd = getInt.invoke(fds.first()) as Int
val ret = protect(fd)
success = protect(fd)
JniHelper.close(fd) // Trick to close file decriptor
socket.outputStream.write(if (ret) 0 else 1)
} catch (e: Exception) {
Log.e(tag, "Error when protect socket", 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()
......@@ -118,7 +125,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
super.startNativeProcesses()
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> {
......
......@@ -72,10 +72,10 @@ object PrivateDatabase : OrmLiteSqliteOpenHelper(app, Key.DB_PROFILE, null, 25)
profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;")
TableUtils.createTable(connectionSource, Profile::class.java)
profileDao.executeRawNoArgs(
"INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," +
" udpdns, ipv6, individual) " +
"SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global, bypass, udpdns, ipv6," +
" individual FROM `tmp`;")
"INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route," +
" proxyApps, bypass, udpdns, ipv6, individual) " +
"SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global," +
" bypass, udpdns, ipv6, individual FROM `tmp`;")
profileDao.executeRawNoArgs("DROP TABLE `tmp`;")
profileDao.executeRawNoArgs("COMMIT;")
} else if (oldVersion < 13) {
......
......@@ -36,6 +36,7 @@ import java.util.*
class Profile : Serializable {
companion object {
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 userInfoPattern = "^(.+?):(.*)$".toRegex()
private val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)$".toRegex()
......
......@@ -25,14 +25,19 @@ import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.ProfilesFragment
import com.github.shadowsocks.preference.DataStore
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 {
private const val TAG = "ProfileManager"
@Throws(SQLException::class)
fun createProfile(p: Profile? = null): Profile {
val profile = p ?: Profile()
profile.id = 0
try {
val oldProfile = app.currentProfile
if (oldProfile != null) {
// Copy Feature Settings from old profile
......@@ -48,56 +53,41 @@ object ProfileManager {
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)
}
return profile
}
/**
* Note: It's caller's responsibility to update DirectBoot profile if necessary.
*/
fun updateProfile(profile: Profile): Boolean = try {
PrivateDatabase.profileDao.update(profile)
true
} catch (ex: Exception) {
Log.e(TAG, "updateProfile", ex)
app.track(ex)
false
}
@Throws(SQLException::class)
fun updateProfile(profile: Profile) = PrivateDatabase.profileDao.update(profile)
fun getProfile(id: Int): Profile? = try {
PrivateDatabase.profileDao.queryForId(id)
} catch (ex: Exception) {
} catch (ex: SQLException) {
Log.e(TAG, "getProfile", ex)
app.track(ex)
null
}
fun delProfile(id: Int): Boolean = try {
@Throws(SQLException::class)
fun delProfile(id: Int) {
PrivateDatabase.profileDao.deleteById(id)
ProfilesFragment.instance?.profilesAdapter?.removeId(id)
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 {
val result = PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().limit(1L).prepare())
if (result.size == 1) result[0] else null
} catch (ex: Exception) {
Log.e(TAG, "getAllProfiles", ex)
PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().limit(1L).prepare()).singleOrNull()
} catch (ex: SQLException) {
Log.e(TAG, "getFirstProfile", ex)
app.track(ex)
null
}
fun getAllProfiles(): List<Profile>? = try {
PrivateDatabase.profileDao.query(PrivateDatabase.profileDao.queryBuilder().orderBy("userOrder", true).prepare())
} catch (ex: Exception) {
} catch (ex: SQLException) {
Log.e(TAG, "getAllProfiles", ex)
app.track(ex)
null
......
......@@ -52,7 +52,7 @@ object DataStore {
/**
* 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
get() = publicStore.getString(Key.serviceMode) ?: Key.modeVpn
set(value) = publicStore.putString(Key.serviceMode, value)
......
......@@ -28,11 +28,7 @@ import android.util.AttributeSet
class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) {
var entryIcons: Array<Drawable?>? = null
val selectedEntry: Int get() = entryValues.indexOf(value)
val entryIcon: Drawable? get() = try {
entryIcons?.get(selectedEntry)
} catch (_: ArrayIndexOutOfBoundsException) {
null
}
val entryIcon: Drawable? get() = entryIcons?.getOrNull(selectedEntry)
// fun setEntryIcons(@ArrayRes entryIconsResId: Int) {
// val array = getContext().getResources().obtainTypedArray(entryIconsResId)
// entryIcons = Array(array.length(), { i -> array.getDrawable(i) })
......@@ -49,7 +45,7 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
}
init {
super.setOnPreferenceChangeListener({ preference, newValue ->
super.setOnPreferenceChangeListener { preference, newValue ->
val listener = listener
if (listener == null || listener.onPreferenceChange(preference, newValue)) {
value = newValue.toString()
......@@ -57,7 +53,7 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
if (entryIcons != null) icon = entryIcon
true
} else false
})
}
// val a = context.obtainStyledAttributes(attrs, R.styleable.IconListPreference)
// val entryIconsResId: Int = a.getResourceId(R.styleable.IconListPreference_entryIcons, -1)
// if (entryIconsResId != -1) entryIcons = entryIconsResId
......
......@@ -85,12 +85,12 @@ class ConfigActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
taskerOption = Settings.fromIntent(intent!!)
} catch (_: Exception) {
val intent = intent
if (intent == null) {
finish()
return
}
taskerOption = Settings.fromIntent(intent)
setContentView(R.layout.layout_tasker)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
......
......@@ -44,8 +44,8 @@ class Settings(bundle: Bundle?) {
if (profileId >= 0) bundle.putInt(KEY_PROFILE_ID, profileId)
val profile = ProfileManager.getProfile(profileId)
return Intent().putExtra(ApiIntent.EXTRA_BUNDLE, bundle).putExtra(ApiIntent.EXTRA_STRING_BLURB,
if (profile != null)
context.getString(if (switchOn) R.string.start_service else R.string.stop_service, profile.formattedName)
if (profile != null) context.getString(if (switchOn) R.string.start_service else R.string.stop_service,
profile.formattedName)
else context.getString(if (switchOn) R.string.start_service_default else R.string.stop))
}
}
......@@ -20,9 +20,7 @@
package com.github.shadowsocks.utils
import java.util.ArrayList
import java.util.Arrays
import java.util.StringTokenizer
import java.util.*
/**
* Commandline objects help handling command lines specifying processes to
......@@ -86,9 +84,7 @@ object Commandline {
* @return empty string for null or no command, else every argument split
* by spaces and quoted by quoting rules.
*/
fun toString(args: Array<String>): String {
return toString(Arrays.asList(*args)) // thanks to Java, arrays aren't iterable
}
fun toString(args: Array<String>) = toString(args.asIterable()) // thanks to Java, arrays aren't iterable
/**
* Crack a command line.
......
......@@ -7,7 +7,7 @@ import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.preference.DataStore
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
......@@ -17,7 +17,7 @@ object DirectBoot {
fun getDeviceProfile(): Profile? = try {
ObjectInputStream(file.inputStream()).use { it.readObject() as Profile }
} catch (_: FileNotFoundException) { null }
} catch (_: IOException) { null }
fun clean() {
file.delete()
......
......@@ -28,8 +28,8 @@ fun String.parseNumericAddress(): InetAddress? {
}
fun parsePort(str: String?, default: Int, min: Int = 1025): Int {
val x = str?.toIntOrNull() ?: default
return if (x < min || x > 65535) default else x
val value = str?.toIntOrNull() ?: default
return if (value < min || value > 65535) default else value
}
fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver = object : BroadcastReceiver() {
......@@ -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 var count = 0
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)
......@@ -29,7 +29,6 @@ import android.support.graphics.drawable.AnimatedVectorDrawableCompat
import android.support.v7.widget.TooltipCompat
import android.util.AttributeSet
import android.view.View
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R
import com.github.shadowsocks.bg.BaseService
import java.util.*
......
......@@ -70,8 +70,8 @@ abstract class NativePluginProvider : ContentProvider() {
/**
* 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
* behavior.
* Default behavior is throwing UnsupportedOperationException. If you don't wish to use this feature, use the
* default behavior.
*
* @return Absolute path for executable entry.
*/
......
......@@ -29,14 +29,12 @@ import android.widget.Toast
* Activity that's capable of getting EXTRA_OPTIONS input.
*/
abstract class OptionsCapableActivity : AppCompatActivity() {
protected fun pluginOptions(intent: Intent = this.intent): PluginOptions {
return try {
protected fun pluginOptions(intent: Intent = this.intent) = try {
PluginOptions(intent.getStringExtra(PluginContract.EXTRA_OPTIONS))
} catch (exc: IllegalArgumentException) {
Toast.makeText(this, exc.message, Toast.LENGTH_SHORT).show()
PluginOptions()
}
}
/**
* Populate args to your user interface.
......
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