package com.github.shadowsocks.utils import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.res.Resources import android.os.Build import android.support.annotation.AttrRes import android.support.v4.app.Fragment import android.support.v4.app.FragmentManager import android.support.v7.util.SortedList import android.util.TypedValue import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.JniHelper import java.net.InetAddress import java.net.URLConnection private val fieldChildFragmentManager by lazy { val field = Fragment::class.java.getDeclaredField("mChildFragmentManager") field.isAccessible = true field } fun String.isNumericAddress() = JniHelper.parseNumericAddress(this) != null fun String.parseNumericAddress(): InetAddress? { val addr = JniHelper.parseNumericAddress(this) return if (addr == null) null else InetAddress.getByAddress(this, addr) } fun parsePort(str: String?, default: Int, min: Int = 1025): Int { val value = str?.toIntOrNull() ?: default return if (value < min || value > 65535) default else value } fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) = callback(context, intent) } /** * Wrapper for kotlin.concurrent.thread that tracks uncaught exceptions. */ fun thread(start: Boolean = true, isDaemon: Boolean = false, contextClassLoader: ClassLoader? = null, name: String? = null, priority: Int = -1, block: () -> Unit): Thread { val thread = kotlin.concurrent.thread(false, isDaemon, contextClassLoader, name, priority, block) thread.setUncaughtExceptionHandler(app::track) if (start) thread.start() return thread } val URLConnection.responseLength: Long get() = if (Build.VERSION.SDK_INT >= 24) contentLengthLong else contentLength.toLong() /** * Based on: https://stackoverflow.com/a/15656428/2245107 */ var Fragment.childFragManager: FragmentManager? get() = childFragmentManager set(value) = fieldChildFragmentManager.set(this, value) /** * Based on: https://stackoverflow.com/a/26348729/2245107 */ fun Resources.Theme.resolveResourceId(@AttrRes resId: Int): Int { val typedValue = TypedValue() if (!resolveAttribute(resId, typedValue, true)) throw Resources.NotFoundException() return typedValue.resourceId } private class SortedListIterable(private val list: SortedList) : Iterable { override fun iterator(): Iterator = SortedListIterator(list) } private class SortedListIterator(private val list: SortedList) : Iterator { private var count = 0 override fun hasNext() = count < list.size() override fun next(): T = if (hasNext()) list[count++] else throw NoSuchElementException() } fun SortedList.asIterable(): Iterable = SortedListIterable(this)