Unverified Commit f053a62f authored by Mygod's avatar Mygod Committed by GitHub

Migrate to Android X (#1881)

* Initial draft for porting to Android X

* Use Android KTX

* Fix wrong constants

* Fix code style

* Migrate to NavigationView

* Fix deprecation

* Update dependencies
parent ff0cd960
......@@ -9,13 +9,12 @@ buildscript {
sdkVersion = 28
compileSdkVersion = 28
buildToolsVersion = '28.0.1'
supportLibraryVersion = '28.0.0-alpha3'
takisoftFixVersion = '27.1.1.2'
androidxVersion = '1.0.0-beta01'
roomVersion = '1.1.1'
workVersion = '1.0.0-alpha04'
junitVersion = '4.12'
androidTestVersion = '1.0.2'
androidEspressoVersion = '3.0.2'
androidTestVersion = '1.1.0-alpha3'
androidEspressoVersion = '3.1.0-alpha3'
}
repositories {
......@@ -29,7 +28,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-beta03'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0'
classpath 'com.google.gms:google-services:4.0.1'
classpath 'com.google.gms:google-services:4.0.2'
classpath 'io.fabric.tools:gradle:1.25.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
......
......@@ -12,7 +12,7 @@ android {
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
ndkBuild {
......@@ -65,6 +65,6 @@ tasks.whenTaskAdded { task ->
dependencies {
api project(':plugin')
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "com.android.support.test:runner:$androidTestVersion"
androidTestImplementation "com.android.support.test.espresso:espresso-core:$androidEspressoVersion"
androidTestImplementation "androidx.test:runner:$androidTestVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidEspressoVersion"
}
package com.github.shadowsocks;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
......
......@@ -39,8 +39,8 @@
package com.github.shadowsocks;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.system.ErrnoException;
public class JniHelper {
......
......@@ -9,6 +9,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
......
......@@ -26,7 +26,7 @@ android {
versionCode 4060100
versionName "4.6.1"
testApplicationId "com.github.shadowsocks.test"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "fa", "fr", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
javaCompileOptions {
annotationProcessorOptions {
......@@ -61,32 +61,28 @@ android {
dependencies {
implementation project(':core')
implementation "android.arch.persistence.room:runtime:$roomVersion"
implementation "android.arch.work:work-runtime-ktx:$workVersion"
implementation "com.android.support:customtabs:$supportLibraryVersion"
implementation "com.android.support:design:$supportLibraryVersion"
implementation "com.android.support:gridlayout-v7:$supportLibraryVersion"
implementation "com.android.support:support-v4:$supportLibraryVersion"
implementation "androidx.browser:browser:$androidxVersion"
implementation "androidx.gridlayout:gridlayout:$androidxVersion"
implementation 'androidx.room:room-runtime:2.0.0-beta01'
implementation "com.google.android.material:material:$androidxVersion"
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.4'
implementation 'com.futuremind.recyclerfastscroll:fastscroll:0.2.5'
implementation 'com.google.android.gms:play-services-vision:15.0.2'
implementation 'com.google.firebase:firebase-ads:15.0.1'
implementation 'com.google.firebase:firebase-config:16.0.0'
implementation 'com.google.firebase:firebase-core:16.0.0'
implementation 'com.mikepenz:materialdrawer:6.0.8'
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
implementation "com.takisoft.fix:preference-v7-simplemenu:$takisoftFixVersion"
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.takisoft.preferencex:preferencex-simplemenu:1.0.0-alpha1'
implementation 'com.twofortyfouram:android-plugin-api-for-locale:1.0.2'
implementation 'eu.chainfire:libsuperuser:1.0.0.201704021214'
implementation 'net.glxn.qrgen:android:2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation 'xyz.belvi.mobilevision:barcodescanner:2.0.3'
kapt "android.arch.persistence.room:compiler:$roomVersion"
testImplementation "android.arch.persistence.room:testing:$roomVersion"
kapt 'androidx.room:room-compiler:2.0.0-beta01'
testImplementation 'androidx.room:room-testing:2.0.0-beta01'
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "android.arch.work:work-testing:$workVersion"
androidTestImplementation "com.android.support.test:runner:$androidTestVersion"
androidTestImplementation "com.android.support.test.espresso:espresso-core:$androidEspressoVersion"
androidTestImplementation "androidx.test:runner:$androidTestVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidEspressoVersion"
}
repositories {
mavenCentral()
......
......@@ -20,7 +20,7 @@
package com.github.shadowsocks.database
import android.net.Uri
import androidx.core.net.toUri
import org.junit.Assert
import org.junit.Test
......@@ -30,7 +30,7 @@ class ProfileTest {
val results = Profile.findAll("garble ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server garble")
.toList()
Assert.assertEquals(1, results.size)
Assert.assertEquals(Uri.parse("ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server"),
Assert.assertEquals("ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server".toUri(),
results.single().toUri())
}
}
......@@ -26,11 +26,9 @@
android:fullBackupContent="@xml/backup_descriptor"
android:fullBackupOnly="true"
android:label="@string/app_name"
android:theme="@style/Theme.Shadowsocks.App"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:banner="@drawable/ic_service_active"
tools:replace="android:theme">
android:banner="@drawable/ic_service_active">
<meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
android:value="true" />
......
/*******************************************************************************
* *
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package android.support.design.animation
import android.animation.TimeInterpolator
object AnimationConsts {
val FAST_OUT_SLOW_IN_INTERPOLATOR: TimeInterpolator get() = AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR
}
......@@ -21,9 +21,7 @@
package com.github.shadowsocks
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.support.v4.text.HtmlCompat
import android.text.SpannableStringBuilder
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
......@@ -32,6 +30,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.net.toUri
import androidx.core.text.HtmlCompat
import androidx.core.text.parseAsHtml
class AboutFragment : ToolbarFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
......@@ -41,16 +42,15 @@ class AboutFragment : ToolbarFragment() {
super.onViewCreated(view, savedInstanceState)
toolbar.title = getString(R.string.about_title, BuildConfig.VERSION_NAME)
view.findViewById<TextView>(R.id.tv_about).apply {
text = SpannableStringBuilder(HtmlCompat.fromHtml(
resources.openRawResource(R.raw.about).bufferedReader().readText(),
HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM)).apply {
text = SpannableStringBuilder(resources.openRawResource(R.raw.about).bufferedReader().readText()
.parseAsHtml(HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM)).apply {
for (span in getSpans(0, length, URLSpan::class.java)) {
setSpan(object : ClickableSpan() {
override fun onClick(view: View) {
if (span.url.startsWith("mailto:")) {
startActivity(Intent.createChooser(Intent().apply {
action = Intent.ACTION_SENDTO
data = Uri.parse(span.url)
data = span.url.toUri()
}, getString(R.string.send_email)))
} else (activity as MainActivity).launchUrl(span.url)
}
......
......@@ -35,9 +35,10 @@ import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.UserManager
import android.support.annotation.RequiresApi
import android.support.v7.app.AppCompatDelegate
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatDelegate
import android.util.Log
import androidx.core.content.getSystemService
import androidx.work.WorkManager
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.acl.Acl
......@@ -51,7 +52,7 @@ import com.github.shadowsocks.utils.*
import com.google.firebase.FirebaseApp
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.PreferenceFragmentCompat
import io.fabric.sdk.android.Fabric
import java.io.File
import java.io.IOException
......@@ -68,8 +69,8 @@ class App : Application() {
val analytics: FirebaseAnalytics by lazy { FirebaseAnalytics.getInstance(deviceContext) }
val info: PackageInfo by lazy { getPackageInfo(packageName) }
val directBootSupported by lazy {
Build.VERSION.SDK_INT >= 24 && getSystemService(DevicePolicyManager::class.java)
.storageEncryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER
Build.VERSION.SDK_INT >= 24 && getSystemService<DevicePolicyManager>()?.storageEncryptionStatus ==
DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER
}
fun getPackageInfo(packageName: String) = packageManager.getPackageInfo(packageName,
......@@ -121,7 +122,7 @@ class App : Application() {
// handle data restored/crash
if (Build.VERSION.SDK_INT >= 24 && DataStore.directBootAware &&
(getSystemService(Context.USER_SERVICE) as UserManager).isUserUnlocked) DirectBoot.flushTrafficStats()
getSystemService<UserManager>()?.isUserUnlocked == true) DirectBoot.flushTrafficStats()
TcpFastOpen.enabledAsync(DataStore.publicStore.getBoolean(Key.tfo, TcpFastOpen.sendEnabled))
if (DataStore.publicStore.getLong(Key.assetUpdateTime, -1) != info.lastUpdateTime) {
val assetManager = assets
......@@ -146,7 +147,7 @@ class App : Application() {
private fun updateNotificationChannels() {
if (Build.VERSION.SDK_INT >= 26) @RequiresApi(26) {
val nm = getSystemService(NotificationManager::class.java)
val nm = getSystemService<NotificationManager>()!!
nm.createNotificationChannels(listOf(
NotificationChannel("service-vpn", getText(R.string.service_vpn),
NotificationManager.IMPORTANCE_LOW),
......
......@@ -33,18 +33,17 @@ import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
import android.support.design.widget.Snackbar
import android.support.v4.app.TaskStackBuilder
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import com.google.android.material.snackbar.Snackbar
import androidx.core.app.TaskStackBuilder
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.appcompat.widget.Toolbar
import android.view.*
import android.widget.ImageView
import android.widget.Switch
import com.futuremind.recyclerviewfastscroll.FastScroller
import com.futuremind.recyclerviewfastscroll.SectionTitleProvider
import androidx.core.content.getSystemService
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.preference.DataStore
......@@ -113,7 +112,7 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
}
}
private inner class AppsAdapter : RecyclerView.Adapter<AppViewHolder>(), SectionTitleProvider {
private inner class AppsAdapter : RecyclerView.Adapter<AppViewHolder>() {
private var apps = listOf<ProxiedApp>()
fun reload() {
......@@ -125,18 +124,16 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder =
AppViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_apps_item, parent, false))
override fun getItemCount(): Int = apps.size
override fun getSectionTitle(position: Int): String = apps[position].name.substring(0, 1)
}
private lateinit var proxiedApps: HashSet<String>
private lateinit var toolbar: Toolbar
private lateinit var bypassSwitch: Switch
private lateinit var appListView: RecyclerView
private lateinit var fastScroller: FastScroller
private lateinit var loadingView: View
private val appsLoading = AtomicBoolean()
private val handler = Handler()
private val clipboard by lazy { systemService<ClipboardManager>() }
private val clipboard by lazy { getSystemService<ClipboardManager>()!! }
private fun initProxiedApps(str: String = DataStore.individual) {
proxiedApps = str.split('\n').toHashSet()
......@@ -147,7 +144,6 @@ 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("AppManager-loader") {
val adapter = appListView.adapter as AppsAdapter
......@@ -161,9 +157,6 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
appListView.alpha = 0F
appListView.visibility = View.VISIBLE
appListView.animate().alpha(1F).duration = shortAnimTime.toLong()
fastScroller.alpha = 0F
fastScroller.visibility = View.VISIBLE
fastScroller.animate().alpha(1F).duration = shortAnimTime.toLong()
loadingView.animate().alpha(0F).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
loadingView.visibility = View.GONE
......@@ -207,11 +200,9 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
initProxiedApps()
loadingView = findViewById(R.id.loading)
appListView = findViewById(R.id.list)
appListView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
appListView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
appListView.itemAnimator = DefaultItemAnimator()
appListView.adapter = AppsAdapter()
fastScroller = findViewById(R.id.fastscroller)
fastScroller.setRecyclerView(appListView)
instance = this
loadAppsAsync()
......
......@@ -22,21 +22,20 @@ package com.github.shadowsocks
import android.os.Build
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v14.preference.SwitchPreference
import android.support.v7.preference.Preference
import com.google.android.material.snackbar.Snackbar
import androidx.preference.SwitchPreference
import androidx.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
import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.TcpFastOpen
import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.PreferenceFragmentCompat
class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = DataStore.publicStore
DataStore.initGlobal()
addPreferencesFromResource(R.xml.pref_global)
val boot = findPreference(Key.isAutoConnect) as SwitchPreference
boot.setOnPreferenceChangeListener { _, value ->
......
......@@ -23,9 +23,9 @@ package com.github.shadowsocks
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.github.shadowsocks.plugin.PluginContract
import com.github.shadowsocks.preference.DataStore
......
......@@ -26,13 +26,15 @@ import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.UserManager
import android.support.design.widget.Snackbar
import android.support.v14.preference.SwitchPreference
import android.support.v7.app.AlertDialog
import android.support.v7.preference.Preference
import android.support.v7.preference.PreferenceDataStore
import android.support.v7.widget.Toolbar
import com.google.android.material.snackbar.Snackbar
import androidx.preference.SwitchPreference
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceDataStore
import androidx.appcompat.widget.Toolbar
import android.view.MenuItem
import androidx.core.content.getSystemService
import androidx.core.os.bundleOf
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
......@@ -47,8 +49,8 @@ import com.github.shadowsocks.preference.PluginConfigurationDialogFragment
import com.github.shadowsocks.utils.Action
import com.github.shadowsocks.utils.DirectBoot
import com.github.shadowsocks.utils.Key
import com.takisoft.fix.support.v7.preference.EditTextPreference
import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat
class ProfileConfigFragment : PreferenceFragmentCompat(), Toolbar.OnMenuItemClickListener,
Preference.OnPreferenceChangeListener, OnPreferenceDataStoreChangeListener {
......@@ -68,7 +70,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), Toolbar.OnMenuItemClic
val activity = requireActivity()
profileId = activity.intent.getLongExtra(Action.EXTRA_PROFILE_ID, -1L)
addPreferencesFromResource(R.xml.pref_profile)
if (Build.VERSION.SDK_INT >= 25 && activity.getSystemService(UserManager::class.java).isDemoUser) {
if (Build.VERSION.SDK_INT >= 25 && activity.getSystemService<UserManager>()?.isDemoUser == true) {
findPreference(Key.host).summary = "shadowsocks.example.org"
findPreference(Key.remotePort).summary = "1337"
findPreference(Key.password).summary = "\u2022".repeat(32)
......@@ -116,12 +118,9 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), Toolbar.OnMenuItemClic
pluginConfigure.text = pluginConfiguration.selectedOptions.toString()
}
private fun showPluginEditor() {
val bundle = Bundle()
bundle.putString("key", Key.pluginConfigure)
bundle.putString(PluginConfigurationDialogFragment.PLUGIN_ID_FRAGMENT_TAG, pluginConfiguration.selected)
displayPreferenceDialog(PluginConfigurationDialogFragment(), Key.pluginConfigure, bundle)
}
private fun showPluginEditor() = displayPreferenceDialog(PluginConfigurationDialogFragment(), Key.pluginConfigure,
bundleOf(Pair("key", Key.pluginConfigure),
Pair(PluginConfigurationDialogFragment.PLUGIN_ID_FRAGMENT_TAG, pluginConfiguration.selected)))
fun saveAndExit() {
val profile = ProfileManager.getProfile(profileId) ?: Profile()
......@@ -182,10 +181,10 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), Toolbar.OnMenuItemClic
val activity = requireActivity()
AlertDialog.Builder(activity)
.setTitle(R.string.delete_confirm_prompt)
.setPositiveButton(R.string.yes, { _, _ ->
.setPositiveButton(R.string.yes) { _, _ ->
ProfileManager.delProfile(profileId)
activity.finish()
})
}
.setNegativeButton(R.string.no, null)
.create()
.show()
......
......@@ -29,15 +29,17 @@ import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v4.app.DialogFragment
import android.support.v7.widget.*
import android.support.v7.widget.helper.ItemTouchHelper
import com.google.android.material.snackbar.Snackbar
import androidx.fragment.app.DialogFragment
import androidx.appcompat.widget.*
import android.text.format.Formatter
import android.view.*
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.getSystemService
import androidx.core.os.bundleOf
import androidx.recyclerview.widget.*
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.database.Profile
......@@ -45,7 +47,6 @@ import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Action
import com.github.shadowsocks.utils.systemService
import com.github.shadowsocks.widget.UndoSnackbarManager
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
......@@ -79,9 +80,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
class QRCodeDialog() : DialogFragment() {
constructor(url: String) : this() {
val bundle = Bundle()
bundle.putString(KEY_URL, url)
arguments = bundle
arguments = bundleOf(Pair(KEY_URL, url))
}
private val url get() = arguments!!.getString(KEY_URL)
......@@ -152,20 +151,14 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
rx += rxTotal
}
text1.text = item.formattedName
val t2 = ArrayList<String>()
if (!item.name.isNullOrEmpty()) t2 += item.formattedAddress
val id = PluginConfiguration(item.plugin ?: "").selected
if (id.isNotEmpty()) t2 += app.getString(R.string.profile_plugin, id)
if (t2.isEmpty()) text2.visibility = View.GONE else {
text2.visibility = View.VISIBLE
text2.text = t2.joinToString("\n")
}
text2.text = ArrayList<String>().apply {
if (!item.name.isNullOrEmpty()) this += item.formattedAddress
val id = PluginConfiguration(item.plugin ?: "").selected
if (id.isNotEmpty()) this += app.getString(R.string.profile_plugin, id)
}.joinToString("\n")
val context = requireContext()
if (tx <= 0 && rx <= 0) traffic.visibility = View.GONE else {
traffic.visibility = View.VISIBLE
traffic.text = getString(R.string.traffic,
Formatter.formatFileSize(context, tx), Formatter.formatFileSize(context, rx))
}
traffic.text = if (tx <= 0 && rx <= 0) null else getString(R.string.traffic,
Formatter.formatFileSize(context, tx), Formatter.formatFileSize(context, rx))
if (item.id == DataStore.profileId) {
itemView.isSelected = true
......@@ -196,7 +189,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
adView.loadAd(adBuilder.build())
this.adView = adView
} else adView.visibility = View.VISIBLE
} else if (adView != null) adView.visibility = View.GONE
} else adView?.visibility = View.GONE
}
override fun onClick(v: View?) {
......@@ -236,7 +229,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProfileViewHolder = ProfileViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.layout_profile, parent, false))
override fun getItemCount(): Int = profiles.size
override fun getItemId(position: Int): Long = profiles[position].id.toLong()
override fun getItemId(position: Int): Long = profiles[position].id
fun add(item: Profile) {
undoManager.flush()
......@@ -309,7 +302,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
private var txTotal: Long = 0L
private var rxTotal: Long = 0L
private val clipboard by lazy { requireContext().systemService<ClipboardManager>() }
private val clipboard by lazy { requireContext().getSystemService<ClipboardManager>()!! }
private fun startConfig(profile: Profile) {
profile.serialize()
......@@ -327,7 +320,7 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
if (!ProfileManager.isNotEmpty()) DataStore.profileId = ProfileManager.createProfile().id
val profilesList = view.findViewById<RecyclerView>(R.id.list)
val layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
profilesList.layoutManager = layoutManager
profilesList.addItemDecoration(DividerItemDecoration(context, layoutManager.orientation))
layoutManager.scrollToPosition(profilesAdapter.profiles.indexOfFirst { it.id == DataStore.profileId })
......
......@@ -25,9 +25,10 @@ import android.content.Intent
import android.content.pm.ShortcutManager
import android.os.Build
import android.os.Bundle
import android.support.v4.content.pm.ShortcutInfoCompat
import android.support.v4.content.pm.ShortcutManagerCompat
import android.support.v4.graphics.drawable.IconCompat
import androidx.core.content.getSystemService
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.bg.BaseService
......@@ -45,7 +46,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface {
finish()
} else {
connection.connect()
if (Build.VERSION.SDK_INT >= 25) getSystemService(ShortcutManager::class.java).reportShortcutUsed("toggle")
if (Build.VERSION.SDK_INT >= 25) getSystemService<ShortcutManager>()!!.reportShortcutUsed("toggle")
}
}
......
......@@ -27,20 +27,20 @@ import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraManager
import android.os.Build
import android.os.Bundle
import android.support.v4.app.TaskStackBuilder
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import androidx.core.app.TaskStackBuilder
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import android.util.Log
import android.util.SparseArray
import android.view.MenuItem
import android.widget.Toast
import androidx.core.content.getSystemService
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.utils.openBitmap
import com.github.shadowsocks.utils.printLog
import com.github.shadowsocks.utils.resolveResourceId
import com.github.shadowsocks.utils.systemService
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.samples.vision.barcodereader.BarcodeCapture
import com.google.android.gms.samples.vision.barcodereader.BarcodeGraphic
......@@ -85,12 +85,12 @@ class ScannerActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListener, Ba
}
return
}
if (Build.VERSION.SDK_INT >= 25) getSystemService(ShortcutManager::class.java).reportShortcutUsed("scan")
if (Build.VERSION.SDK_INT >= 25) getSystemService<ShortcutManager>()!!.reportShortcutUsed("scan")
if (try {
systemService<CameraManager>().cameraIdList.isEmpty()
getSystemService<CameraManager>()?.cameraIdList?.isEmpty()
} catch (_: CameraAccessException) {
true
}) {
} != false) {
startImport()
return
}
......
......@@ -21,8 +21,9 @@
package com.github.shadowsocks
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.widget.Toolbar
import android.view.Gravity
import androidx.fragment.app.Fragment
import androidx.appcompat.widget.Toolbar
import android.view.View
/**
......@@ -34,8 +35,8 @@ open class ToolbarFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
toolbar = view.findViewById(R.id.toolbar)
val activity = activity as MainActivity
activity.drawer.setToolbar(activity, toolbar, true)
toolbar.setNavigationIcon(R.drawable.ic_navigation_menu)
toolbar.setNavigationOnClickListener { (activity as MainActivity).drawer.openDrawer(Gravity.START) }
}
open fun onTrafficUpdated(profileId: Long, txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) { }
......
......@@ -26,15 +26,15 @@ import android.content.Intent
import android.content.IntentFilter
import android.net.VpnService
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import android.util.Log
import androidx.core.content.getSystemService
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.utils.broadcastReceiver
import com.github.shadowsocks.utils.systemService
class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface {
companion object {
......@@ -50,7 +50,7 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface
finish()
return
}
if (systemService<KeyguardManager>().isKeyguardLocked) {
if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) {
receiver = broadcastReceiver { _, _ -> connection.connect() }
registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT))
} else connection.connect()
......
......@@ -21,7 +21,7 @@
package com.github.shadowsocks.acl
import android.content.Context
import android.support.v7.util.SortedList
import androidx.recyclerview.widget.SortedList
import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app
......
......@@ -25,21 +25,20 @@ import android.content.ClipboardManager
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.design.widget.TextInputLayout
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import android.support.v7.widget.helper.ItemTouchHelper
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.ItemTouchHelper
import android.text.Editable
import android.text.TextWatcher
import android.view.*
import android.widget.*
import com.futuremind.recyclerviewfastscroll.FastScroller
import com.futuremind.recyclerviewfastscroll.SectionTitleProvider
import androidx.core.content.getSystemService
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.MainActivity
import com.github.shadowsocks.R
......@@ -162,9 +161,6 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
private val text = view.findViewById<TextView>(android.R.id.text1)
init {
view.setPaddingRelative(view.paddingStart, view.paddingTop,
Math.max(view.paddingEnd, resources.getDimensionPixelSize(R.dimen.fastscroll__bubble_corner)),
view.paddingBottom)
view.setOnClickListener(this)
view.setOnLongClickListener(this)
view.setBackgroundResource(R.drawable.background_selectable)
......@@ -190,15 +186,15 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
if (selectedItems.isNotEmpty()) onLongClick(v) else {
val dialog = AclRuleDialog(item)
dialog.builder
.setNeutralButton(R.string.delete, { _, _ ->
.setNeutralButton(R.string.delete) { _, _ ->
adapter.remove(item)
undoManager.remove(Pair(-1, item))
})
.setPositiveButton(android.R.string.ok, { _, _ ->
}
.setPositiveButton(android.R.string.ok) { _, _ ->
adapter.remove(item)
val index = dialog.add() ?: adapter.add(item)
if (index != null) list.post { list.scrollToPosition(index) }
})
}
dialog.show()
}
}
......@@ -210,7 +206,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
}
}
private inner class AclRulesAdapter : RecyclerView.Adapter<AclRuleViewHolder>(), SectionTitleProvider {
private inner class AclRulesAdapter : RecyclerView.Adapter<AclRuleViewHolder>() {
private val acl = Acl.customRules
private var savePending = false
......@@ -224,17 +220,6 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = AclRuleViewHolder(LayoutInflater
.from(parent.context).inflate(android.R.layout.simple_list_item_1, parent, false))
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 (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
}).firstOrNull()?.toString() ?: " "
}
private fun apply() {
if (!savePending) {
......@@ -358,7 +343,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
private lateinit var list: RecyclerView
private var mode: ActionMode? = null
private lateinit var undoManager: UndoSnackbarManager<Any>
private val clipboard by lazy { requireContext().systemService<ClipboardManager>() }
private val clipboard by lazy { requireContext().getSystemService<ClipboardManager>()!! }
private fun onSelectedItemsUpdated() {
if (selectedItems.isEmpty()) mode?.finish() else if (mode == null) mode = toolbar.startActionMode(this)
......@@ -383,10 +368,9 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
toolbar.setOnMenuItemClickListener(this)
val activity = requireActivity()
list = view.findViewById(R.id.list)
list.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
list.layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
list.itemAnimator = DefaultItemAnimator()
list.adapter = adapter
view.findViewById<FastScroller>(R.id.fastscroller).setRecyclerView(list)
undoManager = UndoSnackbarManager(activity.findViewById(R.id.snackbar), adapter::undo)
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.START or ItemTouchHelper.END) {
override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int =
......@@ -430,7 +414,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
override fun onMenuItemClick(item: MenuItem): Boolean = when (item.itemId) {
R.id.action_manual_settings -> {
val dialog = AclRuleDialog()
dialog.builder.setPositiveButton(android.R.string.ok, { _, _ -> dialog.add() })
dialog.builder.setPositiveButton(android.R.string.ok) { _, _ -> dialog.add() }
dialog.show()
true
}
......@@ -467,7 +451,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
// for dark mode, it's roughly 850? (#303030)
window.statusBarColor = ContextCompat.getColor(activity, when {
resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES ->
R.color.md_black_1000
android.R.color.black
Build.VERSION.SDK_INT >= 23 -> {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
R.color.material_grey_300
......
......@@ -26,12 +26,12 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.os.RemoteCallbackList
import android.support.v4.os.UserManagerCompat
import android.util.Base64
import android.util.Log
import androidx.core.os.UserManagerCompat
import androidx.core.os.bundleOf
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R
......@@ -293,7 +293,7 @@ object BaseService {
val data = data
data.changeState(STOPPING)
app.analytics.logEvent("stop", Bundle().put(FirebaseAnalytics.Param.METHOD, tag))
app.analytics.logEvent("stop", bundleOf(Pair(FirebaseAnalytics.Param.METHOD, tag)))
killProcesses()
......@@ -357,7 +357,7 @@ object BaseService {
}
data.notification = createNotification(profile.formattedName)
app.analytics.logEvent("start", Bundle().put(FirebaseAnalytics.Param.METHOD, tag))
app.analytics.logEvent("start", bundleOf(Pair(FirebaseAnalytics.Param.METHOD, tag)))
data.changeState(CONNECTING)
......
......@@ -29,15 +29,15 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.PowerManager
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import android.text.format.Formatter
import com.github.shadowsocks.MainActivity
import com.github.shadowsocks.R
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.utils.Action
import com.github.shadowsocks.utils.broadcastReceiver
import com.github.shadowsocks.utils.systemService
import androidx.core.content.getSystemService
import java.util.*
/**
......@@ -48,10 +48,8 @@ import java.util.*
*/
class ServiceNotification(private val service: BaseService.Interface, profileName: String,
channel: String, private val visible: Boolean = false) {
private val keyGuard = (service as Context).systemService<KeyguardManager>()
private val nm by lazy {
(service as Context).getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
private val keyGuard = (service as Context).getSystemService<KeyguardManager>()!!
private val nm by lazy { (service as Context).getSystemService<NotificationManager>()!! }
private val callback by lazy {
object : IShadowsocksServiceCallback.Stub() {
override fun stateChanged(state: Int, profileName: String?, msg: String?) { } // ignore
......@@ -84,8 +82,8 @@ class ServiceNotification(private val service: BaseService.Interface, profileNam
service as Context
if (Build.VERSION.SDK_INT < 24) builder.addAction(R.drawable.ic_navigation_close,
service.getString(R.string.stop), PendingIntent.getBroadcast(service, 0, Intent(Action.CLOSE), 0))
val power = service.systemService<PowerManager>()
update(if (power.isInteractive) Intent.ACTION_SCREEN_ON else Intent.ACTION_SCREEN_OFF, true)
update(if (service.getSystemService<PowerManager>()?.isInteractive != false)
Intent.ACTION_SCREEN_ON else Intent.ACTION_SCREEN_OFF, true)
val screenFilter = IntentFilter()
screenFilter.addAction(Intent.ACTION_SCREEN_ON)
screenFilter.addAction(Intent.ACTION_SCREEN_OFF)
......
......@@ -23,14 +23,14 @@ package com.github.shadowsocks.bg
import android.app.KeyguardManager
import android.graphics.drawable.Icon
import android.service.quicksettings.Tile
import android.support.annotation.RequiresApi
import androidx.annotation.RequiresApi
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R
import com.github.shadowsocks.ShadowsocksConnection
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.systemService
import androidx.core.content.getSystemService
import android.service.quicksettings.TileService as BaseTileService
@RequiresApi(24)
......@@ -38,7 +38,7 @@ class TileService : BaseTileService(), ShadowsocksConnection.Interface {
private val iconIdle by lazy { Icon.createWithResource(this, R.drawable.ic_service_idle) }
private val iconBusy by lazy { Icon.createWithResource(this, R.drawable.ic_service_busy) }
private val iconConnected by lazy { Icon.createWithResource(this, R.drawable.ic_service_active) }
private val keyguard by lazy { systemService<KeyguardManager>() }
private val keyguard by lazy { getSystemService<KeyguardManager>()!! }
override val serviceCallback: IShadowsocksServiceCallback.Stub by lazy {
@RequiresApi(24)
......
......@@ -38,7 +38,7 @@ import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Subnet
import com.github.shadowsocks.utils.parseNumericAddress
import com.github.shadowsocks.utils.printLog
import com.github.shadowsocks.utils.systemService
import androidx.core.content.getSystemService
import java.io.File
import java.io.FileDescriptor
import java.io.IOException
......@@ -111,7 +111,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
field = value
}
private val connectivity by lazy { systemService<ConnectivityManager>() }
private val connectivity by lazy { getSystemService<ConnectivityManager>()!! }
@TargetApi(28)
private val defaultNetworkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
......
......@@ -20,7 +20,7 @@
package com.github.shadowsocks.database
import android.arch.persistence.room.*
import androidx.room.*
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
......@@ -37,7 +37,7 @@ class KeyValuePair() {
const val TYPE_STRING_SET = 6
}
@android.arch.persistence.room.Dao
@androidx.room.Dao
interface Dao {
@Query("SELECT * FROM `KeyValuePair` WHERE `key` = :key")
operator fun get(key: String): KeyValuePair?
......
......@@ -20,10 +20,10 @@
package com.github.shadowsocks.database
import android.arch.persistence.db.SupportSQLiteDatabase
import android.arch.persistence.room.Database
import android.arch.persistence.room.Room
import android.arch.persistence.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.migration.RecreateSchemaMigration
import com.github.shadowsocks.utils.Key
......
......@@ -20,10 +20,11 @@
package com.github.shadowsocks.database
import android.arch.persistence.room.*
import androidx.room.*
import android.net.Uri
import android.util.Base64
import android.util.Log
import androidx.core.net.toUri
import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Key
......@@ -43,7 +44,7 @@ class Profile : Serializable {
private val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)$".toRegex()
fun findAll(data: CharSequence?) = pattern.findAll(data ?: "").map {
val uri = Uri.parse(it.value)
val uri = it.value.toUri()
try {
if (uri.userInfo == null) {
val match = legacyPattern.matchEntire(String(Base64.decode(uri.host, Base64.NO_PADDING)))
......@@ -93,7 +94,7 @@ class Profile : Serializable {
}.filterNotNull()
}
@android.arch.persistence.room.Dao
@androidx.room.Dao
interface Dao {
@Query("SELECT * FROM `Profile` WHERE `id` = :id")
operator fun get(id: Long): Profile?
......
......@@ -20,9 +20,9 @@
package com.github.shadowsocks.database
import android.arch.persistence.room.Database
import android.arch.persistence.room.Room
import android.arch.persistence.room.RoomDatabase
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.migration.RecreateSchemaMigration
import com.github.shadowsocks.utils.Key
......
......@@ -20,8 +20,8 @@
package com.github.shadowsocks.database.migration
import android.arch.persistence.db.SupportSQLiteDatabase
import android.arch.persistence.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.room.migration.Migration
open class RecreateSchemaMigration(oldVersion: Int, newVersion: Int, private val table: String,
private val schema: String, private val keys: String) :
......
......@@ -27,9 +27,9 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.net.Uri
import android.os.Bundle
import android.util.Base64
import android.util.Log
import androidx.core.os.bundleOf
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.utils.Commandline
......@@ -151,10 +151,8 @@ object PluginManager {
}
private fun initNativeFast(cr: ContentResolver, options: PluginOptions, uri: Uri): String {
val out = Bundle()
out.putString(PluginContract.EXTRA_OPTIONS, options.id)
val result = cr.call(uri, PluginContract.METHOD_GET_EXECUTABLE, null, out)
.getString(PluginContract.EXTRA_ENTRY)
val result = cr.call(uri, PluginContract.METHOD_GET_EXECUTABLE, null,
bundleOf(Pair(PluginContract.EXTRA_OPTIONS, options.id))).getString(PluginContract.EXTRA_ENTRY)
check(File(result).canExecute())
return result
}
......
......@@ -27,16 +27,17 @@ import android.graphics.Typeface
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.support.design.widget.BottomSheetDialog
import android.support.v7.preference.PreferenceDialogFragmentCompat
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import androidx.preference.PreferenceDialogFragmentCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import com.github.shadowsocks.R
class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
......@@ -58,8 +59,8 @@ class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
val typeface = if (selected) Typeface.BOLD else Typeface.NORMAL
text1.setTypeface(null, typeface)
text2.setTypeface(null, typeface)
text2.visibility = if (preference.entryValues[i].isNotEmpty() &&
preference.entries[i] != preference.entryValues[i]) View.VISIBLE else View.GONE
text2.isVisible = preference.entryValues[i].isNotEmpty() &&
preference.entries[i] != preference.entryValues[i]
icon.setImageDrawable(preference.entryIcons?.get(i))
index = i
}
......
......@@ -21,7 +21,7 @@
package com.github.shadowsocks.preference
import android.os.Binder
import android.support.v7.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.PrivateDatabase
import com.github.shadowsocks.database.PublicDatabase
......@@ -52,37 +52,17 @@ object DataStore {
}
val canToggleLocked: Boolean get() = publicStore.getBoolean(Key.directBootAware) == true
val directBootAware: Boolean get() = app.directBootSupported && canToggleLocked
private var nightModeString: String
get() = publicStore.getString(Key.nightMode) ?: Key.nightModeSystem
set(value) = publicStore.putString(Key.nightMode, value)
@AppCompatDelegate.NightMode
val nightMode: Int get() = when (nightModeString) {
val nightMode get() = when (publicStore.getString(Key.nightMode)) {
Key.nightModeAuto -> AppCompatDelegate.MODE_NIGHT_AUTO
Key.nightModeOff -> AppCompatDelegate.MODE_NIGHT_NO
Key.nightModeOn -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
var serviceMode: String
get() = publicStore.getString(Key.serviceMode) ?: Key.modeVpn
set(value) = publicStore.putString(Key.serviceMode, value)
var portProxy: Int
get() = getLocalPort(Key.portProxy, 1080)
set(value) = publicStore.putString(Key.portProxy, value.toString())
var portLocalDns: Int
get() = getLocalPort(Key.portLocalDns, 5450)
set(value) = publicStore.putString(Key.portLocalDns, value.toString())
var portTransproxy: Int
get() = getLocalPort(Key.portTransproxy, 8200)
set(value) = publicStore.putString(Key.portTransproxy, value.toString())
fun initGlobal() {
// temporary workaround for support lib bug
if (publicStore.getString(Key.nightMode) == null) nightModeString = nightModeString
if (publicStore.getString(Key.serviceMode) == null) serviceMode = serviceMode
if (publicStore.getString(Key.portProxy) == null) portProxy = portProxy
if (publicStore.getString(Key.portLocalDns) == null) portLocalDns = portLocalDns
if (publicStore.getString(Key.portTransproxy) == null) portTransproxy = portTransproxy
}
val serviceMode get() = publicStore.getString(Key.serviceMode) ?: Key.modeVpn
val portProxy get() = getLocalPort(Key.portProxy, 1080)
val portLocalDns get() = getLocalPort(Key.portLocalDns, 5450)
val portTransproxy get() = getLocalPort(Key.portTransproxy, 8200)
var proxyApps: Boolean
get() = privateStore.getBoolean(Key.proxyApps) ?: false
......
......@@ -22,7 +22,7 @@ package com.github.shadowsocks.preference
import android.content.Context
import android.graphics.drawable.Drawable
import android.support.v7.preference.ListPreference
import androidx.preference.ListPreference
import android.util.AttributeSet
class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) {
......@@ -68,8 +68,8 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
fun init() {
icon = entryIcon
}
override fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) {
super.onSetInitialValue(restoreValue, defaultValue)
override fun onSetInitialValue(defaultValue: Any?) {
super.onSetInitialValue(defaultValue)
init()
}
}
......@@ -20,7 +20,7 @@
package com.github.shadowsocks.preference
import android.support.v7.preference.PreferenceDataStore
import androidx.preference.PreferenceDataStore
interface OnPreferenceDataStoreChangeListener {
fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?)
......
......@@ -20,13 +20,13 @@
package com.github.shadowsocks.preference
import android.support.v7.app.AlertDialog
import androidx.appcompat.app.AlertDialog
import android.view.View
import android.widget.EditText
import com.github.shadowsocks.ProfileConfigActivity
import com.github.shadowsocks.plugin.PluginContract
import com.github.shadowsocks.plugin.PluginManager
import com.takisoft.fix.support.v7.preference.EditTextPreferenceDialogFragmentCompat
import com.takisoft.preferencex.EditTextPreferenceDialogFragmentCompat
class PluginConfigurationDialogFragment : EditTextPreferenceDialogFragmentCompat() {
companion object {
......@@ -41,10 +41,10 @@ class PluginConfigurationDialogFragment : EditTextPreferenceDialogFragmentCompat
val intent = PluginManager.buildIntent(arguments!!.getString(PLUGIN_ID_FRAGMENT_TAG),
PluginContract.ACTION_HELP)
val activity = requireActivity()
if (intent.resolveActivity(activity.packageManager) != null) builder.setNeutralButton("?", { _, _ ->
if (intent.resolveActivity(activity.packageManager) != null) builder.setNeutralButton("?") { _, _ ->
activity.startActivityForResult(intent.putExtra(PluginContract.EXTRA_OPTIONS, editText.text.toString()),
ProfileConfigActivity.REQUEST_CODE_PLUGIN_HELP)
})
}
}
override fun onBindDialogView(view: View) {
......
......@@ -20,7 +20,7 @@
package com.github.shadowsocks.preference
import android.support.v7.preference.PreferenceDataStore
import androidx.preference.PreferenceDataStore
import com.github.shadowsocks.database.KeyValuePair
import java.util.HashSet
......
......@@ -23,11 +23,11 @@ package com.github.shadowsocks.tasker
import android.app.Activity
import android.content.res.Resources
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.appcompat.widget.Toolbar
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
......@@ -101,7 +101,7 @@ class ConfigActivity : AppCompatActivity() {
switch = findViewById(R.id.serviceSwitch)
switch.isChecked = taskerOption.switchOn
val profilesList = findViewById<RecyclerView>(R.id.list)
val lm = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
val lm = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
profilesList.layoutManager = lm
profilesList.itemAnimator = DefaultItemAnimator()
profilesList.adapter = profilesAdapter
......
......@@ -23,6 +23,7 @@ package com.github.shadowsocks.tasker
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.core.os.bundleOf
import com.github.shadowsocks.R
import com.github.shadowsocks.database.ProfileManager
import com.twofortyfouram.locale.api.Intent as ApiIntent
......@@ -44,13 +45,13 @@ class Settings(bundle: Bundle?) {
}
fun toIntent(context: Context): Intent {
val bundle = Bundle()
if (!switchOn) bundle.putBoolean(KEY_SWITCH_ON, false)
if (profileId >= 0) bundle.putLong(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)
else context.getString(if (switchOn) R.string.start_service_default else R.string.stop))
return Intent()
.putExtra(ApiIntent.EXTRA_BUNDLE, bundleOf(Pair(KEY_SWITCH_ON, switchOn),
Pair(KEY_PROFILE_ID, profileId)))
.putExtra(ApiIntent.EXTRA_STRING_BLURB,
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))
}
}
......@@ -10,11 +10,9 @@ import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.support.annotation.AttrRes
import android.support.v4.content.ContextCompat
import android.support.v7.util.SortedList
import android.util.TypedValue
import androidx.annotation.AttrRes
import androidx.recyclerview.widget.SortedList
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.JniHelper
import java.net.InetAddress
......@@ -49,8 +47,6 @@ fun thread(name: String? = null, start: Boolean = true, isDaemon: Boolean = fals
val URLConnection.responseLength: Long
get() = if (Build.VERSION.SDK_INT >= 24) contentLengthLong else contentLength.toLong()
inline fun <reified T> Context.systemService() = ContextCompat.getSystemService(this, T::class.java)!!
fun ContentResolver.openBitmap(uri: Uri) =
if (Build.VERSION.SDK_INT >= 28) ImageDecoder.decodeBitmap(ImageDecoder.createSource(this, uri))
else BitmapFactory.decodeStream(openInputStream(uri))
......@@ -81,8 +77,3 @@ fun printLog(t: Throwable) {
Crashlytics.logException(t)
t.printStackTrace()
}
fun Bundle.put(key: String, value: String): Bundle {
putString(key, value)
return this
}
......@@ -22,13 +22,21 @@ package com.github.shadowsocks.widget
import android.content.Context
import android.graphics.Rect
import android.support.v7.widget.AppCompatTextView
import androidx.appcompat.widget.AppCompatTextView
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.core.view.isGone
import com.crashlytics.android.Crashlytics
class HackyTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
class AutoCollapseTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
defStyleAttr: Int = 0) :
AppCompatTextView(context, attrs, defStyleAttr) {
override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
super.onTextChanged(text, start, lengthBefore, lengthAfter)
isGone = text.isNullOrEmpty()
}
// #1874
override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) = try {
super.onFocusChanged(focused, direction, previouslyFocusedRect)
} catch (e: IndexOutOfBoundsException) {
......
......@@ -21,7 +21,7 @@
package com.github.shadowsocks.widget
import android.content.Context
import android.support.v7.widget.GridLayout
import androidx.gridlayout.widget.GridLayout
import android.util.AttributeSet
import com.github.shadowsocks.R
......
......@@ -22,11 +22,11 @@ package com.github.shadowsocks.widget
import android.content.Context
import android.graphics.drawable.Drawable
import android.support.annotation.DrawableRes
import android.support.design.widget.FloatingActionButton
import android.support.graphics.drawable.Animatable2Compat
import android.support.graphics.drawable.AnimatedVectorDrawableCompat
import android.support.v7.widget.TooltipCompat
import androidx.annotation.DrawableRes
import com.google.android.material.floatingactionbutton.FloatingActionButton
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import androidx.appcompat.widget.TooltipCompat
import android.util.AttributeSet
import android.view.View
import com.github.shadowsocks.R
......
......@@ -22,20 +22,20 @@ package com.github.shadowsocks.widget
import android.animation.ValueAnimator
import android.content.Context
import android.support.design.animation.AnimationConsts
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.Snackbar
import android.support.design.widget.SnackbarConsts
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.SnackbarConsts
import android.util.AttributeSet
import android.view.View
import android.view.accessibility.AccessibilityManager
import com.github.shadowsocks.utils.systemService
import androidx.core.content.getSystemService
import com.google.android.material.animation.AnimationUtils
/**
* Full credits go to: https://stackoverflow.com/a/35904421/2245107
*/
class ShrinkUpwardBehavior(context: Context, attrs: AttributeSet?) : CoordinatorLayout.Behavior<View>(context, attrs) {
private val accessibility = context.systemService<AccessibilityManager>()
private val accessibility = context.getSystemService<AccessibilityManager>()!!
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean =
dependency is Snackbar.SnackbarLayout
......@@ -54,11 +54,10 @@ class ShrinkUpwardBehavior(context: Context, attrs: AttributeSet?) : Coordinator
val animator = ValueAnimator()
val start = child.height
animator.setIntValues(start, parent.height)
animator.interpolator = AnimationConsts.FAST_OUT_SLOW_IN_INTERPOLATOR
animator.interpolator = AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR
animator.duration = SnackbarConsts.ANIMATION_DURATION
@Suppress("NAME_SHADOWING")
animator.addUpdateListener { animator ->
child.layoutParams.height = animator.animatedValue as Int
animator.addUpdateListener {
child.layoutParams.height = it.animatedValue as Int
child.requestLayout()
}
animator.start()
......
......@@ -20,7 +20,7 @@
package com.github.shadowsocks.widget
import android.support.design.widget.Snackbar
import com.google.android.material.snackbar.Snackbar
import android.view.View
import com.github.shadowsocks.R
......
......@@ -18,7 +18,7 @@
* *
*******************************************************************************/
package android.support.design.widget
package com.google.android.material.snackbar
object SnackbarConsts {
const val ANIMATION_DURATION = BaseTransientBottomBar.ANIMATION_DURATION.toLong()
......
......@@ -18,7 +18,7 @@
<!-- android:start not available until API 23 -->
<item android:left="8dp">
<shape android:shape="rectangle">
<solid android:color="@color/background" />
<solid android:color="?android:colorBackground" />
</shape>
</item>
<item android:drawable="?android:attr/selectableItemBackground"/>
......
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/darker_gray" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners
android:topLeftRadius="44dp"
android:topRightRadius="44dp"
android:bottomLeftRadius="44dp" />
<padding
android:paddingLeft="22dp"
android:paddingRight="22dp" />
<solid android:color="@color/color_primary_dark" />
</shape>
</item>
</selector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFF"
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
</vector>
......@@ -10,15 +10,15 @@
android:layout_height="wrap_content"
android:labelFor="@+id/content"
android:entries="@array/acl_rule_templates"/>
<android.support.design.widget.TextInputLayout
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true">
<android.support.design.widget.TextInputEditText
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textMultiLine"/>
</android.support.design.widget.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
......@@ -9,7 +9,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<com.github.shadowsocks.widget.HackyTextView
<com.github.shadowsocks.widget.AutoCollapseTextView
android:id="@+id/tv_about"
android:layout_width="match_parent"
android:layout_height="wrap_content"
......
......@@ -11,7 +11,7 @@
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:elevation="1dp"
android:background="@color/background"
android:background="?android:colorBackground"
android:orientation="vertical"
tools:ignore="RtlSymmetry">
......@@ -21,7 +21,7 @@
android:layout_height="wrap_content"
android:checked="true"
android:paddingBottom="12dp"
android:paddingEnd="@dimen/fastscroll__bubble_corner"
android:paddingEnd="16dp"
android:paddingStart="72dp"
android:paddingTop="12dp"
android:text="@string/on"
......@@ -34,7 +34,7 @@
android:layout_height="wrap_content"
android:checked="true"
android:paddingBottom="12dp"
android:paddingEnd="@dimen/fastscroll__bubble_corner"
android:paddingEnd="16dp"
android:paddingStart="72dp"
android:paddingTop="12dp"
android:text="@string/bypass_apps"
......@@ -42,7 +42,7 @@
android:textSize="18sp"
android:tooltipText="@string/bypass_apps_summary"/>
</LinearLayout>
<android.support.design.widget.CoordinatorLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/snackbar"
android:background="@color/material_primary_700"
android:layout_width="match_parent"
......@@ -56,22 +56,16 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/list"
app:fastScrollEnabled="true"
app:fastScrollHorizontalThumbDrawable="@drawable/fastscroll_thumb"
app:fastScrollHorizontalTrackDrawable="@drawable/fastscroll_line"
app:fastScrollVerticalThumbDrawable="@drawable/fastscroll_thumb"
app:fastScrollVerticalTrackDrawable="@drawable/fastscroll_line"
tools:listitem="@layout/layout_apps_item"/>
<com.futuremind.recyclerviewfastscroll.FastScroller
android:id="@+id/fastscroller"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:fastscroll__handleColor="@color/material_primary_500"
app:fastscroll__bubbleColor="@color/material_primary_500"
app:fastscroll__bubbleTextAppearance="@style/StyledScrollerTextAppearance"/>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
......@@ -20,7 +20,7 @@
android:id="@+id/itemcheck"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_marginEnd="@dimen/fastscroll__bubble_corner"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:clickable="false"
android:ellipsize="end"
......
......@@ -9,22 +9,17 @@
<FrameLayout android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<android.support.v7.widget.RecyclerView android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="32dp"
tools:listitem="@android:layout/simple_list_item_1"
android:clipToPadding="false"/>
<com.futuremind.recyclerviewfastscroll.FastScroller
android:id="@+id/fastscroller"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginBottom="32dp"
app:fastscroll__handleColor="@color/material_primary_500"
app:fastscroll__bubbleColor="@color/material_primary_500"
app:fastscroll__bubbleTextAppearance="@style/StyledScrollerTextAppearance"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="32dp"
android:clipToPadding="false"
app:fastScrollEnabled="true"
app:fastScrollHorizontalThumbDrawable="@drawable/fastscroll_thumb"
app:fastScrollHorizontalTrackDrawable="@drawable/fastscroll_line"
app:fastScrollVerticalThumbDrawable="@drawable/fastscroll_thumb"
app:fastScrollVerticalTrackDrawable="@drawable/fastscroll_line"
tools:listitem="@android:layout/simple_list_item_1"/>
</FrameLayout>
</LinearLayout>
......@@ -5,7 +5,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar_light_dark"/>
<android.support.v7.widget.RecyclerView android:id="@+id/list"
<androidx.recyclerview.widget.RecyclerView android:id="@+id/list"
tools:listitem="@layout/layout_profile"
android:layout_width="match_parent"
android:layout_height="0dp"
......
This diff is collapsed.
......@@ -33,7 +33,7 @@
android:textStyle="bold"
tools:text="@string/profile_name"/>
<android.support.v7.widget.AppCompatImageView
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -45,7 +45,7 @@
android:padding="12dp"
app:srcCompat="@drawable/ic_social_share"/>
<android.support.v7.widget.AppCompatImageView
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -63,7 +63,7 @@
android:layout_marginLeft="16dp"
>
<TextView
<com.github.shadowsocks.widget.AutoCollapseTextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -77,7 +77,7 @@
android:textColor="?android:attr/textColorSecondary"
tools:text="@string/profile_plugin"/>
<TextView
<com.github.shadowsocks.widget.AutoCollapseTextView
android:id="@+id/traffic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......
......@@ -16,7 +16,7 @@
android:textSize="18sp"
android:padding="16dp"/>
</FrameLayout>
<android.support.v7.widget.RecyclerView android:id="@+id/list"
<androidx.recyclerview.widget.RecyclerView android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemview="@android:layout/select_dialog_singlechoice_material"
......
......@@ -4,11 +4,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/background_header"/>
android:layout_height="wrap_content"
android:orientation="vertical"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/background_header"/>
<TextView android:id="@+id/drawer_title"
android:layout_width="match_parent"
......
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/main"
android:checkableBehavior="single">
<item android:id="@+id/profiles"
android:title="@string/profiles"
android:icon="@drawable/ic_action_description"/>
<item android:id="@+id/customRules"
android:title="@string/custom_rules"
android:icon="@drawable/ic_action_assignment"/>
<item android:id="@+id/globalSettings"
android:title="@string/settings"
android:icon="@drawable/ic_action_settings"/>
</group>
<group android:id="@+id/misc"
android:checkableBehavior="single">
<item android:id="@+id/faq"
android:checkable="false"
android:title="@string/faq"
android:icon="@drawable/ic_action_help_outline"/>
<item android:id="@+id/about"
android:title="@string/about"
android:icon="@drawable/ic_action_copyright"/>
</group>
</menu>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="background">@color/md_dark_background</color>
<color name="background_selected">@color/material_primary_800</color>
<color name="primary_drawable">@android:color/white</color>
<color name="background_stat">@color/material_primary_600</color>
<!-- MaterialDrawer colors -->
<color name="drawer_background">@color/material_drawer_dark_background</color>
<color name="drawer_primary_text">@color/material_drawer_dark_primary_text</color>
<color name="drawer_primary_icon">@color/material_drawer_dark_primary_icon</color>
<color name="drawer_secondary_text">@color/material_drawer_dark_secondary_text</color>
<color name="drawer_hint_text">@color/material_drawer_dark_hint_text</color>
<color name="drawer_divider">@color/material_drawer_dark_divider</color>
<color name="drawer_selected">@color/material_drawer_dark_selected</color>
<color name="drawer_selected_text">@color/material_accent_200</color>
<color name="drawer_header_selection_text">@color/material_drawer_dark_header_selection_text</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Design.DayNight.BottomSheetDialog" parent="@style/Theme.Design.BottomSheetDialog"/>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#7488A1</color>
<color name="material_drawer_selected_text">@color/material_accent_200</color>
<color name="background">@color/md_light_background</color>
<color name="background_selected">@color/material_primary_100</color>
<color name="primary_drawable">@android:color/black</color>
<color name="background_stat">@color/material_primary_300</color>
<!-- MaterialDrawer colors -->
<color name="drawer_background">@color/material_drawer_background</color>
<color name="drawer_primary_text">@color/material_drawer_primary_text</color>
<color name="drawer_primary_icon">@color/material_drawer_primary_icon</color>
<color name="drawer_secondary_text">@color/material_drawer_secondary_text</color>
<color name="drawer_hint_text">@color/material_drawer_hint_text</color>
<color name="drawer_divider">@color/material_drawer_divider</color>
<color name="drawer_selected">@color/material_drawer_selected</color>
<color name="drawer_selected_text">@color/material_accent_200</color>
<color name="drawer_header_selection_text">@color/material_drawer_header_selection_text</color>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Shadowsocks.App">
<item name="bottomSheetDialogTheme">@style/Theme.Design.DayNight.BottomSheetDialog</item>
<!-- MaterialDrawer specific values -->
<item name="material_drawer_background">@color/drawer_background</item>
<item name="material_drawer_primary_text">@color/drawer_primary_text</item>
<item name="material_drawer_primary_icon">@color/drawer_primary_icon</item>
<item name="material_drawer_secondary_text">@color/drawer_secondary_text</item>
<item name="material_drawer_hint_text">@color/drawer_hint_text</item>
<item name="material_drawer_divider">@color/drawer_divider</item>
<item name="material_drawer_selected">@color/drawer_selected</item>
<item name="material_drawer_selected_text">@color/drawer_selected_text</item>
<item name="material_drawer_header_selection_text">@color/drawer_header_selection_text</item>
</style>
<style name="Theme.Design.DayNight.BottomSheetDialog" parent="@style/Theme.Design.Light.BottomSheetDialog"/>
<!-- https://github.com/Gericop/Android-Support-Preference-V7-Fix/issues/111 -->
<style name="Preference.SimpleMenuPreference">
<item name="android:layout">@layout/preference_simplemenu</item>
<item name="allowDividerAbove">false</item>
<item name="allowDividerBelow">true</item>
<item name="iconSpaceReserved">@bool/config_materialPreferenceIconSpaceReserved</item>
<item name="pref_popupStyle">@style/Preference.SimpleMenuPreference.Popup</item>
</style>
<style name="StyledScrollerTextAppearance" parent="@android:style/TextAppearance">
<item name="android:textSize">24sp</item>
<item name="android:textStyle">bold</item>
......
* 0.2.0:
* Refactor to AndroidX.
* 0.1.1:
* Rewritten in Kotlin;
* Fix assert not working;
......
......@@ -10,10 +10,10 @@ android {
defaultConfig {
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.sdkVersion
versionCode 6
versionName "0.1.1"
versionCode 7
versionName "0.2.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
......@@ -24,12 +24,14 @@ android {
}
dependencies {
api "com.android.support:preference-v14:$supportLibraryVersion"
api "com.takisoft.fix:preference-v7:$takisoftFixVersion"
api "androidx.core:core-ktx:$androidxVersion"
api "androidx.preference:preference:$androidxVersion"
api "com.google.android.material:material:$androidxVersion"
api 'com.takisoft.preferencex:preferencex:1.0.0-alpha1'
api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "com.android.support.test:runner:$androidTestVersion"
androidTestImplementation "com.android.support.test.espresso:espresso-core:$androidEspressoVersion"
androidTestImplementation "androidx.test:runner:$androidTestVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidEspressoVersion"
}
repositories {
mavenCentral()
......
package com.github.shadowsocks.plugin;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
......
......@@ -27,6 +27,7 @@ import android.database.MatrixCursor
import android.net.Uri
import android.os.Bundle
import android.os.ParcelFileDescriptor
import androidx.core.os.bundleOf
/**
* Base class for a native plugin provider. A native plugin provider offers read-only access to files that are required
......@@ -83,12 +84,8 @@ abstract class NativePluginProvider : ContentProvider() {
return openFile(uri)
}
override fun call(method: String?, arg: String?, extras: Bundle?): Bundle = when (method) {
PluginContract.METHOD_GET_EXECUTABLE -> {
val out = Bundle()
out.putString(PluginContract.EXTRA_ENTRY, getExecutable())
out
}
override fun call(method: String?, arg: String?, extras: Bundle?): Bundle? = when (method) {
PluginContract.METHOD_GET_EXECUTABLE -> bundleOf(Pair(PluginContract.EXTRA_ENTRY, getExecutable()))
else -> super.call(method, arg, extras)
}
......
......@@ -22,8 +22,8 @@ package com.github.shadowsocks.plugin
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import android.widget.Toast
/**
......
......@@ -20,7 +20,7 @@
package com.github.shadowsocks.plugin
import android.support.v7.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate
/**
* The contract between the plugin provider and host. Contains definitions for the supported actions, extras, etc.
......
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="?attr/actionBarSize"
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Shadowsocks" parent="Theme.MaterialComponents.NoActionBar">
<item name="android:navigationBarColor">@color/color_primary_dark</item>
<item name="actionModeCloseDrawable">@drawable/ic_navigation_close</item>
<item name="bottomSheetDialogTheme">@style/Theme.MaterialComponents.DayNight.BottomSheetDialog</item>
<item name="colorAccent">@color/material_accent_200</item>
<item name="colorButtonNormal">@color/material_accent_200</item>
<item name="colorPrimary">@color/color_primary</item>
<item name="colorPrimaryDark">@color/color_primary_dark</item>
<item name="windowActionModeOverlay">true</item>
</style>
<style name="Theme.MaterialComponents.DayNight.BottomSheetDialog"
parent="@style/Theme.MaterialComponents.BottomSheetDialog"/>
<style name="ThemeOverlay.AppCompat.DayNight" parent="ThemeOverlay.AppCompat.Dark"/>
</resources>
\ No newline at end of file
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Shadowsocks" parent="Theme.AppCompat.DayNight.NoActionBar">
<style name="Theme.Shadowsocks" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="android:navigationBarColor">@color/color_primary_dark</item>
<item name="actionModeCloseDrawable">@drawable/ic_navigation_close</item>
<item name="bottomSheetDialogTheme">@style/Theme.MaterialComponents.DayNight.BottomSheetDialog</item>
<item name="colorAccent">@color/material_accent_200</item>
<item name="colorButtonNormal">@color/material_accent_200</item>
<item name="colorPrimary">@color/color_primary</item>
<item name="colorPrimaryDark">@color/color_primary_dark</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material.Fix</item>
<item name="preferenceCategory_marginBottom">8dp</item>
<item name="windowActionModeOverlay">true</item>
</style>
<style name="Theme.MaterialComponents.DayNight.BottomSheetDialog"
parent="@style/Theme.MaterialComponents.Light.BottomSheetDialog"/>
<style name="Theme.AppCompat.Translucent" parent="Theme.AppCompat.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowFrame">@null</item>
......
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