commit
2eac270fef
15 changed files with 356 additions and 31 deletions
28
.circleci/config.yml
Normal file
28
.circleci/config.yml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
working_directory: ~/code
|
||||||
|
docker:
|
||||||
|
- image: shadowsocks/shadowsocks-android:circleci
|
||||||
|
environment:
|
||||||
|
JVM_OPTS: -Xmx3500m
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.workers.max=1 -Dorg.gradle.daemon=false -Dkotlin.compiler.execution.strategy="in-process"
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: git submodule update --init --recursive
|
||||||
|
- restore_cache:
|
||||||
|
key: jars-{{ checksum "build.gradle" }}
|
||||||
|
- run:
|
||||||
|
name: Run Build and Tests
|
||||||
|
command: ./gradlew assembleDebug check
|
||||||
|
- save_cache:
|
||||||
|
paths:
|
||||||
|
- ~/.gradle
|
||||||
|
- ~/.android/build-cache
|
||||||
|
key: jars-{{ checksum "build.gradle" }}
|
||||||
|
- store_artifacts:
|
||||||
|
path: app/build/outputs/apk
|
||||||
|
destination: apk
|
||||||
|
- store_artifacts:
|
||||||
|
path: app/build/reports
|
||||||
|
destination: reports
|
|
@ -39,8 +39,8 @@ This plugin is an official plugin thus you can see [shadowsocks-android](https:/
|
||||||
|
|
||||||
### LICENSE
|
### LICENSE
|
||||||
|
|
||||||
Copyright (C) 2017 by Max Lv <<max.c.lv@gmail.com>>
|
Copyright (C) 2019 by Max Lv <<max.c.lv@gmail.com>>
|
||||||
Copyright (C) 2017 by Mygod Studio <<contact-shadowsocks-android@mygod.be>>
|
Copyright (C) 2019 by Mygod Studio <<contact-shadowsocks-android@mygod.be>>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -71,8 +71,10 @@ tasks.whenTaskAdded { task ->
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
|
implementation "androidx.preference:preference:1.1.0-alpha02"
|
||||||
implementation 'com.github.shadowsocks:plugin:1.0.0'
|
implementation 'com.github.shadowsocks:plugin:1.0.0'
|
||||||
|
implementation 'com.takisoft.preferencex:preferencex-simplemenu:1.0.0'
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
|
||||||
|
|
|
@ -22,13 +22,10 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data android:name="com.github.shadowsocks.plugin.id"
|
<meta-data android:name="com.github.shadowsocks.plugin.id"
|
||||||
android:value="v2ray"/>
|
android:value="v2ray"/>
|
||||||
<meta-data android:name="com.github.shadowsocks.plugin.default_config"
|
|
||||||
android:value="host=test.example.com"/>
|
|
||||||
</provider>
|
</provider>
|
||||||
<activity android:name=".HelpCallback"
|
<activity android:name=".ConfigActivity">
|
||||||
android:theme="@style/Theme.AppCompat.Translucent">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.github.shadowsocks.plugin.ACTION_HELP"/>
|
<action android:name="com.github.shadowsocks.plugin.ACTION_CONFIGURE"/>
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
<data android:scheme="plugin"
|
<data android:scheme="plugin"
|
||||||
android:host="com.github.shadowsocks"
|
android:host="com.github.shadowsocks"
|
||||||
|
|
|
@ -1,3 +1,23 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
|
||||||
|
* Copyright (C) 2019 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 com.github.shadowsocks.plugin.v2ray
|
package com.github.shadowsocks.plugin.v2ray
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
|
||||||
|
* Copyright (C) 2019 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 com.github.shadowsocks.plugin.v2ray
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Intent
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.preference.EditTextPreferenceDialogFragmentCompat
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
|
||||||
|
class CertificatePreferenceDialogFragment : EditTextPreferenceDialogFragmentCompat() {
|
||||||
|
fun setKey(key: String) {
|
||||||
|
arguments = bundleOf(Pair(ARG_KEY, key))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) {
|
||||||
|
super.onPrepareDialogBuilder(builder)
|
||||||
|
builder.setNeutralButton("Browse…") { _, _ ->
|
||||||
|
val activity = requireActivity()
|
||||||
|
try {
|
||||||
|
targetFragment!!.startActivityForResult(Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "application/pkix-cert"
|
||||||
|
}, ConfigFragment.REQUEST_BROWSE_CERTIFICATE)
|
||||||
|
return@setNeutralButton
|
||||||
|
} catch (_: ActivityNotFoundException) { } catch (_: SecurityException) { }
|
||||||
|
Snackbar.make(activity.findViewById<View>(R.id.content),
|
||||||
|
"Please install a file manager like MiXplorer",
|
||||||
|
Snackbar.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
|
||||||
|
* Copyright (C) 2019 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 com.github.shadowsocks.plugin.v2ray
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import com.github.shadowsocks.plugin.ConfigurationActivity
|
||||||
|
import com.github.shadowsocks.plugin.PluginOptions
|
||||||
|
|
||||||
|
class ConfigActivity : ConfigurationActivity(), Toolbar.OnMenuItemClickListener {
|
||||||
|
private val child by lazy { supportFragmentManager.findFragmentById(R.id.content) as ConfigFragment }
|
||||||
|
private lateinit var oldOptions: PluginOptions
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
findViewById<Toolbar>(R.id.toolbar).apply {
|
||||||
|
title = this@ConfigActivity.title
|
||||||
|
setNavigationIcon(R.drawable.ic_navigation_close)
|
||||||
|
setNavigationOnClickListener { onBackPressed() }
|
||||||
|
inflateMenu(R.menu.toolbar_config)
|
||||||
|
setOnMenuItemClickListener(this@ConfigActivity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInitializePluginOptions(options: PluginOptions) {
|
||||||
|
oldOptions = options
|
||||||
|
child.onInitializePluginOptions(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemClick(item: MenuItem?) = when (item?.itemId) {
|
||||||
|
R.id.action_apply -> {
|
||||||
|
saveChanges(child.options)
|
||||||
|
finish()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
if (child.options != oldOptions) AlertDialog.Builder(this).run {
|
||||||
|
setTitle(R.string.unsaved_changes_prompt)
|
||||||
|
setPositiveButton(R.string.yes) { _, _ -> saveChanges(child.options) }
|
||||||
|
setNegativeButton(R.string.no) { _, _ -> finish() }
|
||||||
|
setNeutralButton(android.R.string.cancel, null)
|
||||||
|
create()
|
||||||
|
}.show() else super.onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 by Max Lv <max.c.lv@gmail.com> *
|
||||||
|
* Copyright (C) 2019 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 com.github.shadowsocks.plugin.v2ray
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.preference.EditTextPreference
|
||||||
|
import androidx.preference.ListPreference
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.github.shadowsocks.plugin.PluginOptions
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import java.lang.RuntimeException
|
||||||
|
|
||||||
|
class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
|
||||||
|
companion object {
|
||||||
|
const val REQUEST_BROWSE_CERTIFICATE = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mode by lazy { findPreference<ListPreference>("mode") }
|
||||||
|
private val host by lazy { findPreference<EditTextPreference>("host") }
|
||||||
|
private val path by lazy { findPreference<EditTextPreference>("path") }
|
||||||
|
private val certRaw by lazy { findPreference<EditTextPreference>("certRaw") }
|
||||||
|
|
||||||
|
// todo: remove me for updated plugin lib
|
||||||
|
private fun PluginOptions.putWithDefault(key: String, value: String?, default: String? = null) =
|
||||||
|
if (value == null || value == default) remove(key) else put(key, value)
|
||||||
|
|
||||||
|
private fun readMode(value: String = mode.value) = when (value) {
|
||||||
|
"websocket-http" -> Pair(null, null)
|
||||||
|
"websocket-tls" -> Pair(null, "")
|
||||||
|
"quic-tls" -> Pair("quic", null)
|
||||||
|
else -> {
|
||||||
|
check(false)
|
||||||
|
Pair(null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val options get() = PluginOptions().apply {
|
||||||
|
val (mode, tls) = readMode()
|
||||||
|
putWithDefault("mode", mode)
|
||||||
|
putWithDefault("tls", tls)
|
||||||
|
putWithDefault("host", host.text, "cloudfront.com")
|
||||||
|
putWithDefault("path", path.text, "/")
|
||||||
|
putWithDefault("certRaw", certRaw.text.replace("\n", ""), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onInitializePluginOptions(options: PluginOptions) {
|
||||||
|
mode.value = when {
|
||||||
|
options["mode"] ?: "websocket" == "quic" -> "quic-tls"
|
||||||
|
options["tls"] != null -> "websocket-tls"
|
||||||
|
else -> "websocket-http"
|
||||||
|
}.also { onPreferenceChange(null, it) }
|
||||||
|
host.text = options["host"] ?: "cloudfront.com"
|
||||||
|
path.text = options["path"] ?: "/"
|
||||||
|
certRaw.text = options["certRaw"]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
addPreferencesFromResource(R.xml.config)
|
||||||
|
mode.onPreferenceChangeListener = this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
|
||||||
|
val (mode, tls) = readMode(newValue as String)
|
||||||
|
path.isEnabled = mode == null
|
||||||
|
certRaw.isEnabled = mode != null || tls != null
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisplayPreferenceDialog(preference: Preference?) {
|
||||||
|
if (preference == certRaw) CertificatePreferenceDialogFragment().apply {
|
||||||
|
setKey(certRaw.key)
|
||||||
|
setTargetFragment(this@ConfigFragment, 0)
|
||||||
|
}.show(fragmentManager ?: return, certRaw.key) else super.onDisplayPreferenceDialog(preference)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
when (requestCode) {
|
||||||
|
REQUEST_BROWSE_CERTIFICATE -> {
|
||||||
|
if (resultCode != Activity.RESULT_OK) return
|
||||||
|
val activity = requireActivity()
|
||||||
|
try {
|
||||||
|
// we read all its content here to avoid content URL permission issues
|
||||||
|
certRaw.text = activity.contentResolver.openInputStream(data!!.data!!)!!
|
||||||
|
.bufferedReader().readText()
|
||||||
|
} catch (e: RuntimeException) {
|
||||||
|
Snackbar.make(activity.findViewById<View>(R.id.content), e.localizedMessage, Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
package com.github.shadowsocks.plugin.v2ray
|
|
||||||
|
|
||||||
import com.github.shadowsocks.plugin.PluginOptions
|
|
||||||
|
|
||||||
class HelpCallback : com.github.shadowsocks.plugin.HelpCallback() {
|
|
||||||
override fun produceHelpMessage(options: PluginOptions): CharSequence =
|
|
||||||
"""
|
|
||||||
host=string
|
|
||||||
Host header for websocket. (default "cloudfront.com")
|
|
||||||
|
|
||||||
mode=string
|
|
||||||
Transport mode: ws/quic. (default "ws")
|
|
||||||
|
|
||||||
path=string
|
|
||||||
URL path for websocket. (default "/")
|
|
||||||
|
|
||||||
security=string
|
|
||||||
Transport security: none/tls. (default "none")
|
|
||||||
|
|
||||||
""".trimIndent()
|
|
||||||
|
|
||||||
}
|
|
9
app/src/main/res/drawable/ic_action_done.xml
Normal file
9
app/src/main/res/drawable/ic_action_done.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<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="#FFFFFFFF"
|
||||||
|
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
|
||||||
|
</vector>
|
12
app/src/main/res/layout/activity_main.xml
Normal file
12
app/src/main/res/layout/activity_main.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
<include layout="@layout/toolbar_light_dark" />
|
||||||
|
<fragment android:id="@+id/content"
|
||||||
|
class="com.github.shadowsocks.plugin.v2ray.ConfigFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"/>
|
||||||
|
</LinearLayout>
|
10
app/src/main/res/menu/toolbar_config.xml
Normal file
10
app/src/main/res/menu/toolbar_config.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item android:id="@+id/action_apply"
|
||||||
|
android:title="@string/apply"
|
||||||
|
android:icon="@drawable/ic_action_done"
|
||||||
|
android:alphabeticShortcut="a"
|
||||||
|
android:numericShortcut="1"
|
||||||
|
app:showAsAction="always"/>
|
||||||
|
</menu>
|
8
app/src/main/res/values/arrays.xml
Normal file
8
app/src/main/res/values/arrays.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string-array name="modes">
|
||||||
|
<item>websocket-http</item>
|
||||||
|
<item>websocket-tls</item>
|
||||||
|
<item>quic-tls</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
25
app/src/main/res/xml/config.xml
Normal file
25
app/src/main/res/xml/config.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<com.takisoft.preferencex.SimpleMenuPreference
|
||||||
|
app:key="mode"
|
||||||
|
app:persistent="false"
|
||||||
|
app:entries="@array/modes"
|
||||||
|
app:entryValues="@array/modes"
|
||||||
|
app:title="Transport mode"
|
||||||
|
app:useSimpleSummaryProvider="true"/>
|
||||||
|
<EditTextPreference
|
||||||
|
app:key="host"
|
||||||
|
app:persistent="false"
|
||||||
|
app:title="Hostname"
|
||||||
|
app:useSimpleSummaryProvider="true"/>
|
||||||
|
<EditTextPreference
|
||||||
|
app:key="path"
|
||||||
|
app:persistent="false"
|
||||||
|
app:title="Path"
|
||||||
|
app:useSimpleSummaryProvider="true"/>
|
||||||
|
<EditTextPreference
|
||||||
|
app:key="certRaw"
|
||||||
|
app:persistent="false"
|
||||||
|
app:title="Certificate for TLS verification"
|
||||||
|
app:useSimpleSummaryProvider="true"/>
|
||||||
|
</PreferenceScreen>
|
|
@ -1 +1 @@
|
||||||
Subproject commit f2d883c91f2cc20afe19949462736e54adf90bbb
|
Subproject commit b1add5f9903bb717cc5ac42a9b8d55f55127128e
|
Loading…
Reference in a new issue