diff --git a/mobile/src/main/java/com/github/shadowsocks/AppManager.kt b/mobile/src/main/java/com/github/shadowsocks/AppManager.kt index 62b4a358..67c5c7c0 100644 --- a/mobile/src/main/java/com/github/shadowsocks/AppManager.kt +++ b/mobile/src/main/java/com/github/shadowsocks/AppManager.kt @@ -110,13 +110,17 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener { } private inner class AppsAdapter : RecyclerView.Adapter(), SectionTitleProvider { - private val apps = getApps(packageManager).sortedWith(Comparator { a, b -> - when (Pair(proxiedApps.contains(a.packageName), proxiedApps.contains(b.packageName))) { - Pair(true, false) -> -1 - Pair(false, true) -> 1 - else -> a.name.compareTo(b.name, true) - } - }) + private var apps = listOf() + + fun reload() { + apps = getApps(packageManager).sortedWith(Comparator { a, b -> + when (Pair(proxiedApps.contains(a.packageName), proxiedApps.contains(b.packageName))) { + Pair(true, false) -> -1 + Pair(false, true) -> 1 + else -> a.name.compareTo(b.name, true) + } + }) + } override fun onBindViewHolder(holder: AppViewHolder, position: Int) = holder.bind(apps[position]) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder = @@ -143,15 +147,17 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener { } private fun loadAppsAsync() { if (!appsLoading.compareAndSet(false, true)) return + appListView.visibility = View.GONE + fastScroller.visibility = View.GONE + loadingView.visibility = View.VISIBLE thread { - var adapter: AppsAdapter? + val adapter = appListView.adapter as AppsAdapter do { appsLoading.set(true) - adapter = AppsAdapter() + adapter.reload() } while (!appsLoading.compareAndSet(true, false)) handler.post { - appListView.adapter = adapter - fastScroller.setRecyclerView(appListView) + adapter.notifyDataSetChanged() val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime) appListView.alpha = 0F appListView.visibility = View.VISIBLE @@ -204,7 +210,9 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener { appListView = findViewById(R.id.list) appListView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) appListView.itemAnimator = DefaultItemAnimator() + appListView.adapter = AppsAdapter() fastScroller = findViewById(R.id.fastscroller) + fastScroller.setRecyclerView(appListView) instance = this loadAppsAsync() @@ -241,9 +249,6 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener { DataStore.individual = apps DataStore.dirty = true Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show() - appListView.visibility = View.GONE - fastScroller.visibility = View.GONE - loadingView.visibility = View.VISIBLE initProxiedApps(apps) reloadApps() return true diff --git a/mobile/src/main/java/com/github/shadowsocks/ShadowsocksConnection.kt b/mobile/src/main/java/com/github/shadowsocks/ShadowsocksConnection.kt index 25a483ef..96fdb8bb 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ShadowsocksConnection.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ShadowsocksConnection.kt @@ -26,7 +26,6 @@ import android.content.Intent import android.content.ServiceConnection import android.os.IBinder import android.os.RemoteException -import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.aidl.IShadowsocksService import com.github.shadowsocks.aidl.IShadowsocksServiceCallback import com.github.shadowsocks.bg.BaseService diff --git a/mobile/src/main/java/com/github/shadowsocks/ToolbarFragment.kt b/mobile/src/main/java/com/github/shadowsocks/ToolbarFragment.kt index b72f0fd0..9238d776 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ToolbarFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ToolbarFragment.kt @@ -33,7 +33,7 @@ open class ToolbarFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - toolbar = view.findViewById(R.id.toolbar) + toolbar = view.findViewById(R.id.toolbar) val activity = activity as MainActivity if (activity.crossfader == null) activity.drawer.setToolbar(activity, toolbar, true) } diff --git a/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt b/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt index a8d3488a..0bd9cb48 100644 --- a/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt @@ -48,6 +48,7 @@ import com.github.shadowsocks.ToolbarFragment import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.utils.Subnet import com.github.shadowsocks.utils.asIterable +import com.github.shadowsocks.utils.dp import com.github.shadowsocks.widget.UndoSnackbarManager import java.net.IDN import java.net.URL @@ -76,6 +77,8 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { private val text = view.findViewById(android.R.id.text1) init { + view.setPaddingRelative(view.paddingStart, view.paddingTop, + Math.max(view.paddingEnd, 20f.dp().toInt()), view.paddingBottom) view.setOnClickListener(this) view.setOnLongClickListener(this) view.setBackgroundResource(R.drawable.background_selectable) diff --git a/mobile/src/main/java/com/github/shadowsocks/bg/Executable.kt b/mobile/src/main/java/com/github/shadowsocks/bg/Executable.kt index db3ab18f..2d001d47 100644 --- a/mobile/src/main/java/com/github/shadowsocks/bg/Executable.kt +++ b/mobile/src/main/java/com/github/shadowsocks/bg/Executable.kt @@ -28,13 +28,12 @@ import java.io.File object Executable { const val REDSOCKS = "libredsocks.so" - const val PDNSD = "libpdnsd.so" const val SS_LOCAL = "libss-local.so" const val SS_TUNNEL = "libss-tunnel.so" const val TUN2SOCKS = "libtun2socks.so" const val OVERTURE = "liboverture.so" - val EXECUTABLES = setOf(SS_LOCAL, SS_TUNNEL, PDNSD, REDSOCKS, TUN2SOCKS, OVERTURE) + val EXECUTABLES = setOf(SS_LOCAL, SS_TUNNEL, REDSOCKS, TUN2SOCKS, OVERTURE) fun killAll() { for (process in File("/proc").listFiles { _, name -> TextUtils.isDigitsOnly(name) }) { diff --git a/mobile/src/main/java/com/github/shadowsocks/bg/ServiceNotification.kt b/mobile/src/main/java/com/github/shadowsocks/bg/ServiceNotification.kt index c8c064aa..3338c115 100644 --- a/mobile/src/main/java/com/github/shadowsocks/bg/ServiceNotification.kt +++ b/mobile/src/main/java/com/github/shadowsocks/bg/ServiceNotification.kt @@ -69,7 +69,7 @@ class ServiceNotification(private val service: BaseService.Interface, profileNam .setContentTitle(profileName) .setContentIntent(PendingIntent.getActivity(service, 0, Intent(service, MainActivity::class.java) .setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0)) - .setSmallIcon(R.drawable.ic_stat_shadowsocks) + .setSmallIcon(R.drawable.ic_start_connected) private val style = NotificationCompat.BigTextStyle(builder) private var isVisible = true diff --git a/mobile/src/main/java/com/github/shadowsocks/bg/TrafficMonitor.kt b/mobile/src/main/java/com/github/shadowsocks/bg/TrafficMonitor.kt index 0e0653e6..e04dd3e8 100644 --- a/mobile/src/main/java/com/github/shadowsocks/bg/TrafficMonitor.kt +++ b/mobile/src/main/java/com/github/shadowsocks/bg/TrafficMonitor.kt @@ -35,11 +35,11 @@ object TrafficMonitor { var rxTotal = 0L // Bytes for the last query - var txLast = 0L - var rxLast = 0L - var timestampLast = 0L + private var txLast = 0L + private var rxLast = 0L + private var timestampLast = 0L @Volatile - var dirty = true + private var dirty = true private val units = arrayOf("KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB", "NB", "DB", "CB") private val numberFormat = DecimalFormat("@@@") diff --git a/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt b/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt index f5d00745..aa222a1f 100644 --- a/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt +++ b/mobile/src/main/java/com/github/shadowsocks/database/ProfileManager.kt @@ -25,7 +25,7 @@ import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.ProfilesFragment object ProfileManager { - const val TAG = "ProfileManager" + private const val TAG = "ProfileManager" fun createProfile(p: Profile? = null): Profile { val profile = p ?: Profile() diff --git a/mobile/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt b/mobile/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt index dc234213..0e82a551 100644 --- a/mobile/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt +++ b/mobile/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt @@ -21,12 +21,13 @@ package com.github.shadowsocks.plugin import android.content.pm.ResolveInfo +import android.os.Bundle class NativePlugin(resolveInfo: ResolveInfo) : ResolvedPlugin(resolveInfo) { init { assert(resolveInfo.providerInfo != null) } - override val metaData get() = resolveInfo.providerInfo.metaData - override val packageName get() = resolveInfo.providerInfo.packageName + override val metaData: Bundle get() = resolveInfo.providerInfo.metaData + override val packageName: String get() = resolveInfo.providerInfo.packageName } diff --git a/mobile/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt b/mobile/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt index 6c4a6a9f..cfc41865 100644 --- a/mobile/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt +++ b/mobile/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt @@ -36,9 +36,11 @@ class PluginConfiguration(val pluginsOptions: Map, val se val iterator = Commandline.translateCommandline(line).drop(1).iterator() while (iterator.hasNext()) { val option = iterator.next() - if (option == "--nocomp") opt.put("nocomp", null) - else if (option.startsWith("--")) opt.put(option.substring(2), iterator.next()) - else throw IllegalArgumentException("Unknown kcptun parameter: " + option) + when { + option == "--nocomp" -> opt.put("nocomp", null) + option.startsWith("--") -> opt.put(option.substring(2), iterator.next()) + else -> throw IllegalArgumentException("Unknown kcptun parameter: " + option) + } } } catch (exc: Exception) { Log.w("PluginConfiguration", exc.message) @@ -55,6 +57,6 @@ class PluginConfiguration(val pluginsOptions: Map, val se val result = LinkedList() for ((id, opt) in pluginsOptions) if (id == this.selected) result.addFirst(opt) else result.addLast(opt) if (!pluginsOptions.contains(selected)) result.addFirst(selectedOptions) - return result.map { it.toString(false) }.joinToString("\n") + return result.joinToString("\n") { it.toString(false) } } } diff --git a/mobile/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt b/mobile/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt index bc0a6617..faa042b1 100644 --- a/mobile/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt +++ b/mobile/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt @@ -28,10 +28,10 @@ import com.github.shadowsocks.App.Companion.app abstract class ResolvedPlugin(protected val resolveInfo: ResolveInfo) : Plugin() { protected abstract val metaData: Bundle - override val id by lazy { metaData.getString(PluginContract.METADATA_KEY_ID) } - override val label by lazy { resolveInfo.loadLabel(app.packageManager) } - override val icon by lazy { resolveInfo.loadIcon(app.packageManager) } - override val defaultConfig by lazy { metaData.getString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) } - override val packageName get() = resolveInfo.resolvePackageName + override val id: String by lazy { metaData.getString(PluginContract.METADATA_KEY_ID) } + override val label: CharSequence by lazy { resolveInfo.loadLabel(app.packageManager) } + override val icon: Drawable by lazy { resolveInfo.loadIcon(app.packageManager) } + override val defaultConfig: String by lazy { metaData.getString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) } + override val packageName: String get() = resolveInfo.resolvePackageName override val trusted by lazy { app.info.signatures.any(PluginManager.trustedSignatures::contains) } } diff --git a/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt b/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt index b8ad0d65..ec35ec0f 100644 --- a/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt +++ b/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt @@ -28,6 +28,7 @@ import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.parsePort import java.util.* +@Suppress("MemberVisibilityCanPrivate", "unused") object DataStore : PreferenceDataStore() { fun getBoolean(key: String?) = DBHelper.kvPairDao.queryForId(key)?.boolean fun getFloat(key: String?) = DBHelper.kvPairDao.queryForId(key)?.float diff --git a/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt b/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt index c4036568..f1df51f2 100644 --- a/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt +++ b/mobile/src/main/java/com/github/shadowsocks/preference/IconListPreference.kt @@ -22,7 +22,6 @@ package com.github.shadowsocks.preference import android.content.Context import android.graphics.drawable.Drawable -import android.preference.Preference.OnPreferenceChangeListener import android.support.v7.preference.ListPreference import android.util.AttributeSet @@ -43,19 +42,19 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr var unknownValueSummary: String? = null var entryPackageNames: Array? = null - var listener: OnPreferenceChangeListener? = null + private var listener: OnPreferenceChangeListener? = null override fun getOnPreferenceChangeListener(): OnPreferenceChangeListener? = listener override fun setOnPreferenceChangeListener(listener: OnPreferenceChangeListener?) { this.listener = listener } init { - super.setOnPreferenceChangeListener(OnPreferenceChangeListener { preference, newValue -> + super.setOnPreferenceChangeListener({ preference, newValue -> val listener = listener if (listener == null || listener.onPreferenceChange(preference, newValue)) { - setValue(newValue.toString()) + value = newValue.toString() checkSummary() - if (entryIcons != null) setIcon(entryIcon) + if (entryIcons != null) icon = entryIcon true } else false }) @@ -70,7 +69,9 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr if (unknownValueSummary != null) summary = if (selectedEntry < 0) unknownValueSummary.format(value) else "%s" } - fun init() = setIcon(entryIcon) + fun init() { + icon = entryIcon + } override fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) { super.onSetInitialValue(restoreValue, defaultValue) init() diff --git a/mobile/src/main/java/com/github/shadowsocks/utils/Utils.kt b/mobile/src/main/java/com/github/shadowsocks/utils/Utils.kt index 4b5decbc..a3410711 100644 --- a/mobile/src/main/java/com/github/shadowsocks/utils/Utils.kt +++ b/mobile/src/main/java/com/github/shadowsocks/utils/Utils.kt @@ -9,6 +9,7 @@ import android.support.v4.app.Fragment import android.support.v4.app.FragmentManager import android.support.v7.util.SortedList import android.util.DisplayMetrics +import android.util.TypedValue import android.view.Gravity import android.view.View import android.view.Window @@ -77,6 +78,8 @@ fun Toast.position(view: View, window: Window, offsetX: Int = 0, offsetY: Int = return this } +fun Float.dp(): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, app.resources.displayMetrics) + /** * Based on: https://stackoverflow.com/a/15656428/2245107 */ diff --git a/mobile/src/main/java/com/github/shadowsocks/widget/UndoSnackbarManager.kt b/mobile/src/main/java/com/github/shadowsocks/widget/UndoSnackbarManager.kt index 98bf8c99..993b90f5 100644 --- a/mobile/src/main/java/com/github/shadowsocks/widget/UndoSnackbarManager.kt +++ b/mobile/src/main/java/com/github/shadowsocks/widget/UndoSnackbarManager.kt @@ -30,8 +30,8 @@ import com.github.shadowsocks.R * @param commit Callback for committing removals. * @tparam T Item type. */ -class UndoSnackbarManager(private val view: View, private val undo: (List>) -> Unit, - commit: ((List>) -> Unit)? = null) { +class UndoSnackbarManager(private val view: View, private val undo: (List>) -> Unit, + commit: ((List>) -> Unit)? = null) { private val recycleBin = ArrayList>() private val removedCallback = object : Snackbar.Callback() { override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { diff --git a/mobile/src/main/res/drawable-hdpi/ic_stat_shadowsocks.png b/mobile/src/main/res/drawable-hdpi/ic_start_connected.png similarity index 100% rename from mobile/src/main/res/drawable-hdpi/ic_stat_shadowsocks.png rename to mobile/src/main/res/drawable-hdpi/ic_start_connected.png diff --git a/mobile/src/main/res/drawable-mdpi/ic_stat_shadowsocks.png b/mobile/src/main/res/drawable-mdpi/ic_start_connected.png similarity index 100% rename from mobile/src/main/res/drawable-mdpi/ic_stat_shadowsocks.png rename to mobile/src/main/res/drawable-mdpi/ic_start_connected.png diff --git a/mobile/src/main/res/drawable-v21/background_profile.xml b/mobile/src/main/res/drawable-v21/background_profile.xml index d6fb147a..3509fa32 100644 --- a/mobile/src/main/res/drawable-v21/background_profile.xml +++ b/mobile/src/main/res/drawable-v21/background_profile.xml @@ -15,6 +15,7 @@ + diff --git a/mobile/src/main/res/drawable-xhdpi/ic_stat_shadowsocks.png b/mobile/src/main/res/drawable-xhdpi/ic_start_connected.png similarity index 100% rename from mobile/src/main/res/drawable-xhdpi/ic_stat_shadowsocks.png rename to mobile/src/main/res/drawable-xhdpi/ic_start_connected.png diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_stat_shadowsocks.png b/mobile/src/main/res/drawable-xxhdpi/ic_start_connected.png similarity index 100% rename from mobile/src/main/res/drawable-xxhdpi/ic_stat_shadowsocks.png rename to mobile/src/main/res/drawable-xxhdpi/ic_start_connected.png diff --git a/mobile/src/main/res/drawable/ic_action_assignment.xml b/mobile/src/main/res/drawable/ic_action_assignment.xml index 4a3eb4fe..9706a6ca 100644 --- a/mobile/src/main/res/drawable/ic_action_assignment.xml +++ b/mobile/src/main/res/drawable/ic_action_assignment.xml @@ -1,6 +1,7 @@ - - diff --git a/mobile/src/main/res/drawable/ic_content_paste.xml b/mobile/src/main/res/drawable/ic_content_paste.xml deleted file mode 100644 index 7d2f624c..00000000 --- a/mobile/src/main/res/drawable/ic_content_paste.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/mobile/src/main/res/drawable/ic_social_share.xml b/mobile/src/main/res/drawable/ic_social_share.xml index e3fe874d..1a9c8292 100644 --- a/mobile/src/main/res/drawable/ic_social_share.xml +++ b/mobile/src/main/res/drawable/ic_social_share.xml @@ -1,6 +1,7 @@ - - + + + + + tools:listitem="@layout/layout_apps_item"/> diff --git a/mobile/src/main/res/layout/layout_apps_item.xml b/mobile/src/main/res/layout/layout_apps_item.xml index 21870bb3..04fa1f7f 100644 --- a/mobile/src/main/res/layout/layout_apps_item.xml +++ b/mobile/src/main/res/layout/layout_apps_item.xml @@ -9,25 +9,25 @@ + android:paddingStart="8dp" + android:paddingTop="4dp" + android:scaleType="fitCenter"/> + android:gravity="center_vertical" + android:textColor="?android:attr/textColorSecondary" + android:textSize="18sp"/> diff --git a/mobile/src/main/res/layout/layout_custom_rules.xml b/mobile/src/main/res/layout/layout_custom_rules.xml index 510e9dba..77a40337 100644 --- a/mobile/src/main/res/layout/layout_custom_rules.xml +++ b/mobile/src/main/res/layout/layout_custom_rules.xml @@ -1,6 +1,7 @@ @@ -12,6 +13,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="32dp" + tools:listitem="@android:layout/simple_list_item_1" android:clipToPadding="false"/> @@ -18,5 +19,6 @@ diff --git a/mobile/src/main/res/menu/app_manager_menu.xml b/mobile/src/main/res/menu/app_manager_menu.xml index a58af6ca..83b6eef2 100644 --- a/mobile/src/main/res/menu/app_manager_menu.xml +++ b/mobile/src/main/res/menu/app_manager_menu.xml @@ -1,20 +1,23 @@ - - - + + diff --git a/mobile/src/main/res/menu/profile_manager_menu.xml b/mobile/src/main/res/menu/profile_manager_menu.xml index e0b6f003..2e7d2a11 100644 --- a/mobile/src/main/res/menu/profile_manager_menu.xml +++ b/mobile/src/main/res/menu/profile_manager_menu.xml @@ -1,30 +1,35 @@ - + - - - + + + - +