ui: reformat all code
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
a3bfa6f1ab
commit
40eaa54cf0
@ -468,6 +468,7 @@
|
|||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
<codeStyleSettings language="kotlin">
|
<codeStyleSettings language="kotlin">
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
<option name="RIGHT_MARGIN" value="160" />
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
</code_scheme>
|
</code_scheme>
|
||||||
</component>
|
</component>
|
@ -1,4 +1,5 @@
|
|||||||
@file:Suppress("UnstableApiUsage")
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
||||||
|
|
||||||
val pkg: String = providers.gradleProperty("wireguardPackageName").get()
|
val pkg: String = providers.gradleProperty("wireguardPackageName").get()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
@file:Suppress("UnstableApiUsage")
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" tools:node="remove" />
|
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.REQUEST_INSTALL_PACKAGES"
|
||||||
|
tools:node="remove" />
|
||||||
<application>
|
<application>
|
||||||
<receiver android:name=".updater.Updater$AppUpdatedReceiver" tools:node="remove" />
|
<receiver
|
||||||
|
android:name=".updater.Updater$AppUpdatedReceiver"
|
||||||
|
tools:node="remove" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -45,10 +45,12 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.TunnelToggleActivity"
|
android:name=".activity.TunnelToggleActivity"
|
||||||
android:theme="@style/NoBackgroundTheme"
|
android:excludeFromRecents="true"
|
||||||
android:excludeFromRecents="true"/>
|
android:theme="@style/NoBackgroundTheme" />
|
||||||
|
|
||||||
<activity android:name=".activity.MainActivity" android:exported="true">
|
<activity
|
||||||
|
android:name=".activity.MainActivity"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
@ -62,8 +64,8 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.TvMainActivity"
|
android:name=".activity.TvMainActivity"
|
||||||
android:theme="@style/TvTheme"
|
android:exported="true"
|
||||||
android:exported="true">
|
android:theme="@style/TvTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
@ -87,8 +89,8 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.LogViewerActivity"
|
android:name=".activity.LogViewerActivity"
|
||||||
android:label="@string/log_viewer_title"
|
android:exported="false"
|
||||||
android:exported="false">
|
android:label="@string/log_viewer_title">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@ -100,14 +102,18 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true" />
|
android:grantUriPermissions="true" />
|
||||||
|
|
||||||
<receiver android:name=".BootShutdownReceiver" android:exported="true">
|
<receiver
|
||||||
|
android:name=".BootShutdownReceiver"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
|
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".updater.Updater$AppUpdatedReceiver" android:exported="true">
|
<receiver
|
||||||
|
android:name=".updater.Updater$AppUpdatedReceiver"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@ -115,8 +121,8 @@
|
|||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".model.TunnelManager$IntentReceiver"
|
android:name=".model.TunnelManager$IntentReceiver"
|
||||||
android:permission="${applicationId}.permission.CONTROL_TUNNELS"
|
android:exported="true"
|
||||||
android:exported="true">
|
android:permission="${applicationId}.permission.CONTROL_TUNNELS">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.wireguard.android.action.REFRESH_TUNNEL_STATES" />
|
<action android:name="com.wireguard.android.action.REFRESH_TUNNEL_STATES" />
|
||||||
<action android:name="com.wireguard.android.action.SET_TUNNEL_UP" />
|
<action android:name="com.wireguard.android.action.SET_TUNNEL_UP" />
|
||||||
@ -126,9 +132,9 @@
|
|||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".QuickTileService"
|
android:name=".QuickTileService"
|
||||||
|
android:exported="true"
|
||||||
android:icon="@drawable/ic_tile"
|
android:icon="@drawable/ic_tile"
|
||||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||||
android:exported="true">
|
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||||
|
@ -67,7 +67,8 @@ abstract class BaseActivity : AppCompatActivity() {
|
|||||||
protected abstract fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?): Boolean
|
protected abstract fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?): Boolean
|
||||||
|
|
||||||
fun removeOnSelectedTunnelChangedListener(
|
fun removeOnSelectedTunnelChangedListener(
|
||||||
listener: OnSelectedTunnelChangedListener) {
|
listener: OnSelectedTunnelChangedListener
|
||||||
|
) {
|
||||||
selectionChangeRegistry.remove(listener)
|
selectionChangeRegistry.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,18 +142,20 @@ class LogViewerActivity : AppCompatActivity() {
|
|||||||
finish()
|
finish()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.save_log -> {
|
R.id.save_log -> {
|
||||||
saveButton?.isEnabled = false
|
saveButton?.isEnabled = false
|
||||||
lifecycleScope.launch { saveLog() }
|
lifecycleScope.launch { saveLog() }
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val downloadsFileSaver = DownloadsFileSaver(this)
|
private val downloadsFileSaver = DownloadsFileSaver(this)
|
||||||
|
|
||||||
private suspend fun rawLogBytes() : ByteArray {
|
private suspend fun rawLogBytes(): ByteArray {
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
for (i in 0 until rawLogLines.size()) {
|
for (i in 0 until rawLogLines.size()) {
|
||||||
@ -179,10 +181,12 @@ class LogViewerActivity : AppCompatActivity() {
|
|||||||
saveButton?.isEnabled = true
|
saveButton?.isEnabled = true
|
||||||
if (outputFile == null)
|
if (outputFile == null)
|
||||||
return
|
return
|
||||||
Snackbar.make(findViewById(android.R.id.content),
|
Snackbar.make(
|
||||||
|
findViewById(android.R.id.content),
|
||||||
if (exception == null) getString(R.string.log_export_success, outputFile?.fileName)
|
if (exception == null) getString(R.string.log_export_success, outputFile?.fileName)
|
||||||
else getString(R.string.log_export_error, ErrorMessages[exception]),
|
else getString(R.string.log_export_error, ErrorMessages[exception]),
|
||||||
if (exception == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG)
|
if (exception == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG
|
||||||
|
)
|
||||||
.setAnchorView(binding.shareFab)
|
.setAnchorView(binding.shareFab)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
@ -287,7 +291,8 @@ class LogViewerActivity : AppCompatActivity() {
|
|||||||
*
|
*
|
||||||
* <pre>05-26 11:02:36.886 5689 5689 D AndroidRuntime: CheckJNI is OFF.</pre>
|
* <pre>05-26 11:02:36.886 5689 5689 D AndroidRuntime: CheckJNI is OFF.</pre>
|
||||||
*/
|
*/
|
||||||
private val THREADTIME_LINE: Pattern = Pattern.compile("^(\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{3})(?:\\s+[0-9A-Za-z]+)?\\s+(\\d+)\\s+(\\d+)\\s+([A-Z])\\s+(.+?)\\s*: (.*)$")
|
private val THREADTIME_LINE: Pattern =
|
||||||
|
Pattern.compile("^(\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{3})(?:\\s+[0-9A-Za-z]+)?\\s+(\\d+)\\s+(\\d+)\\s+([A-Z])\\s+(.+?)\\s*: (.*)$")
|
||||||
private val LOGS: MutableMap<String, ByteArray> = ConcurrentHashMap()
|
private val LOGS: MutableMap<String, ByteArray> = ConcurrentHashMap()
|
||||||
private const val TAG = "WireGuard/LogViewerActivity"
|
private const val TAG = "WireGuard/LogViewerActivity"
|
||||||
}
|
}
|
||||||
@ -321,8 +326,10 @@ class LogViewerActivity : AppCompatActivity() {
|
|||||||
else
|
else
|
||||||
SpannableString("${line.tag}: ${line.msg}").apply {
|
SpannableString("${line.tag}: ${line.msg}").apply {
|
||||||
setSpan(StyleSpan(BOLD), 0, "${line.tag}:".length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
setSpan(StyleSpan(BOLD), 0, "${line.tag}:".length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
setSpan(ForegroundColorSpan(levelToColor(line.level)),
|
setSpan(
|
||||||
0, "${line.tag}:".length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
ForegroundColorSpan(levelToColor(line.level)),
|
||||||
|
0, "${line.tag}:".length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
}
|
}
|
||||||
holder.layout.apply {
|
holder.layout.apply {
|
||||||
findViewById<MaterialTextView>(R.id.log_date).text = line.time.toString()
|
findViewById<MaterialTextView>(R.id.log_date).text = line.time.toString()
|
||||||
@ -358,7 +365,8 @@ class LogViewerActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun getType(uri: Uri): String? = logForUri(uri)?.let { "text/plain" }
|
override fun getType(uri: Uri): String? = logForUri(uri)?.let { "text/plain" }
|
||||||
|
|
||||||
override fun getStreamTypes(uri: Uri, mimeTypeFilter: String): Array<String>? = getType(uri)?.let { if (compareMimeTypes(it, mimeTypeFilter)) arrayOf(it) else null }
|
override fun getStreamTypes(uri: Uri, mimeTypeFilter: String): Array<String>? =
|
||||||
|
getType(uri)?.let { if (compareMimeTypes(it, mimeTypeFilter)) arrayOf(it) else null }
|
||||||
|
|
||||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
||||||
if (mode != "r") return null
|
if (mode != "r") return null
|
||||||
|
@ -77,6 +77,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
|
|||||||
onBackPressedDispatcher.onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_action_edit -> {
|
R.id.menu_action_edit -> {
|
||||||
supportFragmentManager.commit {
|
supportFragmentManager.commit {
|
||||||
replace(R.id.detail_container, TunnelEditorFragment())
|
replace(R.id.detail_container, TunnelEditorFragment())
|
||||||
@ -91,12 +92,15 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
|
|||||||
startActivity(Intent(this, SettingsActivity::class.java))
|
startActivity(Intent(this, SettingsActivity::class.java))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?,
|
override fun onSelectedTunnelChanged(
|
||||||
newTunnel: ObservableTunnel?): Boolean {
|
oldTunnel: ObservableTunnel?,
|
||||||
|
newTunnel: ObservableTunnel?
|
||||||
|
): Boolean {
|
||||||
val fragmentManager = supportFragmentManager
|
val fragmentManager = supportFragmentManager
|
||||||
if (fragmentManager.isStateSaved) {
|
if (fragmentManager.isStateSaved) {
|
||||||
return false
|
return false
|
||||||
|
@ -24,7 +24,8 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
class TunnelToggleActivity : AppCompatActivity() {
|
class TunnelToggleActivity : AppCompatActivity() {
|
||||||
private val permissionActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { toggleTunnelWithPermissionsResult() }
|
private val permissionActivityResultLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { toggleTunnelWithPermissionsResult() }
|
||||||
|
|
||||||
private fun toggleTunnelWithPermissionsResult() {
|
private fun toggleTunnelWithPermissionsResult() {
|
||||||
val tunnel = Application.getTunnelManager().lastUsedTunnel ?: return
|
val tunnel = Application.getTunnelManager().lastUsedTunnel ?: return
|
||||||
|
@ -211,7 +211,8 @@ class TvMainActivity : AppCompatActivity() {
|
|||||||
try {
|
try {
|
||||||
tunnelFileImportResultLauncher.launch("*/*")
|
tunnelFileImportResultLauncher.launch("*/*")
|
||||||
} catch (_: Throwable) {
|
} catch (_: Throwable) {
|
||||||
MaterialAlertDialogBuilder(binding.root.context).setMessage(R.string.tv_no_file_picker).setCancelable(false).setPositiveButton(android.R.string.ok) { _, _ ->
|
MaterialAlertDialogBuilder(binding.root.context).setMessage(R.string.tv_no_file_picker).setCancelable(false)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
try {
|
try {
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://webstoreredirect")))
|
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://webstoreredirect")))
|
||||||
} catch (_: Throwable) {
|
} catch (_: Throwable) {
|
||||||
@ -359,6 +360,7 @@ class TvMainActivity : AppCompatActivity() {
|
|||||||
binding.tunnelList.requestFocus()
|
binding.tunnelList.requestFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filesRoot.get()?.isNotEmpty() == true -> {
|
filesRoot.get()?.isNotEmpty() == true -> {
|
||||||
files.clear()
|
files.clear()
|
||||||
filesRoot.set("")
|
filesRoot.set("")
|
||||||
|
@ -47,9 +47,11 @@ object BindingAdapters {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@BindingAdapter("items", "layout", "fragment")
|
@BindingAdapter("items", "layout", "fragment")
|
||||||
fun <E> setItems(view: LinearLayout,
|
fun <E> setItems(
|
||||||
|
view: LinearLayout,
|
||||||
oldList: ObservableList<E>?, oldLayoutId: Int, @Suppress("UNUSED_PARAMETER") oldFragment: Fragment?,
|
oldList: ObservableList<E>?, oldLayoutId: Int, @Suppress("UNUSED_PARAMETER") oldFragment: Fragment?,
|
||||||
newList: ObservableList<E>?, newLayoutId: Int, newFragment: Fragment?) {
|
newList: ObservableList<E>?, newLayoutId: Int, newFragment: Fragment?
|
||||||
|
) {
|
||||||
if (oldList === newList && oldLayoutId == newLayoutId)
|
if (oldList === newList && oldLayoutId == newLayoutId)
|
||||||
return
|
return
|
||||||
var listener: ItemChangeListener<E>? = ListenerUtil.getListener(view, R.id.item_change_listener)
|
var listener: ItemChangeListener<E>? = ListenerUtil.getListener(view, R.id.item_change_listener)
|
||||||
@ -73,9 +75,11 @@ object BindingAdapters {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@BindingAdapter("items", "layout")
|
@BindingAdapter("items", "layout")
|
||||||
fun <E> setItems(view: LinearLayout,
|
fun <E> setItems(
|
||||||
|
view: LinearLayout,
|
||||||
oldList: Iterable<E>?, oldLayoutId: Int,
|
oldList: Iterable<E>?, oldLayoutId: Int,
|
||||||
newList: Iterable<E>?, newLayoutId: Int) {
|
newList: Iterable<E>?, newLayoutId: Int
|
||||||
|
) {
|
||||||
if (oldList === newList && oldLayoutId == newLayoutId)
|
if (oldList === newList && oldLayoutId == newLayoutId)
|
||||||
return
|
return
|
||||||
view.removeAllViews()
|
view.removeAllViews()
|
||||||
@ -93,11 +97,13 @@ object BindingAdapters {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@BindingAdapter(requireAll = false, value = ["items", "layout", "configurationHandler"])
|
@BindingAdapter(requireAll = false, value = ["items", "layout", "configurationHandler"])
|
||||||
fun <K, E : Keyed<out K>> setItems(view: RecyclerView,
|
fun <K, E : Keyed<out K>> setItems(
|
||||||
|
view: RecyclerView,
|
||||||
oldList: ObservableKeyedArrayList<K, E>?, oldLayoutId: Int,
|
oldList: ObservableKeyedArrayList<K, E>?, oldLayoutId: Int,
|
||||||
@Suppress("UNUSED_PARAMETER") oldRowConfigurationHandler: RowConfigurationHandler<*, *>?,
|
@Suppress("UNUSED_PARAMETER") oldRowConfigurationHandler: RowConfigurationHandler<*, *>?,
|
||||||
newList: ObservableKeyedArrayList<K, E>?, newLayoutId: Int,
|
newList: ObservableKeyedArrayList<K, E>?, newLayoutId: Int,
|
||||||
newRowConfigurationHandler: RowConfigurationHandler<*, *>?) {
|
newRowConfigurationHandler: RowConfigurationHandler<*, *>?
|
||||||
|
) {
|
||||||
if (view.layoutManager == null)
|
if (view.layoutManager == null)
|
||||||
view.layoutManager = LinearLayoutManager(view.context, RecyclerView.VERTICAL, false)
|
view.layoutManager = LinearLayoutManager(view.context, RecyclerView.VERTICAL, false)
|
||||||
if (oldList === newList && oldLayoutId == newLayoutId)
|
if (oldList === newList && oldLayoutId == newLayoutId)
|
||||||
@ -123,16 +129,20 @@ object BindingAdapters {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@BindingAdapter("onBeforeCheckedChanged")
|
@BindingAdapter("onBeforeCheckedChanged")
|
||||||
fun setOnBeforeCheckedChanged(view: ToggleSwitch,
|
fun setOnBeforeCheckedChanged(
|
||||||
listener: OnBeforeCheckedChangeListener?) {
|
view: ToggleSwitch,
|
||||||
|
listener: OnBeforeCheckedChangeListener?
|
||||||
|
) {
|
||||||
view.setOnBeforeCheckedChangeListener(listener)
|
view.setOnBeforeCheckedChangeListener(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@BindingAdapter("onFocusChange")
|
@BindingAdapter("onFocusChange")
|
||||||
fun setOnFocusChange(view: EditText,
|
fun setOnFocusChange(
|
||||||
listener: View.OnFocusChangeListener?) {
|
view: EditText,
|
||||||
view.setOnFocusChangeListener(listener)
|
listener: View.OnFocusChangeListener?
|
||||||
|
) {
|
||||||
|
view.onFocusChangeListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -61,8 +61,10 @@ internal class ItemChangeListener<T>(private val container: ViewGroup, private v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeChanged(sender: ObservableList<T>, positionStart: Int,
|
override fun onItemRangeChanged(
|
||||||
itemCount: Int) {
|
sender: ObservableList<T>, positionStart: Int,
|
||||||
|
itemCount: Int
|
||||||
|
) {
|
||||||
val listener = weakListener.get()
|
val listener = weakListener.get()
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
for (i in positionStart until positionStart + itemCount) {
|
for (i in positionStart until positionStart + itemCount) {
|
||||||
@ -75,8 +77,10 @@ internal class ItemChangeListener<T>(private val container: ViewGroup, private v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeInserted(sender: ObservableList<T>, positionStart: Int,
|
override fun onItemRangeInserted(
|
||||||
itemCount: Int) {
|
sender: ObservableList<T>, positionStart: Int,
|
||||||
|
itemCount: Int
|
||||||
|
) {
|
||||||
val listener = weakListener.get()
|
val listener = weakListener.get()
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
for (i in positionStart until positionStart + itemCount)
|
for (i in positionStart until positionStart + itemCount)
|
||||||
@ -86,8 +90,10 @@ internal class ItemChangeListener<T>(private val container: ViewGroup, private v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeMoved(sender: ObservableList<T>, fromPosition: Int,
|
override fun onItemRangeMoved(
|
||||||
toPosition: Int, itemCount: Int) {
|
sender: ObservableList<T>, fromPosition: Int,
|
||||||
|
toPosition: Int, itemCount: Int
|
||||||
|
) {
|
||||||
val listener = weakListener.get()
|
val listener = weakListener.get()
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
val views = arrayOfNulls<View>(itemCount)
|
val views = arrayOfNulls<View>(itemCount)
|
||||||
@ -99,8 +105,10 @@ internal class ItemChangeListener<T>(private val container: ViewGroup, private v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeRemoved(sender: ObservableList<T>, positionStart: Int,
|
override fun onItemRangeRemoved(
|
||||||
itemCount: Int) {
|
sender: ObservableList<T>, positionStart: Int,
|
||||||
|
itemCount: Int
|
||||||
|
) {
|
||||||
val listener = weakListener.get()
|
val listener = weakListener.get()
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.container.removeViews(positionStart, itemCount)
|
listener.container.removeViews(positionStart, itemCount)
|
||||||
|
@ -49,7 +49,8 @@ class AppListDialogFragment : DialogFragment() {
|
|||||||
packageInfos.forEach {
|
packageInfos.forEach {
|
||||||
val packageName = it.packageName
|
val packageName = it.packageName
|
||||||
val appInfo = it.applicationInfo
|
val appInfo = it.applicationInfo
|
||||||
val appData = ApplicationData(appInfo.loadIcon(pm), appInfo.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
|
val appData =
|
||||||
|
ApplicationData(appInfo.loadIcon(pm), appInfo.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
|
||||||
applicationData.add(appData)
|
applicationData.add(appData)
|
||||||
appData.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
|
appData.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
|
||||||
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
|
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
|
||||||
@ -143,10 +144,12 @@ class AppListDialogFragment : DialogFragment() {
|
|||||||
selectedApps.add(data.packageName)
|
selectedApps.add(data.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setFragmentResult(REQUEST_SELECTION, bundleOf(
|
setFragmentResult(
|
||||||
|
REQUEST_SELECTION, bundleOf(
|
||||||
KEY_SELECTED_APPS to selectedApps.toTypedArray(),
|
KEY_SELECTED_APPS to selectedApps.toTypedArray(),
|
||||||
KEY_IS_EXCLUDED to (tabs?.selectedTabPosition == 0)
|
KEY_IS_EXCLUDED to (tabs?.selectedTabPosition == 0)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ class ConfigNamingDialogFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val configText = requireArguments().getString(KEY_CONFIG_TEXT)
|
val configText = requireArguments().getString(KEY_CONFIG_TEXT)
|
||||||
|
@ -40,8 +40,10 @@ class TunnelDetailFragment : BaseFragment(), MenuProvider {
|
|||||||
menuInflater.inflate(R.menu.tunnel_detail, menu)
|
menuInflater.inflate(R.menu.tunnel_detail, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
override fun onCreateView(
|
||||||
savedInstanceState: Bundle?): View? {
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
super.onCreateView(inflater, container, savedInstanceState)
|
super.onCreateView(inflater, container, savedInstanceState)
|
||||||
binding = TunnelDetailFragmentBinding.inflate(inflater, container, false)
|
binding = TunnelDetailFragmentBinding.inflate(inflater, container, false)
|
||||||
binding?.executePendingBindings()
|
binding?.executePendingBindings()
|
||||||
@ -117,9 +119,11 @@ class TunnelDetailFragment : BaseFragment(), MenuProvider {
|
|||||||
peer.transferLabel.visibility = View.GONE
|
peer.transferLabel.visibility = View.GONE
|
||||||
peer.transferText.visibility = View.GONE
|
peer.transferText.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
peer.transferText.text = getString(R.string.transfer_rx_tx,
|
peer.transferText.text = getString(
|
||||||
|
R.string.transfer_rx_tx,
|
||||||
QuantityFormatter.formatBytes(peerStats.rxBytes),
|
QuantityFormatter.formatBytes(peerStats.rxBytes),
|
||||||
QuantityFormatter.formatBytes(peerStats.txBytes))
|
QuantityFormatter.formatBytes(peerStats.txBytes)
|
||||||
|
)
|
||||||
peer.transferLabel.visibility = View.VISIBLE
|
peer.transferLabel.visibility = View.VISIBLE
|
||||||
peer.transferText.visibility = View.VISIBLE
|
peer.transferText.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package com.wireguard.android.fragment
|
package com.wireguard.android.fragment
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@ -67,16 +66,14 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
menuInflater.inflate(R.menu.config_editor, menu)
|
menuInflater.inflate(R.menu.config_editor, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
override fun onCreateView(
|
||||||
savedInstanceState: Bundle?): View? {
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
super.onCreateView(inflater, container, savedInstanceState)
|
super.onCreateView(inflater, container, savedInstanceState)
|
||||||
binding = TunnelEditorFragmentBinding.inflate(inflater, container, false)
|
binding = TunnelEditorFragmentBinding.inflate(inflater, container, false)
|
||||||
binding?.apply {
|
binding?.apply {
|
||||||
@ -103,8 +100,10 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
val focusedView = activity.currentFocus
|
val focusedView = activity.currentFocus
|
||||||
if (focusedView != null) {
|
if (focusedView != null) {
|
||||||
val inputManager = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
val inputManager = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||||
inputManager?.hideSoftInputFromWindow(focusedView.windowToken,
|
inputManager?.hideSoftInputFromWindow(
|
||||||
InputMethodManager.HIDE_NOT_ALWAYS)
|
focusedView.windowToken,
|
||||||
|
InputMethodManager.HIDE_NOT_ALWAYS
|
||||||
|
)
|
||||||
}
|
}
|
||||||
parentFragmentManager.popBackStackImmediate()
|
parentFragmentManager.popBackStackImmediate()
|
||||||
|
|
||||||
@ -138,6 +137,7 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
onTunnelCreated(null, e)
|
onTunnelCreated(null, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnel!!.name != binding!!.name -> {
|
tunnel!!.name != binding!!.name -> {
|
||||||
Log.d(TAG, "Attempting to rename tunnel to " + binding!!.name)
|
Log.d(TAG, "Attempting to rename tunnel to " + binding!!.name)
|
||||||
try {
|
try {
|
||||||
@ -147,6 +147,7 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
onTunnelRenamed(tunnel!!, newConfig, e)
|
onTunnelRenamed(tunnel!!, newConfig, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Log.d(TAG, "Attempting to save config of " + tunnel!!.name)
|
Log.d(TAG, "Attempting to save config of " + tunnel!!.name)
|
||||||
try {
|
try {
|
||||||
@ -202,8 +203,10 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?,
|
override fun onSelectedTunnelChanged(
|
||||||
newTunnel: ObservableTunnel?) {
|
oldTunnel: ObservableTunnel?,
|
||||||
|
newTunnel: ObservableTunnel?
|
||||||
|
) {
|
||||||
tunnel = newTunnel
|
tunnel = newTunnel
|
||||||
if (binding == null) return
|
if (binding == null) return
|
||||||
binding!!.config = ConfigProxy()
|
binding!!.config = ConfigProxy()
|
||||||
@ -240,8 +243,10 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onTunnelRenamed(renamedTunnel: ObservableTunnel, newConfig: Config,
|
private suspend fun onTunnelRenamed(
|
||||||
throwable: Throwable?) {
|
renamedTunnel: ObservableTunnel, newConfig: Config,
|
||||||
|
throwable: Throwable?
|
||||||
|
) {
|
||||||
val ctx = activity ?: Application.get()
|
val ctx = activity ?: Application.get()
|
||||||
if (throwable == null) {
|
if (throwable == null) {
|
||||||
val message = ctx.getString(R.string.tunnel_rename_success, renamedTunnel.name)
|
val message = ctx.getString(R.string.tunnel_rename_success, renamedTunnel.name)
|
||||||
@ -298,6 +303,7 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
haveShownKeys = true
|
haveShownKeys = true
|
||||||
showPrivateKey(edit)
|
showPrivateKey(edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
is BiometricAuthenticator.Result.Failure -> {
|
is BiometricAuthenticator.Result.Failure -> {
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
binding!!.mainContainer,
|
binding!!.mainContainer,
|
||||||
@ -305,6 +311,7 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
|
|||||||
Snackbar.LENGTH_SHORT
|
Snackbar.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
is BiometricAuthenticator.Result.Cancelled -> {}
|
is BiometricAuthenticator.Result.Cancelled -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,8 +91,10 @@ class TunnelListFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
override fun onCreateView(
|
||||||
savedInstanceState: Bundle?): View? {
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
super.onCreateView(inflater, container, savedInstanceState)
|
super.onCreateView(inflater, container, savedInstanceState)
|
||||||
binding = TunnelListFragmentBinding.inflate(inflater, container, false)
|
binding = TunnelListFragmentBinding.inflate(inflater, container, false)
|
||||||
val bottomSheet = AddTunnelsSheet()
|
val bottomSheet = AddTunnelsSheet()
|
||||||
@ -105,14 +107,18 @@ class TunnelListFragment : BaseFragment() {
|
|||||||
AddTunnelsSheet.REQUEST_CREATE -> {
|
AddTunnelsSheet.REQUEST_CREATE -> {
|
||||||
startActivity(Intent(requireActivity(), TunnelCreatorActivity::class.java))
|
startActivity(Intent(requireActivity(), TunnelCreatorActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
AddTunnelsSheet.REQUEST_IMPORT -> {
|
AddTunnelsSheet.REQUEST_IMPORT -> {
|
||||||
tunnelFileImportResultLauncher.launch("*/*")
|
tunnelFileImportResultLauncher.launch("*/*")
|
||||||
}
|
}
|
||||||
|
|
||||||
AddTunnelsSheet.REQUEST_SCAN -> {
|
AddTunnelsSheet.REQUEST_SCAN -> {
|
||||||
qrImportResultLauncher.launch(ScanOptions()
|
qrImportResultLauncher.launch(
|
||||||
|
ScanOptions()
|
||||||
.setOrientationLocked(false)
|
.setOrientationLocked(false)
|
||||||
.setBeepEnabled(false)
|
.setBeepEnabled(false)
|
||||||
.setPrompt(getString(R.string.qr_code_hint)))
|
.setPrompt(getString(R.string.qr_code_hint))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,6 +240,7 @@ class TunnelListFragment : BaseFragment() {
|
|||||||
mode.finish()
|
mode.finish()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_action_select_all -> {
|
R.id.menu_action_select_all -> {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val tunnels = Application.getTunnelManager().getTunnels()
|
val tunnels = Application.getTunnelManager().getTunnels()
|
||||||
@ -243,6 +250,7 @@ class TunnelListFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,8 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
|
|||||||
if (previouslyRunning.isEmpty()) return
|
if (previouslyRunning.isEmpty()) return
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
tunnelMap.filter { previouslyRunning.contains(it.name) }.map { async(Dispatchers.IO + SupervisorJob()) { setTunnelState(it, Tunnel.State.UP) } }.awaitAll()
|
tunnelMap.filter { previouslyRunning.contains(it.name) }.map { async(Dispatchers.IO + SupervisorJob()) { setTunnelState(it, Tunnel.State.UP) } }
|
||||||
|
.awaitAll()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
Log.e(TAG, Log.getStackTraceString(e))
|
Log.e(TAG, Log.getStackTraceString(e))
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,15 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
|
|||||||
Log.e(TAG, message, e)
|
Log.e(TAG, message, e)
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
activity.findViewById(android.R.id.content),
|
activity.findViewById(android.R.id.content),
|
||||||
message, Snackbar.LENGTH_LONG).show()
|
message, Snackbar.LENGTH_LONG
|
||||||
|
).show()
|
||||||
isEnabled = true
|
isEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSummary() = if (exportedFilePath == null) context.getString(R.string.zip_export_summary) else context.getString(R.string.zip_export_success, exportedFilePath)
|
override fun getSummary() =
|
||||||
|
if (exportedFilePath == null) context.getString(R.string.zip_export_summary) else context.getString(R.string.zip_export_success, exportedFilePath)
|
||||||
|
|
||||||
override fun getTitle() = context.getString(R.string.zip_export_title)
|
override fun getTitle() = context.getString(R.string.zip_export_title)
|
||||||
|
|
||||||
@ -91,6 +93,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
|
|||||||
isEnabled = false
|
isEnabled = false
|
||||||
exportZip()
|
exportZip()
|
||||||
}
|
}
|
||||||
|
|
||||||
is BiometricAuthenticator.Result.Failure -> {
|
is BiometricAuthenticator.Result.Failure -> {
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
activity.findViewById(android.R.id.content),
|
activity.findViewById(android.R.id.content),
|
||||||
@ -98,6 +101,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
|
|||||||
Snackbar.LENGTH_SHORT
|
Snackbar.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
is BiometricAuthenticator.Result.Cancelled -> {}
|
is BiometricAuthenticator.Result.Cancelled -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,7 @@ object SnackbarUpdateShower {
|
|||||||
override fun onDismissed(snackbar: Snackbar?, @DismissEvent event: Int) {
|
override fun onDismissed(snackbar: Snackbar?, @DismissEvent event: Int) {
|
||||||
super.onDismissed(snackbar, event)
|
super.onDismissed(snackbar, event)
|
||||||
if (event == DISMISS_EVENT_MANUAL || event == DISMISS_EVENT_ACTION ||
|
if (event == DISMISS_EVENT_MANUAL || event == DISMISS_EVENT_ACTION ||
|
||||||
(snackbar == actionSnackbar && !showingAction) ||
|
(snackbar == actionSnackbar && !showingAction) || (snackbar == statusSnackbar && !showingStatus)
|
||||||
(snackbar == statusSnackbar && !showingStatus)
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
activity.lifecycleScope.launch {
|
activity.lifecycleScope.launch {
|
||||||
@ -106,10 +105,7 @@ object SnackbarUpdateShower {
|
|||||||
snackbar.dismiss()
|
snackbar.dismiss()
|
||||||
|
|
||||||
is Updater.Progress.Available ->
|
is Updater.Progress.Available ->
|
||||||
snackbar.showAction(
|
snackbar.showAction(context.getString(R.string.updater_avalable), context.getString(R.string.updater_action)) {
|
||||||
context.getString(R.string.updater_avalable),
|
|
||||||
context.getString(R.string.updater_action)
|
|
||||||
) {
|
|
||||||
progress.update()
|
progress.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,12 +141,7 @@ object SnackbarUpdateShower {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is Updater.Progress.Failure -> {
|
is Updater.Progress.Failure -> {
|
||||||
snackbar.showText(
|
snackbar.showText( context.getString(R.string.updater_failure, ErrorMessages[progress.error]))
|
||||||
context.getString(
|
|
||||||
R.string.updater_failure,
|
|
||||||
ErrorMessages[progress.error]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
delay(5.seconds)
|
delay(5.seconds)
|
||||||
progress.retry()
|
progress.retry()
|
||||||
}
|
}
|
||||||
|
@ -44,13 +44,11 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
|
|
||||||
object Updater {
|
object Updater {
|
||||||
private const val TAG = "WireGuard/Updater"
|
private const val TAG = "WireGuard/Updater"
|
||||||
private const val LATEST_VERSION_URL =
|
private const val LATEST_VERSION_URL = "https://download.wireguard.com/android-client/latest.sig"
|
||||||
"https://download.wireguard.com/android-client/latest.sig"
|
|
||||||
private const val APK_PATH_URL = "https://download.wireguard.com/android-client/%s"
|
private const val APK_PATH_URL = "https://download.wireguard.com/android-client/%s"
|
||||||
private val APK_NAME_PREFIX = BuildConfig.APPLICATION_ID.removeSuffix(".debug") + "-"
|
private val APK_NAME_PREFIX = BuildConfig.APPLICATION_ID.removeSuffix(".debug") + "-"
|
||||||
private const val APK_NAME_SUFFIX = ".apk"
|
private const val APK_NAME_SUFFIX = ".apk"
|
||||||
private const val RELEASE_PUBLIC_KEY_BASE64 =
|
private const val RELEASE_PUBLIC_KEY_BASE64 = "RWTAzwGRYr3EC9px0Ia3fbttz8WcVN6wrOwWp2delz4el6SI8XmkKSMp"
|
||||||
"RWTAzwGRYr3EC9px0Ia3fbttz8WcVN6wrOwWp2delz4el6SI8XmkKSMp"
|
|
||||||
private val CURRENT_VERSION = Version(BuildConfig.VERSION_NAME.removeSuffix("-debug"))
|
private val CURRENT_VERSION = Version(BuildConfig.VERSION_NAME.removeSuffix("-debug"))
|
||||||
|
|
||||||
private val updaterScope = CoroutineScope(Job() + Dispatchers.IO)
|
private val updaterScope = CoroutineScope(Job() + Dispatchers.IO)
|
||||||
@ -219,12 +217,7 @@ object Updater {
|
|||||||
val receiver = InstallReceiver()
|
val receiver = InstallReceiver()
|
||||||
val context = Application.get().applicationContext
|
val context = Application.get().applicationContext
|
||||||
val pendingIntent = withContext(Dispatchers.Main) {
|
val pendingIntent = withContext(Dispatchers.Main) {
|
||||||
ContextCompat.registerReceiver(
|
ContextCompat.registerReceiver(context, receiver, IntentFilter(receiver.sessionId), ContextCompat.RECEIVER_NOT_EXPORTED)
|
||||||
context,
|
|
||||||
receiver,
|
|
||||||
IntentFilter(receiver.sessionId),
|
|
||||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
|
||||||
)
|
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
0,
|
0,
|
||||||
@ -241,24 +234,20 @@ object Updater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emitProgress(Progress.Downloading(0UL, 0UL), true)
|
emitProgress(Progress.Downloading(0UL, 0UL), true)
|
||||||
val connection =
|
val connection = URL(APK_PATH_URL.format(update.fileName)).openConnection() as HttpURLConnection
|
||||||
URL(APK_PATH_URL.format(update.fileName)).openConnection() as HttpURLConnection
|
|
||||||
connection.setRequestProperty("User-Agent", Application.USER_AGENT)
|
connection.setRequestProperty("User-Agent", Application.USER_AGENT)
|
||||||
connection.connect()
|
connection.connect()
|
||||||
if (connection.responseCode != HttpURLConnection.HTTP_OK)
|
if (connection.responseCode != HttpURLConnection.HTTP_OK)
|
||||||
throw IOException("Update could not be fetched: ${connection.responseCode}")
|
throw IOException("Update could not be fetched: ${connection.responseCode}")
|
||||||
|
|
||||||
var downloadedByteLen: ULong = 0UL
|
var downloadedByteLen: ULong = 0UL
|
||||||
val totalByteLen =
|
val totalByteLen = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) connection.contentLengthLong else connection.contentLength).toLong().toULong()
|
||||||
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) connection.contentLengthLong else connection.contentLength).toLong()
|
|
||||||
.toULong()
|
|
||||||
val fileBytes = ByteArray(1024 * 32 /* 32 KiB */)
|
val fileBytes = ByteArray(1024 * 32 /* 32 KiB */)
|
||||||
val digest = MessageDigest.getInstance("SHA-256")
|
val digest = MessageDigest.getInstance("SHA-256")
|
||||||
emitProgress(Progress.Downloading(downloadedByteLen, totalByteLen), true)
|
emitProgress(Progress.Downloading(downloadedByteLen, totalByteLen), true)
|
||||||
|
|
||||||
val installer = context.packageManager.packageInstaller
|
val installer = context.packageManager.packageInstaller
|
||||||
val params =
|
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
|
||||||
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||||
params.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)
|
params.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)
|
||||||
params.setAppPackageName(context.packageName) /* Enforces updates; disallows new apps. */
|
params.setAppPackageName(context.packageName) /* Enforces updates; disallows new apps. */
|
||||||
@ -316,18 +305,10 @@ object Updater {
|
|||||||
if (sessionId != intent.action)
|
if (sessionId != intent.action)
|
||||||
return
|
return
|
||||||
|
|
||||||
when (val status =
|
when (val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE_INVALID)) {
|
||||||
intent.getIntExtra(
|
|
||||||
PackageInstaller.EXTRA_STATUS,
|
|
||||||
PackageInstaller.STATUS_FAILURE_INVALID
|
|
||||||
)) {
|
|
||||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||||
val id = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, 0)
|
val id = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, 0)
|
||||||
val userIntervention = IntentCompat.getParcelableExtra(
|
val userIntervention = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_INTENT, Intent::class.java)!!
|
||||||
intent,
|
|
||||||
Intent.EXTRA_INTENT,
|
|
||||||
Intent::class.java
|
|
||||||
)!!
|
|
||||||
Application.getCoroutineScope().launch {
|
Application.getCoroutineScope().launch {
|
||||||
emitProgress(Progress.NeedsUserIntervention(userIntervention, id))
|
emitProgress(Progress.NeedsUserIntervention(userIntervention, id))
|
||||||
}
|
}
|
||||||
@ -346,9 +327,7 @@ object Updater {
|
|||||||
context.applicationContext.packageManager.packageInstaller.abandonSession(id)
|
context.applicationContext.packageManager.packageInstaller.abandonSession(id)
|
||||||
} catch (_: SecurityException) {
|
} catch (_: SecurityException) {
|
||||||
}
|
}
|
||||||
val message =
|
val message = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) ?: "Installation error $status"
|
||||||
intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
|
|
||||||
?: "Installation error $status"
|
|
||||||
Application.getCoroutineScope().launch {
|
Application.getCoroutineScope().launch {
|
||||||
val e = Exception(message)
|
val e = Exception(message)
|
||||||
Log.e(TAG, "Update failure", e)
|
Log.e(TAG, "Update failure", e)
|
||||||
@ -365,9 +344,7 @@ object Updater {
|
|||||||
return
|
return
|
||||||
|
|
||||||
updaterScope.launch {
|
updaterScope.launch {
|
||||||
if (UserKnobs.updaterNewerVersionSeen.firstOrNull()
|
if (UserKnobs.updaterNewerVersionSeen.firstOrNull()?.let { Version(it) > CURRENT_VERSION } == true)
|
||||||
?.let { Version(it) > CURRENT_VERSION } == true
|
|
||||||
)
|
|
||||||
return@launch
|
return@launch
|
||||||
|
|
||||||
var waitTime = 15
|
var waitTime = 15
|
||||||
@ -387,8 +364,10 @@ object Updater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UserKnobs.updaterNewerVersionSeen.onEach { ver ->
|
UserKnobs.updaterNewerVersionSeen.onEach { ver ->
|
||||||
if (ver != null && Version(ver) > CURRENT_VERSION && UserKnobs.updaterNewerVersionConsented.firstOrNull()
|
if (
|
||||||
?.let { Version(it) > CURRENT_VERSION } != true
|
ver != null &&
|
||||||
|
Version(ver) > CURRENT_VERSION &&
|
||||||
|
UserKnobs.updaterNewerVersionConsented.firstOrNull()?.let { Version(it) > CURRENT_VERSION } != true
|
||||||
)
|
)
|
||||||
emitProgress(Progress.Available(ver))
|
emitProgress(Progress.Available(ver))
|
||||||
}.launchIn(Application.getCoroutineScope())
|
}.launchIn(Application.getCoroutineScope())
|
||||||
|
@ -39,17 +39,21 @@ object BiometricAuthenticator {
|
|||||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
super.onAuthenticationError(errorCode, errString)
|
super.onAuthenticationError(errorCode, errString)
|
||||||
Log.d(TAG, "BiometricAuthentication error: errorCode=$errorCode, msg=$errString")
|
Log.d(TAG, "BiometricAuthentication error: errorCode=$errorCode, msg=$errString")
|
||||||
callback(when (errorCode) {
|
callback(
|
||||||
|
when (errorCode) {
|
||||||
BiometricPrompt.ERROR_CANCELED, BiometricPrompt.ERROR_USER_CANCELED,
|
BiometricPrompt.ERROR_CANCELED, BiometricPrompt.ERROR_USER_CANCELED,
|
||||||
BiometricPrompt.ERROR_NEGATIVE_BUTTON -> {
|
BiometricPrompt.ERROR_NEGATIVE_BUTTON -> {
|
||||||
Result.Cancelled
|
Result.Cancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
BiometricPrompt.ERROR_HW_NOT_PRESENT, BiometricPrompt.ERROR_HW_UNAVAILABLE,
|
BiometricPrompt.ERROR_HW_NOT_PRESENT, BiometricPrompt.ERROR_HW_UNAVAILABLE,
|
||||||
BiometricPrompt.ERROR_NO_BIOMETRICS, BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> {
|
BiometricPrompt.ERROR_NO_BIOMETRICS, BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> {
|
||||||
Result.HardwareUnavailableOrDisabled
|
Result.HardwareUnavailableOrDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Result.Failure(errorCode, fragment.getString(R.string.biometric_auth_error_reason, errString))
|
else -> Result.Failure(errorCode, fragment.getString(R.string.biometric_auth_error_reason, errString))
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAuthenticationFailed() {
|
override fun onAuthenticationFailed() {
|
||||||
|
@ -80,21 +80,27 @@ object ErrorMessages {
|
|||||||
val explanation = getBadConfigExceptionExplanation(resources, rootCause)
|
val explanation = getBadConfigExceptionExplanation(resources, rootCause)
|
||||||
resources.getString(R.string.bad_config_error, reason, context) + explanation
|
resources.getString(R.string.bad_config_error, reason, context) + explanation
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCause is BackendException -> {
|
rootCause is BackendException -> {
|
||||||
resources.getString(BE_REASON_MAP.getValue(rootCause.reason), *rootCause.format)
|
resources.getString(BE_REASON_MAP.getValue(rootCause.reason), *rootCause.format)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCause is RootShellException -> {
|
rootCause is RootShellException -> {
|
||||||
resources.getString(RSE_REASON_MAP.getValue(rootCause.reason), *rootCause.format)
|
resources.getString(RSE_REASON_MAP.getValue(rootCause.reason), *rootCause.format)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCause is NotFoundException -> {
|
rootCause is NotFoundException -> {
|
||||||
resources.getString(R.string.error_no_qr_found)
|
resources.getString(R.string.error_no_qr_found)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCause is ChecksumException -> {
|
rootCause is ChecksumException -> {
|
||||||
resources.getString(R.string.error_qr_checksum)
|
resources.getString(R.string.error_qr_checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCause.localizedMessage != null -> {
|
rootCause.localizedMessage != null -> {
|
||||||
rootCause.localizedMessage!!
|
rootCause.localizedMessage!!
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val errorType = rootCause.javaClass.simpleName
|
val errorType = rootCause.javaClass.simpleName
|
||||||
resources.getString(R.string.generic_error, errorType)
|
resources.getString(R.string.generic_error, errorType)
|
||||||
@ -102,8 +108,10 @@ object ErrorMessages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBadConfigExceptionExplanation(resources: Resources,
|
private fun getBadConfigExceptionExplanation(
|
||||||
bce: BadConfigException): String {
|
resources: Resources,
|
||||||
|
bce: BadConfigException
|
||||||
|
): String {
|
||||||
if (bce.cause is KeyFormatException) {
|
if (bce.cause is KeyFormatException) {
|
||||||
val kfe = bce.cause as KeyFormatException?
|
val kfe = bce.cause as KeyFormatException?
|
||||||
if (kfe!!.type == KeyFormatException.Type.LENGTH) return resources.getString(KFE_FORMAT_MAP.getValue(kfe.format))
|
if (kfe!!.type == KeyFormatException.Type.LENGTH) return resources.getString(KFE_FORMAT_MAP.getValue(kfe.format))
|
||||||
@ -120,8 +128,10 @@ object ErrorMessages {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBadConfigExceptionReason(resources: Resources,
|
private fun getBadConfigExceptionReason(
|
||||||
bce: BadConfigException): String {
|
resources: Resources,
|
||||||
|
bce: BadConfigException
|
||||||
|
): String {
|
||||||
if (bce.cause is KeyFormatException) {
|
if (bce.cause is KeyFormatException) {
|
||||||
val kfe = bce.cause as KeyFormatException?
|
val kfe = bce.cause as KeyFormatException?
|
||||||
return resources.getString(KFE_TYPE_MAP.getValue(kfe!!.type))
|
return resources.getString(KFE_TYPE_MAP.getValue(kfe!!.type))
|
||||||
@ -137,7 +147,8 @@ object ErrorMessages {
|
|||||||
var cause = throwable
|
var cause = throwable
|
||||||
while (cause.cause != null) {
|
while (cause.cause != null) {
|
||||||
if (cause is BadConfigException || cause is BackendException ||
|
if (cause is BadConfigException || cause is BackendException ||
|
||||||
cause is RootShellException) break
|
cause is RootShellException
|
||||||
|
) break
|
||||||
val nextCause = cause.cause!!
|
val nextCause = cause.cause!!
|
||||||
if (nextCause is RemoteException) break
|
if (nextCause is RemoteException) break
|
||||||
cause = nextCause
|
cause = nextCause
|
||||||
|
@ -55,11 +55,13 @@ class QrCodeFromFileScanner(
|
|||||||
multFactor = originalWidth.toFloat() / originalHeight.toFloat()
|
multFactor = originalWidth.toFloat() / originalHeight.toFloat()
|
||||||
newWidth = (newHeight * multFactor).toInt()
|
newWidth = (newHeight * multFactor).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
originalWidth > originalHeight -> {
|
originalWidth > originalHeight -> {
|
||||||
newWidth = scaledSize
|
newWidth = scaledSize
|
||||||
multFactor = originalHeight.toFloat() / originalWidth.toFloat()
|
multFactor = originalHeight.toFloat() / originalWidth.toFloat()
|
||||||
newHeight = (newWidth * multFactor).toInt()
|
newHeight = (newWidth * multFactor).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
originalHeight == originalWidth -> {
|
originalHeight == originalWidth -> {
|
||||||
newHeight = scaledSize
|
newHeight = scaledSize
|
||||||
newWidth = scaledSize
|
newWidth = scaledSize
|
||||||
|
@ -15,7 +15,6 @@ import com.wireguard.android.Application
|
|||||||
import com.wireguard.android.R
|
import com.wireguard.android.R
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
import kotlin.time.DurationUnit
|
|
||||||
|
|
||||||
object QuantityFormatter {
|
object QuantityFormatter {
|
||||||
fun formatBytes(bytes: Long): String {
|
fun formatBytes(bytes: Long): String {
|
||||||
|
@ -24,7 +24,6 @@ import java.io.BufferedReader
|
|||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
@ -135,12 +134,16 @@ object TunnelImporter {
|
|||||||
message = context.getString(R.string.import_success, tunnels[0].name)
|
message = context.getString(R.string.import_success, tunnels[0].name)
|
||||||
else if (tunnels.isEmpty() && throwables.size == 1)
|
else if (tunnels.isEmpty() && throwables.size == 1)
|
||||||
else if (throwables.isEmpty())
|
else if (throwables.isEmpty())
|
||||||
message = context.resources.getQuantityString(R.plurals.import_total_success,
|
message = context.resources.getQuantityString(
|
||||||
tunnels.size, tunnels.size)
|
R.plurals.import_total_success,
|
||||||
|
tunnels.size, tunnels.size
|
||||||
|
)
|
||||||
else if (!throwables.isEmpty())
|
else if (!throwables.isEmpty())
|
||||||
message = context.resources.getQuantityString(R.plurals.import_partial_success,
|
message = context.resources.getQuantityString(
|
||||||
|
R.plurals.import_partial_success,
|
||||||
tunnels.size + throwables.size,
|
tunnels.size + throwables.size,
|
||||||
tunnels.size, tunnels.size + throwables.size)
|
tunnels.size, tunnels.size + throwables.size
|
||||||
|
)
|
||||||
|
|
||||||
messageCallback(message)
|
messageCallback(message)
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,6 @@ import com.wireguard.config.Attribute
|
|||||||
import com.wireguard.config.BadConfigException
|
import com.wireguard.config.BadConfigException
|
||||||
import com.wireguard.config.Peer
|
import com.wireguard.config.Peer
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.LinkedHashSet
|
|
||||||
|
|
||||||
class PeerProxy : BaseObservable, Parcelable {
|
class PeerProxy : BaseObservable, Parcelable {
|
||||||
private val dnsRoutes: MutableList<String?> = ArrayList()
|
private val dnsRoutes: MutableList<String?> = ArrayList()
|
||||||
@ -240,24 +238,32 @@ class PeerProxy : BaseObservable, Parcelable {
|
|||||||
peerProxy.setTotalPeers(sender.size)
|
peerProxy.setTotalPeers(sender.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeChanged(sender: ObservableList<PeerProxy?>,
|
override fun onItemRangeChanged(
|
||||||
positionStart: Int, itemCount: Int) {
|
sender: ObservableList<PeerProxy?>,
|
||||||
|
positionStart: Int, itemCount: Int
|
||||||
|
) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeInserted(sender: ObservableList<PeerProxy?>,
|
override fun onItemRangeInserted(
|
||||||
positionStart: Int, itemCount: Int) {
|
sender: ObservableList<PeerProxy?>,
|
||||||
|
positionStart: Int, itemCount: Int
|
||||||
|
) {
|
||||||
onChanged(sender)
|
onChanged(sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeMoved(sender: ObservableList<PeerProxy?>,
|
override fun onItemRangeMoved(
|
||||||
|
sender: ObservableList<PeerProxy?>,
|
||||||
fromPosition: Int, toPosition: Int,
|
fromPosition: Int, toPosition: Int,
|
||||||
itemCount: Int) {
|
itemCount: Int
|
||||||
|
) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemRangeRemoved(sender: ObservableList<PeerProxy?>,
|
override fun onItemRangeRemoved(
|
||||||
positionStart: Int, itemCount: Int) {
|
sender: ObservableList<PeerProxy?>,
|
||||||
|
positionStart: Int, itemCount: Int
|
||||||
|
) {
|
||||||
onChanged(sender)
|
onChanged(sender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,12 @@ import com.wireguard.crypto.Key
|
|||||||
* InputFilter for entering WireGuard private/public keys encoded with base64.
|
* InputFilter for entering WireGuard private/public keys encoded with base64.
|
||||||
*/
|
*/
|
||||||
class KeyInputFilter : InputFilter {
|
class KeyInputFilter : InputFilter {
|
||||||
override fun filter(source: CharSequence,
|
override fun filter(
|
||||||
|
source: CharSequence,
|
||||||
sStart: Int, sEnd: Int,
|
sStart: Int, sEnd: Int,
|
||||||
dest: Spanned,
|
dest: Spanned,
|
||||||
dStart: Int, dEnd: Int): CharSequence? {
|
dStart: Int, dEnd: Int
|
||||||
|
): CharSequence? {
|
||||||
var replacement: SpannableStringBuilder? = null
|
var replacement: SpannableStringBuilder? = null
|
||||||
var rIndex = 0
|
var rIndex = 0
|
||||||
val dLength = dest.length
|
val dLength = dest.length
|
||||||
@ -27,7 +29,8 @@ class KeyInputFilter : InputFilter {
|
|||||||
// Ensure adding this character does not push the length over the limit.
|
// Ensure adding this character does not push the length over the limit.
|
||||||
if ((dIndex + 1 < Key.Format.BASE64.length && isAllowed(c) ||
|
if ((dIndex + 1 < Key.Format.BASE64.length && isAllowed(c) ||
|
||||||
dIndex + 1 == Key.Format.BASE64.length && c == '=') &&
|
dIndex + 1 == Key.Format.BASE64.length && c == '=') &&
|
||||||
dLength + (sIndex - sStart) < Key.Format.BASE64.length) {
|
dLength + (sIndex - sStart) < Key.Format.BASE64.length
|
||||||
|
) {
|
||||||
++rIndex
|
++rIndex
|
||||||
} else {
|
} else {
|
||||||
if (replacement == null) replacement = SpannableStringBuilder(source, sStart, sEnd)
|
if (replacement == null) replacement = SpannableStringBuilder(source, sStart, sEnd)
|
||||||
|
@ -13,10 +13,12 @@ import com.wireguard.android.backend.Tunnel
|
|||||||
* InputFilter for entering WireGuard configuration names (Linux interface names).
|
* InputFilter for entering WireGuard configuration names (Linux interface names).
|
||||||
*/
|
*/
|
||||||
class NameInputFilter : InputFilter {
|
class NameInputFilter : InputFilter {
|
||||||
override fun filter(source: CharSequence,
|
override fun filter(
|
||||||
|
source: CharSequence,
|
||||||
sStart: Int, sEnd: Int,
|
sStart: Int, sEnd: Int,
|
||||||
dest: Spanned,
|
dest: Spanned,
|
||||||
dStart: Int, dEnd: Int): CharSequence? {
|
dStart: Int, dEnd: Int
|
||||||
|
): CharSequence? {
|
||||||
var replacement: SpannableStringBuilder? = null
|
var replacement: SpannableStringBuilder? = null
|
||||||
var rIndex = 0
|
var rIndex = 0
|
||||||
val dLength = dest.length
|
val dLength = dest.length
|
||||||
@ -26,7 +28,8 @@ class NameInputFilter : InputFilter {
|
|||||||
// Restrict characters to those valid in interfaces.
|
// Restrict characters to those valid in interfaces.
|
||||||
// Ensure adding this character does not push the length over the limit.
|
// Ensure adding this character does not push the length over the limit.
|
||||||
if (dIndex < Tunnel.NAME_MAX_LENGTH && isAllowed(c) &&
|
if (dIndex < Tunnel.NAME_MAX_LENGTH && isAllowed(c) &&
|
||||||
dLength + (sIndex - sStart) < Tunnel.NAME_MAX_LENGTH) {
|
dLength + (sIndex - sStart) < Tunnel.NAME_MAX_LENGTH
|
||||||
|
) {
|
||||||
++rIndex
|
++rIndex
|
||||||
} else {
|
} else {
|
||||||
if (replacement == null) replacement = SpannableStringBuilder(source, sStart, sEnd)
|
if (replacement == null) replacement = SpannableStringBuilder(source, sStart, sEnd)
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
app:state_multiselected="true">
|
app:state_multiselected="true">
|
||||||
<color android:color="?attr/colorSurfaceVariant" />
|
<color android:color="?attr/colorSurfaceVariant" />
|
||||||
</item>
|
</item>
|
||||||
<item
|
<item android:state_activated="true">
|
||||||
android:state_activated="true">
|
|
||||||
<color android:color="?attr/colorControlHighlight" />
|
<color android:color="?attr/colorControlHighlight" />
|
||||||
</item>
|
</item>
|
||||||
</selector>
|
</selector>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<import type="com.wireguard.android.widget.NameInputFilter" />
|
<import type="com.wireguard.android.widget.NameInputFilter" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
@ -24,7 +25,8 @@
|
|||||||
android:imeOptions="actionDone"
|
android:imeOptions="actionDone"
|
||||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||||
app:filter="@{NameInputFilter.newInstance()}">
|
app:filter="@{NameInputFilter.newInstance()}">
|
||||||
<requestFocus/>
|
|
||||||
|
<requestFocus />
|
||||||
</com.google.android.material.textfield.TextInputEditText>
|
</com.google.android.material.textfield.TextInputEditText>
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
@ -60,11 +60,11 @@
|
|||||||
android:src="@mipmap/ic_launcher" />
|
android:src="@mipmap/ic_launcher" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_marginStart="@dimen/tunnel_list_placeholder_margin"
|
|
||||||
android:layout_marginEnd="@dimen/tunnel_list_placeholder_margin"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="@dimen/tunnel_list_placeholder_margin"
|
||||||
|
android:layout_marginEnd="@dimen/tunnel_list_placeholder_margin"
|
||||||
android:text="@string/tunnel_list_placeholder"
|
android:text="@string/tunnel_list_placeholder"
|
||||||
android:textSize="20sp" />
|
android:textSize="20sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="WireGuardTheme" parent="Theme.Material3.Dark">
|
<style name="WireGuardTheme" parent="Theme.Material3.Dark">
|
||||||
<item name="colorPrimary">@color/md_theme_dark_primary</item>
|
<item name="colorPrimary">@color/md_theme_dark_primary</item>
|
||||||
<item name="colorOnPrimary">@color/md_theme_dark_onPrimary</item>
|
<item name="colorOnPrimary">@color/md_theme_dark_onPrimary</item>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<style name="AppTheme" parent="AppThemeBase">
|
<style name="AppTheme" parent="AppThemeBase">
|
||||||
<item name="android:statusBarColor">?android:colorBackground</item>
|
<item name="android:statusBarColor">?android:colorBackground</item>
|
||||||
<item name="android:windowLightStatusBar">@bool/light_status_bar</item>
|
<item name="android:windowLightStatusBar">@bool/light_status_bar</item>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<style name="AppTheme" parent="AppThemeBase">
|
<style name="AppTheme" parent="AppThemeBase">
|
||||||
<item name="android:statusBarColor">?android:colorBackground</item>
|
<item name="android:statusBarColor">?android:colorBackground</item>
|
||||||
<item name="android:windowLightStatusBar">@bool/light_status_bar</item>
|
<item name="android:windowLightStatusBar">@bool/light_status_bar</item>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="WireGuardTheme" parent="Theme.Material3.Light">
|
<style name="WireGuardTheme" parent="Theme.Material3.Light">
|
||||||
<item name="colorPrimary">@color/md_theme_light_primary</item>
|
<item name="colorPrimary">@color/md_theme_light_primary</item>
|
||||||
<item name="colorOnPrimary">@color/md_theme_light_onPrimary</item>
|
<item name="colorOnPrimary">@color/md_theme_light_onPrimary</item>
|
||||||
|
@ -40,6 +40,5 @@
|
|||||||
android:summaryOff="@string/allow_remote_control_intents_summary_off"
|
android:summaryOff="@string/allow_remote_control_intents_summary_off"
|
||||||
android:summaryOn="@string/allow_remote_control_intents_summary_on"
|
android:summaryOn="@string/allow_remote_control_intents_summary_on"
|
||||||
android:title="@string/allow_remote_control_intents_title" />
|
android:title="@string/allow_remote_control_intents_title" />
|
||||||
<com.wireguard.android.preference.DonatePreference
|
<com.wireguard.android.preference.DonatePreference android:singleLineTitle="false" />
|
||||||
android:singleLineTitle="false" />
|
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
||||||
|
Loading…
Reference in New Issue
Block a user