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