Compare commits

..

53 Commits

Author SHA1 Message Date
Jason A. Donenfeld e08d873cc3 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-07-24 09:50:31 +02:00
Jason A. Donenfeld 3748a1da88 AdminKnobs: allow enterprise admins to disable private key export
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-07-23 17:35:47 +02:00
Jason A. Donenfeld 9597d719ac build: bump AGP to 4.0.1
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-07-23 16:04:22 +02:00
Harsh Shandilya 041ce2134f build: upgrade to Gradle 6.5.1
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-07-10 15:07:54 +05:30
Harsh Shandilya 4c17fc51e7 gitignore: add gradlew.bat
We do not support building on Windows for now and deleting this file on every wrapper update is just lame

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-06-25 01:36:31 +05:30
Harsh Shandilya 6cf7439053 gradle: upgrade to 6.5
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-06-25 01:36:30 +05:30
Harsh Shandilya 814ab4937d build: bump core-ktx, coroutines and fragments
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-06-25 01:30:00 +05:30
David Crawshaw 3d088411e2 libwg-go: use conn.Bind for socketfd peek
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-06-22 02:24:55 -06:00
Jason A. Donenfeld 39e0c861e2 tools: bump versions
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-06-07 01:58:02 -06:00
Harsh Shandilya d60efcd7c7 strings: sync translations
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-06-02 17:52:01 +05:30
Harsh Shandilya 4dff537d21 ui: address new databinding requirements
Layouts in differing configurations must agree on their root tags, so we give
both copies of main_activity the same root ID, and adjust the check for
two-pane layout to simply test for nullability. This also changes the inset
dispatch code to use ViewCompat and WindowInsetsCompat since they will adjust
insets based on the SDK level allowing us to abstract away that concern.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-05-29 12:25:52 +05:30
Harsh Shandilya 761c2ade4a build: bump to AGP 4.0.0
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-05-29 12:05:24 +05:30
Harsh Shandilya 115a87af32 ui: remove unneeded actionBarPopupTheme attribute
This caused inconsistencies between our overflow icon and actionbar title's tint

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-05-09 15:49:43 +05:30
Harsh Shandilya c7ecaeb145 build: upgrade to gradle 6.4 and track checksum
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-05-09 13:15:57 +05:30
Jason A. Donenfeld 8e2d63db75 tunnel: add windows-style killswitch semantics for GoBackend
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-05-04 02:30:44 -06:00
Harsh Shandilya 3208bac987 build: upgrade to mdc-android 1.2.0-alpha06
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-30 18:21:31 +05:30
Harsh Shandilya fc1f2132fe build: bump gradle wrapper version in task configuration
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-27 14:09:37 +05:30
Harsh Shandilya 09125e1e31 libwg-go: bump go version
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-26 04:33:41 +05:30
Harsh Shandilya 6b1164ad8d ui: switch up dark theme system bars colors
The status bar color had a subtle transparency applied which caused
inconsistencies, and the navigation bar color was the wrong shade of
gray.

Reported-by: Danny Lin <danny@kdrag0n.dev>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-26 04:30:26 +05:30
Harsh Shandilya c68a5c776b build: bump threetenabp to 1.2.4
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-24 19:32:36 +05:30
Harsh Shandilya f3ac787f5a ToolsInstaller: update Magisk directory
/data/adb/modules has been the location for modules since v18.0 and nobody
should reasonably be on any older version anymore. This has continued to
work for this long because Magisk created symlinks for backwards compat. However,
these symlinks are not created anymore on Android 11, which is where this
problem	first surfaced.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-23 01:40:50 +05:30
Harsh Shandilya 751be2c469 build: don't obfuscate code in minify step
While Play Console correctly manages to deobfuscate stacktraces using the
ProGuard mapping, it makes user recorded logs useless which is rather
undesirable.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-21 21:36:59 +05:30
Harsh Shandilya cfb7f1b016 ui: tweak fab animation duration
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-19 02:17:27 +05:30
Harsh Shandilya 33e07628db build: remove unused cardview dependency
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-19 02:09:07 +05:30
Harsh Shandilya b1b7d1d90c build: upgrade AGP, Kotlin, and preference
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-19 02:08:41 +05:30
Harsh Shandilya 6cb9548f72 tunnel: disable LongLogTag lint
Should have been part of the patch that disabled this for ui/

Fixes: 8d128cf2e9 ("ui: disable LongLogTag lint")
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-19 01:59:51 +05:30
Harsh Shandilya 8207ae1e8d strings: sync translations
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-19 01:48:50 +05:30
Harsh Shandilya 48e0e427eb ui: animate fab scale rather than translation
Suggested-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-16 23:14:35 +05:30
Jason A. Donenfeld 03e95d2dd3 ObservableTunnel: account for race in renulling stats
The stats might become null between these two checks, when a tunnel
flips off, resulting in a null pointer dereference:

at com.wireguard.android.model.ObservableTunnel.getStatisticsAsync (ObservableTunnel.java:103)
at com.wireguard.android.fragment.TunnelDetailFragment.updateStats (TunnelDetailFragment.java:108)
at com.wireguard.android.fragment.TunnelDetailFragment.access$updateStats (TunnelDetailFragment.java:27)
at com.wireguard.android.fragment.TunnelDetailFragment$onResume$1.run (TunnelDetailFragment.java:74)
at java.util.TimerThread.mainLoop (TimerThread.java:562)
at java.util.TimerThread.run (TimerThread.java:512)

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-15 01:57:55 -06:00
Harsh Shandilya 58b14cc650 ui: animate fab position in tunnel deletion flow
When tunnel deletion is triggered we don't bother with animation theatrics
because the resulting Snackbar needs this fab to be its anchor, which it can't
do if its outside the screen or busy animating.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-08 19:43:25 +05:30
Harsh Shandilya 3fa8e09545 tunnel: disable BuildConfig generation
We don't (and shouldn't) use BuildConfig values, but the class was
polluting our public API regardless which is undesirable.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-08 17:05:31 +05:30
Jason A. Donenfeld 9d76b354f0 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-08 00:02:37 -06:00
Harsh Shandilya 1856a50c56 strings: sync translations
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-08 03:37:01 +05:30
Harsh Shandilya ba0f3ece04 ui: tweak FABs to use the correct type
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-08 03:34:07 +05:30
Harsh Shandilya e8ad75d924 ui: codestyle nit
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-07 14:19:54 +05:30
Jason A. Donenfeld b858284b1e KernelModuleDisablerPreference: do not make synchronous calls to getBackend
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-07 02:28:34 -06:00
Jason A. Donenfeld 3c6e06f8d5 ui: set proper content description for applications
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 19:25:05 -06:00
Jason A. Donenfeld 0d33a00e72 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 19:09:25 -06:00
Jason A. Donenfeld 830d0992a7 ui: show excluded/included apps in details view
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 19:08:57 -06:00
Jason A. Donenfeld e4192ea172 ui: align listen port and mtu in detail editor
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 18:43:41 -06:00
Jason A. Donenfeld 4bbb1a0fcd ui: add suffix to persistent keepalive in editor
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 18:24:08 -06:00
Jason A. Donenfeld 77b5937fbb ui: add missing fields to detail view
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 18:09:03 -06:00
Jason A. Donenfeld 3144d36056 TunnelListFragment: onCreateActionMode is called before adapter is alive
Long press a tunnel item. SIGKILL the app. Reenter it. Boom:

kotlin.KotlinNullPointerException:
  at com.wireguard.android.fragment.TunnelListFragment$ActionModeListener.onCreateActionMode (TunnelListFragment.java:347)
  at androidx.appcompat.app.AppCompatDelegateImpl$ActionModeCallbackWrapperV9.onCreateActionMode (AppCompatDelegateImpl.java:2442)
  at androidx.appcompat.app.WindowDecorActionBar$ActionModeImpl.dispatchOnCreate (WindowDecorActionBar.java:1062)
  at androidx.appcompat.app.WindowDecorActionBar.startActionMode (WindowDecorActionBar.java:530)
  at androidx.appcompat.app.AppCompatDelegateImpl.startSupportActionMode (AppCompatDelegateImpl.java:1055)
  at androidx.appcompat.app.AppCompatActivity.startSupportActionMode (AppCompatActivity.java:316)
  at com.wireguard.android.fragment.TunnelListFragment$ActionModeListener.setItemChecked (TunnelListFragment.java:371)
  at com.wireguard.android.fragment.TunnelListFragment.onActivityCreated (TunnelListFragment.java:174)
  at androidx.fragment.app.Fragment.performActivityCreated (Fragment.java:2717)
  at androidx.fragment.app.FragmentStateManager.activityCreated (FragmentStateManager.java:346)
  at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:1188)
  at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:161)
  at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:1356)
  at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:5)
  at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState (FragmentManager.java:1434)
  at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState (FragmentManager.java:5)
  at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:1497)
  at androidx.fragment.app.FragmentManager.moveToState (FragmentManager.java:389)
  at androidx.fragment.app.FragmentManager.dispatchStateChange (FragmentManager.java:2625)
  at androidx.fragment.app.FragmentManager.dispatchStateChange (FragmentManager.java:677)
  at androidx.fragment.app.FragmentManager.dispatchActivityCreated (FragmentManager.java:2577)
  at androidx.fragment.app.FragmentManager.dispatchActivityCreated (FragmentManager.java:9)
  at androidx.fragment.app.FragmentController.dispatchActivityCreated (FragmentController.java:247)
  at androidx.fragment.app.FragmentActivity.onStart (FragmentActivity.java:541)
  at androidx.appcompat.app.AppCompatActivity.onStart (AppCompatActivity.java:201)
  at android.app.Instrumentation.callActivityOnStart (Instrumentation.java:1440)
  at android.app.Activity.performStart (Activity.java:8109)
  at android.app.ActivityThread.handleStartActivity (ActivityThread.java:3806)
  at android.app.servertransaction.TransactionExecutor.performLifecycleSequence (TransactionExecutor.java:235)
  at android.app.servertransaction.TransactionExecutor.cycleToPath (TransactionExecutor.java:215)
  at android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:187)
  at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:105)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2386)
  at android.os.Handler.dispatchMessage (Handler.java:107)
  at android.os.Looper.loop (Looper.java:213)
  at android.app.ActivityThread.main (ActivityThread.java:8178)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:513)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1101)

This commit avoids the crash. But it's not clear to me that this is
really the right solution. However, in testing it appears to work.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 15:56:07 -06:00
Jason A. Donenfeld 521bbb4b4c AppListDialogFragment: refine singular grammar
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 19:56:53 +05:30
Jason A. Donenfeld 0a55e10b94 AppListDialogFragment: remove colons from tabs
Harsh's club became ill upon seeing them.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 19:56:53 +05:30
Harsh Shandilya d6e5fd9301 ui: tweak cards to make them nicer on the eyes
Surprisingly-requested-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-06 19:56:53 +05:30
Harsh Shandilya 2c625f56fd ui: misc cleanups to AppListDialogFragment
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-06 19:56:46 +05:30
Jason A. Donenfeld 7db0fa915e AppListDialogFragment: support both inclusion and exclusion
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-06 02:40:49 -06:00
Jason A. Donenfeld e424765a61 tunnel: support IncludedApplications as whitelist
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2020-04-05 20:04:51 -06:00
Harsh Shandilya 1ca4dbf1a2 tunnel: hold peers in an ArrayList
A set will cause identical peers to be dropped during save

Reported-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-06 01:22:44 +05:30
Harsh Shandilya 065893e31d MultiselectableRelativeLayout: use JvmOverloads constructor
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-06 00:39:22 +05:30
Harsh Shandilya ef70aa88e1 ui: fix scrolling in detail view
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-06 00:17:14 +05:30
Harsh Shandilya 6a11a199ca strings: sync translations
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2020-04-04 16:19:21 +05:30
65 changed files with 1577 additions and 413 deletions
+1
View File
@@ -15,3 +15,4 @@ build/
*.iml
*.jks
keystore.properties
gradlew.bat
+10 -10
View File
@@ -8,27 +8,26 @@ allprojects {
buildscript {
ext {
agpVersion = '3.6.2'
agpVersion = '4.0.1'
annotationsVersion = '1.1.0'
appcompatVersion = '1.1.0'
bintrayPluginVersion = '1.8.4'
biometricVersion = '1.0.1'
cardviewVersion = '1.0.0'
collectionVersion = '1.1.0'
constraintLayoutVersion = '1.1.3'
coordinatorLayoutVersion = '1.1.0'
coreKtxVersion = '1.2.0'
coroutinesVersion = '1.3.5'
coreKtxVersion = '1.3.0'
coroutinesVersion = '1.3.7'
eddsaVersion = '0.3.0'
fragmentVersion = '1.2.4'
fragmentVersion = '1.2.5'
jsr305Version = '3.0.2'
junitVersion = '4.13'
kotlinVersion = '1.3.71'
materialComponentsVersion = '1.1.0'
kotlinVersion = '1.3.72'
materialComponentsVersion = '1.2.0-alpha06'
mavenPluginVersion = '2.1'
preferenceVersion = '1.1.0'
preferenceVersion = '1.1.1'
streamsupportVersion = '1.7.2'
threetenabpVersion = '1.2.3'
threetenabpVersion = '1.2.4'
zxingEmbeddedVersion = '3.6.0'
groupName = 'com.wireguard.android'
@@ -51,8 +50,9 @@ task clean(type: Delete) {
tasks {
wrapper {
gradleVersion = "6.2.2"
gradleVersion = "6.5.1"
distributionType = Wrapper.DistributionType.ALL
distributionSha256Sum = "143a28f54f1ae93ef4f72d862dbc3c438050d81bb45b4601eb7076e998362920"
}
}
Binary file not shown.
+2 -1
View File
@@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
distributionSha256Sum=143a28f54f1ae93ef4f72d862dbc3c438050d81bb45b4601eb7076e998362920
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+2
View File
@@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
+6
View File
@@ -21,6 +21,9 @@ android {
path 'tools/CMakeLists.txt'
}
}
libraryVariants.all {
it.generateBuildConfigProvider.configure { enabled = false }
}
testOptions.unitTests.all {
testLogging {
events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
@@ -42,6 +45,9 @@ android {
}
}
}
lintOptions {
disable('LongLogTag')
}
}
dependencies {
@@ -9,6 +9,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.system.OsConstants;
import android.util.Log;
import com.wireguard.android.backend.BackendException.Reason;
@@ -193,15 +194,28 @@ public final class GoBackend implements Backend {
for (final String excludedApplication : config.getInterface().getExcludedApplications())
builder.addDisallowedApplication(excludedApplication);
for (final String includedApplication : config.getInterface().getIncludedApplications())
builder.addAllowedApplication(includedApplication);
for (final InetNetwork addr : config.getInterface().getAddresses())
builder.addAddress(addr.getAddress(), addr.getMask());
for (final InetAddress addr : config.getInterface().getDnsServers())
builder.addDnsServer(addr.getHostAddress());
boolean sawDefaultRoute = false;
for (final Peer peer : config.getPeers()) {
for (final InetNetwork addr : peer.getAllowedIps())
for (final InetNetwork addr : peer.getAllowedIps()) {
if (addr.getMask() == 0)
sawDefaultRoute = true;
builder.addRoute(addr.getAddress(), addr.getMask());
}
}
// "Kill-switch" semantics
if (!(sawDefaultRoute && config.getPeers().size() == 1)) {
builder.allowFamily(OsConstants.AF_INET);
builder.allowFamily(OsConstants.AF_INET6);
}
builder.setMtu(config.getInterface().getMtu().orElse(1280));
@@ -143,12 +143,12 @@ public final class ToolsInstaller {
extract();
final StringBuilder script = new StringBuilder("set -ex; ");
script.append("trap 'rm -rf /sbin/.magisk/img/wireguard' INT TERM EXIT; ");
script.append(String.format("rm -rf /sbin/.magisk/img/wireguard/; mkdir -p /sbin/.magisk/img/wireguard%s; ", INSTALL_DIR));
script.append("printf 'name=WireGuard Command Line Tools\nversion=1.0\nversionCode=1\nauthor=zx2c4\ndescription=Command line tools for WireGuard\nminMagisk=1500\n' > /sbin/.magisk/img/wireguard/module.prop; ");
script.append("touch /sbin/.magisk/img/wireguard/auto_mount; ");
script.append("trap 'rm -rf /data/adb/moduleswireguard' INT TERM EXIT; ");
script.append(String.format("rm -rf /data/adb/modules/wireguard/; mkdir -p /data/adb/modules/wireguard%s; ", INSTALL_DIR));
script.append("printf 'name=WireGuard Command Line Tools\nversion=1.0\nversionCode=1\nauthor=zx2c4\ndescription=Command line tools for WireGuard\nminMagisk=1500\n' > /data/adb/modules/wireguard/module.prop; ");
script.append("touch /data/adb/modules/wireguard/auto_mount; ");
for (final String name : EXECUTABLES) {
final File destination = new File("/sbin/.magisk/img/wireguard" + INSTALL_DIR, name);
final File destination = new File("/data/adb/modules/wireguard" + INSTALL_DIR, name);
script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; chcon 'u:object_r:system_file:s0' '%s' || true; ",
new File(localBinaryDir, name), destination, destination, destination));
}
@@ -191,7 +191,7 @@ public final class ToolsInstaller {
synchronized (lock) {
if (installAsMagiskModule == null) {
try {
installAsMagiskModule = rootShell.run(null, "[ -d /sbin/.magisk/mirror -a -d /sbin/.magisk/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
installAsMagiskModule = rootShell.run(null, "[ -d /data/adb/modules -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
} catch (final Exception ignored) {
installAsMagiskModule = false;
}
@@ -72,6 +72,7 @@ public class BadConfigException extends Exception {
DNS("DNS"),
ENDPOINT("Endpoint"),
EXCLUDED_APPLICATIONS("ExcludedApplications"),
INCLUDED_APPLICATIONS("IncludedApplications"),
LISTEN_PORT("ListenPort"),
MTU("MTU"),
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
@@ -17,10 +17,8 @@ import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import androidx.annotation.Nullable;
@@ -187,7 +185,7 @@ public final class Config {
@SuppressWarnings("UnusedReturnValue")
public static final class Builder {
// Defaults to an empty set.
private final Set<Peer> peers = new LinkedHashSet<>();
private final ArrayList<Peer> peers = new ArrayList<>();
// No default; must be provided before building.
@Nullable private Interface interfaze;
@@ -43,6 +43,7 @@ public final class Interface {
private final Set<InetNetwork> addresses;
private final Set<InetAddress> dnsServers;
private final Set<String> excludedApplications;
private final Set<String> includedApplications;
private final KeyPair keyPair;
private final Optional<Integer> listenPort;
private final Optional<Integer> mtu;
@@ -52,6 +53,7 @@ public final class Interface {
addresses = Collections.unmodifiableSet(new LinkedHashSet<>(builder.addresses));
dnsServers = Collections.unmodifiableSet(new LinkedHashSet<>(builder.dnsServers));
excludedApplications = Collections.unmodifiableSet(new LinkedHashSet<>(builder.excludedApplications));
includedApplications = Collections.unmodifiableSet(new LinkedHashSet<>(builder.includedApplications));
keyPair = Objects.requireNonNull(builder.keyPair, "Interfaces must have a private key");
listenPort = builder.listenPort;
mtu = builder.mtu;
@@ -81,6 +83,9 @@ public final class Interface {
case "excludedapplications":
builder.parseExcludedApplications(attribute.getValue());
break;
case "includedapplications":
builder.parseIncludedApplications(attribute.getValue());
break;
case "listenport":
builder.parseListenPort(attribute.getValue());
break;
@@ -106,6 +111,7 @@ public final class Interface {
return addresses.equals(other.addresses)
&& dnsServers.equals(other.dnsServers)
&& excludedApplications.equals(other.excludedApplications)
&& includedApplications.equals(other.includedApplications)
&& keyPair.equals(other.keyPair)
&& listenPort.equals(other.listenPort)
&& mtu.equals(other.mtu);
@@ -141,6 +147,16 @@ public final class Interface {
return excludedApplications;
}
/**
* Returns the set of applications included exclusively for using the interface.
*
* @return a set of package names
*/
public Set<String> getIncludedApplications() {
// The collection is already immutable.
return includedApplications;
}
/**
* Returns the public/private key pair used by the interface.
*
@@ -174,6 +190,7 @@ public final class Interface {
hash = 31 * hash + addresses.hashCode();
hash = 31 * hash + dnsServers.hashCode();
hash = 31 * hash + excludedApplications.hashCode();
hash = 31 * hash + includedApplications.hashCode();
hash = 31 * hash + keyPair.hashCode();
hash = 31 * hash + listenPort.hashCode();
hash = 31 * hash + mtu.hashCode();
@@ -213,6 +230,8 @@ public final class Interface {
}
if (!excludedApplications.isEmpty())
sb.append("ExcludedApplications = ").append(Attribute.join(excludedApplications)).append('\n');
if (!includedApplications.isEmpty())
sb.append("IncludedApplications = ").append(Attribute.join(includedApplications)).append('\n');
listenPort.ifPresent(lp -> sb.append("ListenPort = ").append(lp).append('\n'));
mtu.ifPresent(m -> sb.append("MTU = ").append(m).append('\n'));
sb.append("PrivateKey = ").append(keyPair.getPrivateKey().toBase64()).append('\n');
@@ -240,6 +259,8 @@ public final class Interface {
private final Set<InetAddress> dnsServers = new LinkedHashSet<>();
// Defaults to an empty set.
private final Set<String> excludedApplications = new LinkedHashSet<>();
// Defaults to an empty set.
private final Set<String> includedApplications = new LinkedHashSet<>();
// No default; must be provided before building.
@Nullable private KeyPair keyPair;
// Defaults to not present.
@@ -271,6 +292,9 @@ public final class Interface {
if (keyPair == null)
throw new BadConfigException(Section.INTERFACE, Location.PRIVATE_KEY,
Reason.MISSING_ATTRIBUTE, null);
if (!includedApplications.isEmpty() && !excludedApplications.isEmpty())
throw new BadConfigException(Section.INTERFACE, Location.INCLUDED_APPLICATIONS,
Reason.INVALID_KEY, null);
return new Interface(this);
}
@@ -284,6 +308,16 @@ public final class Interface {
return this;
}
public Builder includeApplication(final String application) {
includedApplications.add(application);
return this;
}
public Builder includeApplications(final Collection<String> applications) {
includedApplications.addAll(applications);
return this;
}
public Builder parseAddresses(final CharSequence addresses) throws BadConfigException {
try {
for (final String address : Attribute.split(addresses))
@@ -308,6 +342,10 @@ public final class Interface {
return excludeApplications(Lists.of(Attribute.split(apps)));
}
public Builder parseIncludedApplications(final CharSequence apps) {
return includeApplications(Lists.of(Attribute.split(apps)));
}
public Builder parseListenPort(final String listenPort) throws BadConfigException {
try {
return setListenPort(Integer.parseInt(listenPort));
+1 -1
View File
@@ -14,7 +14,7 @@ target_link_libraries(libwg-quick.so -ldl)
file(GLOB WG_SOURCES wireguard-tools/src/*.c ndk-compat/compat.c)
add_executable(libwg.so ${WG_SOURCES})
target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/uapi/" "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/")
target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/uapi/linux/" "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/")
target_compile_options(libwg.so PUBLIC -O3 -std=gnu11 -D_GNU_SOURCE -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"/data/data/${ANDROID_PACKAGE_NAME}/cache\")
add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building wireguard-go" VERBATIM COMMAND make
+3 -3
View File
@@ -20,11 +20,11 @@ export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
export GOOS := android
export CGO_ENABLED := 1
GO_VERSION := 1.14.1
GO_VERSION := 1.14.4
GO_PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m))
GO_TARBALL := go$(GO_VERSION).$(GO_PLATFORM).tar.gz
GO_HASH_darwin-amd64 := 6632f9d53fd95632e431e8c34295349cca3f0a124e3a28b760ae5c42b32816e3
GO_HASH_linux-amd64 := 2f49eb17ce8b48c680cdb166ffd7389702c0dec6effa090c324804a5cac8a7f8
GO_HASH_darwin-amd64 := 3fa7ed8dc44fdd50c0bfe72676250cceca527d59950aef20af906a670cf88de2
GO_HASH_linux-amd64 := aed845e4185a0b2a3c3d5e1d0a35491702c55889192bb9c30e67a3de6849c067
default: $(DESTDIR)/libwg-go.so
+16 -6
View File
@@ -11,10 +11,6 @@ import "C"
import (
"bufio"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
"bytes"
"log"
"math"
@@ -24,6 +20,12 @@ import (
"runtime"
"strings"
"unsafe"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
)
type AndroidLogger struct {
@@ -149,7 +151,11 @@ func wgGetSocketV4(tunnelHandle int32) int32 {
if !ok {
return -1
}
fd, err := handle.device.PeekLookAtSocketFd4()
bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd)
if bind == nil {
return -1
}
fd, err := bind.PeekLookAtSocketFd4()
if err != nil {
return -1
}
@@ -162,7 +168,11 @@ func wgGetSocketV6(tunnelHandle int32) int32 {
if !ok {
return -1
}
fd, err := handle.device.PeekLookAtSocketFd6()
bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd)
if bind == nil {
return -1
}
fd, err := bind.PeekLookAtSocketFd4()
if err != nil {
return -1
}
+5 -5
View File
@@ -1,10 +1,10 @@
module golang.zx2c4.com/wireguard/android
go 1.13
go 1.14
require (
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df // indirect
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 // indirect
golang.org/x/sys v0.0.0-20200321134203-328b4cd54aae
golang.zx2c4.com/wireguard v0.0.20200320
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 // indirect
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980
golang.zx2c4.com/wireguard v0.0.20200321-0.20200622004228-b84f1d4db25e
)
+12 -11
View File
@@ -1,19 +1,20 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df h1:lDWgvUvNnaTnNBc/dwOty86cFeKoKWbwy2wQj0gIxbU=
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 h1:1+zQlQqEEhUeStBTi653GZAnAuivZq/2hz+Iz+OP7rg=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200321134203-328b4cd54aae h1:3tcmuaB7wwSZtelmiv479UjUB+vviwABz7a133ZwOKQ=
golang.org/x/sys v0.0.0-20200321134203-328b4cd54aae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.20200320 h1:1vE6zVeO7fix9cJX1Z9ZQ+ikPIIx7vIyU0o0tLDD88g=
golang.zx2c4.com/wireguard v0.0.20200320/go.mod h1:lDian4Sw4poJ04SgHh35nzMVwGSYlPumkdnHcucAQoY=
golang.zx2c4.com/wireguard v0.0.20200321-0.20200622004228-b84f1d4db25e h1:f8BS3yEMeIGx/zzJfihxDRedx6lT7EiJlfih4j6LY98=
golang.zx2c4.com/wireguard v0.0.20200321-0.20200622004228-b84f1d4db25e/go.mod h1:GJvYs5O24/ASlwPiRklVnjMx2xQzrOic0DuU6GvYJL4=
+2 -3
View File
@@ -21,8 +21,8 @@ android {
}
}
compileSdkVersion 29
dataBinding.enabled true
viewBinding.enabled true
buildFeatures.dataBinding = true
buildFeatures.viewBinding = true
defaultConfig {
applicationId 'com.wireguard.android'
minSdkVersion 21
@@ -68,7 +68,6 @@ dependencies {
implementation project(":tunnel")
implementation "androidx.annotation:annotation:$annotationsVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation "androidx.cardview:cardview:$cardviewVersion"
implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$coordinatorLayoutVersion"
implementation "androidx.biometric:biometric:$biometricVersion"
+3 -3
View File
@@ -2,9 +2,6 @@
# escalates them as errors.
-dontwarn sun.misc.Unsafe
# Retain some information to keep stacktraces usable
-keepattributes SourceFile,LineNumberTable
# Fragment 1.2.4 allows Fragment classes to be obfuscated but
# databinding references in XML seem to not be rewritten to
# match, so we preserve the names as 1.2.3 did.
@@ -12,3 +9,6 @@
-keep public class <1> {
public <init>();
}
# Don't obfuscate
-dontobfuscate
+3
View File
@@ -112,5 +112,8 @@
android:name="android.service.quicksettings.ACTIVE_TILE"
android:value="false" />
</service>
<meta-data android:name="android.content.APP_RESTRICTIONS"
android:resource="@xml/app_restrictions" />
</application>
</manifest>
@@ -9,8 +9,9 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.LinearLayout
import androidx.appcompat.app.ActionBar
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import com.wireguard.android.R
@@ -55,16 +56,15 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
actionBar = supportActionBar
isTwoPaneLayout = findViewById<View>(R.id.master_detail_wrapper) is LinearLayout
isTwoPaneLayout = findViewById<View?>(R.id.master_detail_wrapper) != null
supportFragmentManager.addOnBackStackChangedListener(this)
onBackStackChanged()
// Dispatch insets on back stack change
// This is required to ensure replaced fragments are also able to consume insets
findViewById<View>(R.id.master_detail_wrapper).setOnApplyWindowInsetsListener { _, insets ->
val fragmentManager = supportFragmentManager
fragmentManager.addOnBackStackChangedListener {
fragmentManager.fragments.forEach {
it.requireView().dispatchApplyWindowInsets(insets)
findViewById<View>(R.id.main_activity_container).setOnApplyWindowInsetsListener { _, insets ->
supportFragmentManager.addOnBackStackChangedListener {
supportFragmentManager.fragments.forEach {
ViewCompat.dispatchApplyWindowInsets(it.requireView(), WindowInsetsCompat.toWindowInsetsCompat(insets))
}
}
insets
@@ -17,6 +17,7 @@ import androidx.preference.PreferenceFragmentCompat
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.util.AdminKnobs
import com.wireguard.android.util.ModuleLoader
import java.util.ArrayList
import java.util.Arrays
@@ -87,6 +88,10 @@ class SettingsActivity : ThemeChangeAwareActivity() {
val remoteApps = preferenceManager.findPreference<Preference>("allow_remote_control_intents")
remoteApps?.parent?.removePreference(remoteApps)
}
if (AdminKnobs.disableConfigExport) {
val zipExporter = preferenceManager.findPreference<Preference>("zip_exporter")
zipExporter?.parent?.removePreference(zipExporter)
}
val wgQuickOnlyPrefs = arrayOf(
preferenceManager.findPreference("tools_installer"),
preferenceManager.findPreference("restore_on_boot"),
@@ -26,6 +26,7 @@ import com.wireguard.android.widget.ToggleSwitch.OnBeforeCheckedChangeListener
import com.wireguard.config.Attribute
import com.wireguard.config.InetNetwork
import java9.util.Optional
import java.net.InetAddress
/**
* Static methods for use by generated code in the Android data binding library.
@@ -135,13 +136,30 @@ object BindingAdapters {
@JvmStatic
@BindingAdapter("android:text")
fun setText(view: TextView, text: Optional<*>) {
view.text = text.map { it.toString() }.orElse("")
fun setOptionalText(view: TextView, text: Optional<*>?) {
view.text = text?.map { it.toString() }?.orElse("") ?: ""
}
@JvmStatic
@BindingAdapter("android:text")
fun setText(view: TextView, networks: Iterable<InetNetwork?>?) {
fun setInetNetworkSetText(view: TextView, networks: Iterable<InetNetwork?>?) {
view.text = if (networks != null) Attribute.join(networks) else ""
}
@JvmStatic
@BindingAdapter("android:text")
fun setInetAddressSetText(view: TextView, addresses: Iterable<InetAddress?>?) {
view.text = if (addresses != null) Attribute.join(addresses.map { it?.hostAddress }) else ""
}
@JvmStatic
fun tryParseInt(s: String?): Int {
if (s == null)
return 0
return try {
Integer.parseInt(s)
} catch (_: Exception) {
0
}
}
}
@@ -17,8 +17,10 @@ import java.lang.ref.WeakReference
/**
* A generic `RecyclerView.Adapter` backed by a `ObservableKeyedArrayList`.
*/
class ObservableKeyedRecyclerViewAdapter<K, E : Keyed<out K>> internal constructor(context: Context, private val layoutId: Int,
list: ObservableKeyedArrayList<K, E>?) : RecyclerView.Adapter<ObservableKeyedRecyclerViewAdapter.ViewHolder>() {
class ObservableKeyedRecyclerViewAdapter<K, E : Keyed<out K>> internal constructor(
context: Context, private val layoutId: Int,
list: ObservableKeyedArrayList<K, E>?
) : RecyclerView.Adapter<ObservableKeyedRecyclerViewAdapter.ViewHolder>() {
private val callback = OnListChangedCallback(this)
private val layoutInflater: LayoutInflater = LayoutInflater.from(context)
private var list: ObservableKeyedArrayList<K, E>? = null
@@ -12,13 +12,13 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.zxing.integration.android.IntentIntegrator
import com.wireguard.android.R
import com.wireguard.android.activity.TunnelCreatorActivity
import com.wireguard.android.util.requireTargetFragment
import com.wireguard.android.util.resolveAttribute
class AddTunnelsSheet : BottomSheetDialogFragment() {
@@ -81,10 +81,6 @@ class AddTunnelsSheet : BottomSheetDialogFragment() {
behavior?.removeBottomSheetCallback(bottomSheetCallback)
}
private fun requireTargetFragment(): Fragment {
return requireNotNull(targetFragment) { "A target fragment should always be set" }
}
private fun onRequestCreateConfig() {
startActivity(Intent(activity, TunnelCreatorActivity::class.java))
}
@@ -5,23 +5,30 @@
package com.wireguard.android.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.databinding.Observable
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayout
import com.wireguard.android.Application
import com.wireguard.android.BR
import com.wireguard.android.R
import com.wireguard.android.databinding.AppListDialogFragmentBinding
import com.wireguard.android.databinding.ObservableKeyedArrayList
import com.wireguard.android.model.ApplicationData
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.requireTargetFragment
class AppListDialogFragment : DialogFragment() {
private val appData: ObservableKeyedArrayList<String, ApplicationData> = ObservableKeyedArrayList()
private var currentlyExcludedApps = emptyList<String>()
private val appData = ObservableKeyedArrayList<String, ApplicationData>()
private var currentlySelectedApps = emptyList<String>()
private var initiallyExcluded = false
private var button: Button? = null
private var tabs: TabLayout? = null
private fun loadData() {
val activity = activity ?: return
@@ -33,7 +40,14 @@ class AppListDialogFragment : DialogFragment() {
val applicationData: MutableList<ApplicationData> = ArrayList()
resolveInfos.forEach {
val packageName = it.activityInfo.packageName
applicationData.add(ApplicationData(it.loadIcon(pm), it.loadLabel(pm).toString(), packageName, currentlyExcludedApps.contains(packageName)))
val appData = ApplicationData(it.loadIcon(pm), it.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
applicationData.add(appData)
appData.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
if (propertyId == BR.selected)
setButtonText()
}
})
}
applicationData.sortWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name })
applicationData
@@ -52,17 +66,37 @@ class AppListDialogFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val excludedApps = requireArguments().getStringArrayList(KEY_EXCLUDED_APPS)
currentlyExcludedApps = (excludedApps ?: emptyList())
require(requireTargetFragment() is AppSelectionListener) { "${requireTargetFragment()} must implement AppSelectionListener" }
currentlySelectedApps = (arguments?.getStringArrayList(KEY_SELECTED_APPS) ?: emptyList())
initiallyExcluded = arguments?.getBoolean(KEY_IS_EXCLUDED) ?: true
}
private fun setButtonText() {
val numSelected = appData.count { it.isSelected }
button?.text = if (numSelected == 0)
getString(R.string.use_all_applications)
else when (tabs?.selectedTabPosition) {
0 -> resources.getQuantityString(R.plurals.exclude_n_applications, numSelected, numSelected)
1 -> resources.getQuantityString(R.plurals.include_n_applications, numSelected, numSelected)
else -> null
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val alertDialogBuilder = AlertDialog.Builder(requireActivity())
alertDialogBuilder.setTitle(R.string.excluded_applications)
val binding = AppListDialogFragmentBinding.inflate(requireActivity().layoutInflater, null, false)
binding.executePendingBindings()
alertDialogBuilder.setView(binding.root)
alertDialogBuilder.setPositiveButton(R.string.set_exclusions) { _, _ -> setExclusionsAndDismiss() }
tabs = binding.tabs
tabs?.apply {
selectTab(binding.tabs.getTabAt(if (initiallyExcluded) 0 else 1))
addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) = Unit
override fun onTabUnselected(tab: TabLayout.Tab?) = Unit
override fun onTabSelected(tab: TabLayout.Tab?) = setButtonText()
})
}
alertDialogBuilder.setPositiveButton(" ") { _, _ -> setSelectionAndDismiss() }
alertDialogBuilder.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
alertDialogBuilder.setNeutralButton(R.string.toggle_all) { _, _ -> }
binding.fragment = this
@@ -70,39 +104,40 @@ class AppListDialogFragment : DialogFragment() {
loadData()
val dialog = alertDialogBuilder.create()
dialog.setOnShowListener {
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
val selectedItems = appData
.filter { it.isExcludedFromTunnel }
val excludeAll = selectedItems.isEmpty()
button = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
setButtonText()
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener { _ ->
val selectAll = appData.none { it.isSelected }
appData.forEach {
it.isExcludedFromTunnel = excludeAll
it.isSelected = selectAll
}
}
}
return dialog
}
private fun setExclusionsAndDismiss() {
val excludedApps: MutableList<String> = ArrayList()
private fun setSelectionAndDismiss() {
val selectedApps: MutableList<String> = ArrayList()
for (data in appData) {
if (data.isExcludedFromTunnel) {
excludedApps.add(data.packageName)
if (data.isSelected) {
selectedApps.add(data.packageName)
}
}
(targetFragment as AppExclusionListener?)!!.onExcludedAppsSelected(excludedApps)
(requireTargetFragment() as AppSelectionListener).onSelectedAppsSelected(selectedApps, tabs?.selectedTabPosition == 0)
dismiss()
}
interface AppExclusionListener {
fun onExcludedAppsSelected(excludedApps: List<String>)
interface AppSelectionListener {
fun onSelectedAppsSelected(selectedApps: List<String>, isExcluded: Boolean)
}
companion object {
private const val KEY_EXCLUDED_APPS = "excludedApps"
fun <T> newInstance(excludedApps: ArrayList<String?>?, target: T): AppListDialogFragment where T : Fragment?, T : AppExclusionListener? {
private const val KEY_SELECTED_APPS = "selected_apps"
private const val KEY_IS_EXCLUDED = "is_excluded"
fun <T> newInstance(selectedApps: ArrayList<String?>?, isExcluded: Boolean, target: T): AppListDialogFragment where T : Fragment?, T : AppSelectionListener? {
val extras = Bundle()
extras.putStringArrayList(KEY_EXCLUDED_APPS, excludedApps)
extras.putStringArrayList(KEY_SELECTED_APPS, selectedApps)
extras.putBoolean(KEY_IS_EXCLUDED, isExcluded)
val fragment = AppListDialogFragment()
fragment.setTargetFragment(target, 0)
fragment.arguments = extras
@@ -23,9 +23,10 @@ import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.databinding.TunnelEditorFragmentBinding
import com.wireguard.android.fragment.AppListDialogFragment.AppExclusionListener
import com.wireguard.android.fragment.AppListDialogFragment.AppSelectionListener
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.BiometricAuthenticator
import com.wireguard.android.util.AdminKnobs
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.viewmodel.ConfigProxy
import com.wireguard.android.widget.EdgeToEdge.setUpRoot
@@ -35,7 +36,7 @@ import com.wireguard.config.Config
/**
* Fragment for editing a WireGuard configuration.
*/
class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
class TunnelEditorFragment : BaseFragment(), AppSelectionListener {
private var haveShownKeys = false
private var binding: TunnelEditorFragmentBinding? = null
private var tunnel: ObservableTunnel? = null
@@ -88,11 +89,20 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
super.onDestroyView()
}
override fun onExcludedAppsSelected(excludedApps: List<String>) {
requireNotNull(binding) { "Tried to set excluded apps while no view was loaded" }
binding!!.config!!.`interface`.excludedApplications.apply {
clear()
addAll(excludedApps)
override fun onSelectedAppsSelected(selectedApps: List<String>, isExcluded: Boolean) {
requireNotNull(binding) { "Tried to set excluded/included apps while no view was loaded" }
if (isExcluded) {
binding!!.config!!.`interface`.includedApplications.clear()
binding!!.config!!.`interface`.excludedApplications.apply {
clear()
addAll(selectedApps)
}
} else {
binding!!.config!!.`interface`.excludedApplications.clear()
binding!!.config!!.`interface`.includedApplications.apply {
clear()
addAll(selectedApps)
}
}
}
@@ -150,10 +160,16 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
}
@Suppress("UNUSED_PARAMETER")
fun onRequestSetExcludedApplications(view: View?) {
fun onRequestSetExcludedIncludedApplications(view: View?) {
if (binding != null) {
val excludedApps = ArrayList(binding!!.config!!.`interface`.excludedApplications)
val fragment = AppListDialogFragment.newInstance(excludedApps, this)
var isExcluded = true
var selectedApps = ArrayList(binding!!.config!!.`interface`.excludedApplications)
if (selectedApps.isEmpty()) {
selectedApps = ArrayList(binding!!.config!!.`interface`.includedApplications)
if (selectedApps.isNotEmpty())
isExcluded = false
}
val fragment = AppListDialogFragment.newInstance(selectedApps, isExcluded, this)
fragment.show(parentFragmentManager, null)
}
}
@@ -237,6 +253,7 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
val edit = view as? EditText ?: return
if (edit.inputType == InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) return
if (!haveShownKeys && edit.text.isNotEmpty()) {
if (AdminKnobs.disableConfigExport) return
showingAuthenticator = true
BiometricAuthenticator.authenticate(R.string.biometric_prompt_private_key_title, this) {
showingAuthenticator = false
@@ -17,6 +17,8 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import com.google.android.material.snackbar.Snackbar
@@ -314,6 +316,11 @@ class TunnelListFragment : BaseFragment() {
return when (item.itemId) {
R.id.menu_action_delete -> {
val copyCheckedItems = HashSet(checkedItems)
binding?.createFab?.apply {
visibility = View.VISIBLE
scaleX = 1f
scaleY = 1f
}
Application.getTunnelManager().tunnels.thenAccept { tunnels ->
val tunnelsToDelete = ArrayList<ObservableTunnel>()
for (position in copyCheckedItems) tunnelsToDelete.add(tunnels[position])
@@ -343,14 +350,16 @@ class TunnelListFragment : BaseFragment() {
if (activity != null) {
resources = activity!!.resources
}
animateFab(binding?.createFab, false)
mode.menuInflater.inflate(R.menu.tunnel_list_action_mode, menu)
binding!!.tunnelList.adapter!!.notifyDataSetChanged()
binding?.tunnelList?.adapter?.notifyDataSetChanged()
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
resources = null
animateFab(binding?.createFab, true)
checkedItems.clear()
binding!!.tunnelList.adapter!!.notifyDataSetChanged()
}
@@ -391,6 +400,26 @@ class TunnelListFragment : BaseFragment() {
mode.title = resources!!.getQuantityString(R.plurals.delete_title, count, count)
}
}
private fun animateFab(view: View?, show: Boolean) {
view ?: return
val animation = AnimationUtils.loadAnimation(
context, if (show) R.anim.scale_up else R.anim.scale_down
)
animation.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
if (!show) view.visibility = View.GONE
}
override fun onAnimationStart(animation: Animation?) {
if (show) view.visibility = View.VISIBLE
}
})
view.startAnimation(animation)
}
}
companion object {
@@ -10,13 +10,13 @@ import androidx.databinding.Bindable
import com.wireguard.android.BR
import com.wireguard.android.databinding.Keyed
class ApplicationData(val icon: Drawable, val name: String, val packageName: String, isExcludedFromTunnel: Boolean) : BaseObservable(), Keyed<String> {
class ApplicationData(val icon: Drawable, val name: String, val packageName: String, isSelected: Boolean) : BaseObservable(), Keyed<String> {
override val key = name
@get:Bindable
var isExcludedFromTunnel = isExcludedFromTunnel
var isSelected = isSelected
set(value) {
field = value
notifyPropertyChanged(BR.excludedFromTunnel)
notifyPropertyChanged(BR.selected)
}
}
@@ -93,14 +93,14 @@ class ObservableTunnel internal constructor(
@get:Bindable
var statistics: Statistics? = null
get() {
if (field == null || field!!.isStale)
if (field == null || field?.isStale != false)
manager.getTunnelStatistics(this).whenComplete(ExceptionLoggers.E)
return field
}
private set
val statisticsAsync: CompletionStage<Statistics>
get() = if (statistics == null || statistics!!.isStale)
get() = if (statistics == null || statistics?.isStale != false)
manager.getTunnelStatistics(this)
else
CompletableFuture.completedFuture(statistics)
@@ -18,11 +18,18 @@ import java9.util.concurrent.CompletableFuture
import kotlin.system.exitProcess
class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var state = if (Application.getBackend() is WgQuickBackend) State.ENABLED else State.DISABLED
private var state = State.UNKNOWN
override fun getSummary() = context.getString(state.summaryResourceId)
init {
isVisible = false
Application.getBackendAsync().thenAccept { backend ->
setState(if (backend is WgQuickBackend) State.ENABLED else State.DISABLED)
}
}
override fun getTitle() = context.getString(state.titleResourceId)
override fun getSummary() = if (state == State.UNKNOWN) "" else context.getString(state.summaryResourceId)
override fun getTitle() = if (state == State.UNKNOWN) "" else context.getString(state.titleResourceId)
@SuppressLint("ApplySharedPref")
override fun onClick() {
@@ -51,13 +58,15 @@ class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : P
if (this.state == state) return
this.state = state
if (isEnabled != state.shouldEnableView) isEnabled = state.shouldEnableView
if (isVisible != state.visible) isVisible = state.visible
notifyChanged()
}
private enum class State(val titleResourceId: Int, val summaryResourceId: Int, val shouldEnableView: Boolean) {
ENABLED(R.string.module_disabler_enabled_title, R.string.module_disabler_enabled_summary, true),
DISABLED(R.string.module_disabler_disabled_title, R.string.module_disabler_disabled_summary, true),
ENABLING(R.string.module_disabler_disabled_title, R.string.success_application_will_restart, false),
DISABLING(R.string.module_disabler_enabled_title, R.string.success_application_will_restart, false);
private enum class State(val titleResourceId: Int, val summaryResourceId: Int, val shouldEnableView: Boolean, val visible: Boolean) {
UNKNOWN(0, 0, false, false),
ENABLED(R.string.module_disabler_enabled_title, R.string.module_disabler_enabled_summary, true, true),
DISABLED(R.string.module_disabler_disabled_title, R.string.module_disabler_disabled_summary, true, true),
ENABLING(R.string.module_disabler_disabled_title, R.string.success_application_will_restart, false, true),
DISABLING(R.string.module_disabler_enabled_title, R.string.success_application_will_restart, false, true);
}
}
@@ -16,6 +16,7 @@ import com.wireguard.android.R
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.BiometricAuthenticator
import com.wireguard.android.util.DownloadsFileSaver
import com.wireguard.android.util.AdminKnobs
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.FragmentUtils
import java9.util.concurrent.CompletableFuture
@@ -82,6 +83,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
override fun getTitle() = context.getString(R.string.zip_export_title)
override fun onClick() {
if (AdminKnobs.disableConfigExport) return
val prefActivity = FragmentUtils.getPrefActivity(this)
val fragment = prefActivity.supportFragmentManager.fragments.first()
BiometricAuthenticator.authenticate(R.string.biometric_prompt_zip_exporter_title, fragment) {
@@ -0,0 +1,16 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
import android.content.RestrictionsManager
import androidx.core.content.getSystemService
import com.wireguard.android.Application
object AdminKnobs {
private val restrictions: RestrictionsManager? = Application.get().getSystemService()
val disableConfigExport: Boolean
get() = restrictions?.applicationRestrictions?.getBoolean("disable_config_export", false) ?: false
}
@@ -8,9 +8,14 @@ package com.wireguard.android.util
import android.content.Context
import android.util.TypedValue
import androidx.annotation.AttrRes
import androidx.fragment.app.Fragment
fun Context.resolveAttribute(@AttrRes attrRes: Int): Int {
val typedValue = TypedValue()
theme.resolveAttribute(attrRes, typedValue, true)
return typedValue.data
}
fun Fragment.requireTargetFragment(): Fragment {
return requireNotNull(targetFragment) { "A target fragment should always be set for $this" }
}
@@ -22,6 +22,9 @@ class InterfaceProxy : BaseObservable, Parcelable {
@get:Bindable
val excludedApplications: ObservableList<String> = ObservableArrayList()
@get:Bindable
val includedApplications: ObservableList<String> = ObservableArrayList()
@get:Bindable
var addresses: String = ""
set(value) {
@@ -70,6 +73,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
addresses = parcel.readString() ?: ""
dnsServers = parcel.readString() ?: ""
parcel.readStringList(excludedApplications)
parcel.readStringList(includedApplications)
listenPort = parcel.readString() ?: ""
mtu = parcel.readString() ?: ""
privateKey = parcel.readString() ?: ""
@@ -80,6 +84,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
val dnsServerStrings = other.dnsServers.map { it.hostAddress }
dnsServers = Attribute.join(dnsServerStrings)
excludedApplications.addAll(other.excludedApplications)
includedApplications.addAll(other.includedApplications)
listenPort = other.listenPort.map { it.toString() }.orElse("")
mtu = other.mtu.map { it.toString() }.orElse("")
val keyPair = other.keyPair
@@ -103,6 +108,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
if (addresses.isNotEmpty()) builder.parseAddresses(addresses)
if (dnsServers.isNotEmpty()) builder.parseDnsServers(dnsServers)
if (excludedApplications.isNotEmpty()) builder.excludeApplications(excludedApplications)
if (includedApplications.isNotEmpty()) builder.includeApplications(includedApplications)
if (listenPort.isNotEmpty()) builder.parseListenPort(listenPort)
if (mtu.isNotEmpty()) builder.parseMtu(mtu)
if (privateKey.isNotEmpty()) builder.parsePrivateKey(privateKey)
@@ -113,6 +119,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
dest.writeString(addresses)
dest.writeString(dnsServers)
dest.writeStringList(excludedApplications)
dest.writeStringList(includedApplications)
dest.writeString(listenPort)
dest.writeString(mtu)
dest.writeString(privateKey)
@@ -12,7 +12,7 @@ import androidx.core.view.marginRight
import androidx.core.view.marginTop
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
/**
* A utility for edge-to-edge display. It provides several features needed to make the app
@@ -27,7 +27,7 @@ object EdgeToEdge {
}
@JvmStatic
fun setUpScrollingContent(scrollingContent: ViewGroup, fab: ExtendedFloatingActionButton?) {
fun setUpScrollingContent(scrollingContent: ViewGroup, fab: FloatingActionButton?) {
val originalPaddingLeft = scrollingContent.paddingLeft
val originalPaddingRight = scrollingContent.paddingRight
val originalPaddingBottom = scrollingContent.paddingBottom
@@ -50,7 +50,7 @@ object EdgeToEdge {
}
@JvmStatic
fun setUpFAB(fab: ExtendedFloatingActionButton) {
fun setUpFAB(fab: FloatingActionButton) {
val originalMarginLeft = fab.marginLeft
val originalMarginRight = fab.marginRight
val originalMarginBottom = fab.marginBottom
@@ -10,14 +10,14 @@ import android.view.View
import android.widget.RelativeLayout
import com.wireguard.android.R
class MultiselectableRelativeLayout : RelativeLayout {
class MultiselectableRelativeLayout @JvmOverloads constructor(
context: Context? = null,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr, defStyleRes) {
private var multiselected = false
constructor(context: Context?) : super(context) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}
override fun onCreateDrawableState(extraSpace: Int): IntArray {
if (multiselected) {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<scale
android:duration="300"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0"
android:toYScale="0" />
</set>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<scale
android:duration="300"
android:fromXScale="0"
android:fromYScale="0"
android:interpolator="@android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_activity_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.MainActivity">
@@ -18,30 +18,50 @@
type="com.wireguard.android.databinding.ObservableKeyedArrayList&lt;String, ApplicationData&gt;" />
</data>
<FrameLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="200dp">
android:orientation="vertical">
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="@{appData.isEmpty() ? View.VISIBLE : View.GONE}"
tools:visibility="gone" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
style="@style/Widget.MaterialComponents.TabLayout.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/app_list"
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/exclude_from_tunnel" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/include_in_tunnel" />
</com.google.android.material.tabs.TabLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:items="@{appData}"
app:layout="@{@layout/app_list_item}"
tools:itemCount="10"
tools:listitem="@layout/app_list_item" />
</FrameLayout>
android:minHeight="200dp">
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="@{appData.isEmpty() ? View.VISIBLE : View.GONE}"
tools:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/app_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:items="@{appData}"
app:layout="@{@layout/app_list_item}"
tools:itemCount="10"
tools:listitem="@layout/app_list_item" />
</FrameLayout>
</LinearLayout>
</layout>
+3 -3
View File
@@ -24,7 +24,7 @@
android:layout_height="wrap_content"
android:background="@drawable/list_item_background"
android:gravity="center_vertical"
android:onClick="@{(view) -> item.setExcludedFromTunnel(!item.excludedFromTunnel)}"
android:onClick="@{(view) -> item.setSelected(!item.selected)}"
android:orientation="horizontal"
android:paddingTop="8dp"
android:paddingBottom="8dp">
@@ -51,10 +51,10 @@
tools:text="@tools:sample/full_names" />
<CheckBox
android:id="@+id/excluded_checkbox"
android:id="@+id/selected_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@={item.excludedFromTunnel}"
android:checked="@={item.selected}"
tools:checked="true" />
</LinearLayout>
@@ -16,13 +16,12 @@
tools:itemCount="20"
tools:listitem="@layout/log_viewer_entry" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/share_fab"
style="@style/Widget.MaterialComponents.ExtendedFloatingActionButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:icon="@drawable/ic_action_share_white" />
app:srcCompat="@drawable/ic_action_share_white" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/master_detail_wrapper"
android:id="@+id/main_activity_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
+222 -111
View File
@@ -22,131 +22,242 @@
type="com.wireguard.config.Config" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorBackground"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
android:focusable="true">
<com.google.android.material.card.MaterialCardView
android:id="@+id/tunnel_detail_card"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:cardBackgroundColor="?attr/elevationOverlayColor"
app:cardCornerRadius="0dp"
app:cardElevation="2dp"
app:contentPadding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
<com.google.android.material.card.MaterialCardView
android:id="@+id/tunnel_detail_card"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/interface_title"
style="@style/SectionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/interface_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.wireguard.android.widget.ToggleSwitch
android:id="@+id/tunnel_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:checked="@{tunnel.state == State.UP}"
app:layout_constraintBaseline_toBaselineOf="@+id/interface_title"
app:layout_constraintEnd_toEndOf="parent"
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
<TextView
android:id="@+id/interface_name_label"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/interface_name_text"
android:text="@string/name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/interface_title" />
android:layout_height="wrap_content">
<TextView
android:id="@+id/interface_name_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{tunnel.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/interface_name_label"
tools:text="wg0" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/interface_title"
style="@style/SectionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/interface_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/public_key_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/public_key_text"
android:text="@string/public_key"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/interface_name_text" />
<com.wireguard.android.widget.ToggleSwitch
android:id="@+id/tunnel_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:checked="@{tunnel.state == State.UP}"
app:layout_constraintBaseline_toBaselineOf="@+id/interface_title"
app:layout_constraintEnd_toEndOf="parent"
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
<TextView
android:id="@+id/public_key_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/public_key_description"
android:ellipsize="end"
android:maxLines="1"
android:onClick="@{ClipboardUtils::copyTextView}"
android:singleLine="true"
android:text="@{config.interface.keyPair.publicKey.toBase64}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/public_key_label"
tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" />
<TextView
android:id="@+id/interface_name_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/interface_name_text"
android:text="@string/name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/interface_title" />
<TextView
android:id="@+id/addresses_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/addresses_text"
android:text="@string/addresses"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/public_key_text" />
<TextView
android:id="@+id/interface_name_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/name"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{tunnel.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/interface_name_label"
tools:text="wg0" />
<TextView
android:id="@+id/addresses_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/addresses"
android:text="@{config.interface.addresses}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/addresses_label"
tools:text="fc00:bbbb:bbbb:bb11::3:368b/128" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/public_key_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/public_key_text"
android:text="@string/public_key"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/interface_name_text" />
<LinearLayout
android:id="@+id/peers_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:divider="@null"
android:orientation="vertical"
app:items="@{config.peers}"
app:layout="@{@layout/tunnel_detail_peer}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tunnel_detail_card"
tools:ignore="UselessLeaf" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/public_key_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/public_key"
android:ellipsize="end"
android:maxLines="1"
android:onClick="@{ClipboardUtils::copyTextView}"
android:singleLine="true"
android:text="@{config.interface.keyPair.publicKey.toBase64}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/public_key_label"
tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" />
<TextView
android:id="@+id/addresses_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/addresses_text"
android:text="@string/addresses"
android:visibility="@{config.interface.addresses.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/public_key_text" />
<TextView
android:id="@+id/addresses_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/addresses"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{config.interface.addresses}"
android:visibility="@{config.interface.addresses.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/addresses_label"
tools:text="fc00:bbbb:bbbb:bb11::3:368b/128" />
<TextView
android:id="@+id/dns_servers_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/dns_servers_text"
android:text="@string/dns_servers"
android:visibility="@{config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/addresses_text" />
<TextView
android:id="@+id/dns_servers_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/dns_servers"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{config.interface.dnsServers}"
android:visibility="@{config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/dns_servers_label"
tools:text="8.8.8.8, 8.8.4.4" />
<TextView
android:id="@+id/listen_port_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/listen_port_text"
android:text="@string/listen_port"
android:visibility="@{config.interface.listenPort.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintEnd_toStartOf="@id/mtu_label"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dns_servers_text" />
<TextView
android:id="@+id/listen_port_text"
style="@style/DetailText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:contentDescription="@string/listen_port"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{config.interface.listenPort}"
android:visibility="@{config.interface.listenPort.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintEnd_toStartOf="@id/mtu_label"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/listen_port_label"
tools:text="51820" />
<TextView
android:id="@+id/mtu_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/mtu_text"
android:text="@string/mtu"
android:visibility="@{config.interface.mtu.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintLeft_toRightOf="@id/listen_port_label"
app:layout_constraintStart_toEndOf="@id/listen_port_label"
app:layout_constraintTop_toBottomOf="@id/dns_servers_text" />
<TextView
android:id="@+id/mtu_text"
style="@style/DetailText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:contentDescription="@string/mtu"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{config.interface.mtu}"
android:visibility="@{config.interface.mtu.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintStart_toEndOf="@id/listen_port_label"
app:layout_constraintStart_toStartOf="@+id/mtu_label"
app:layout_constraintTop_toBottomOf="@+id/mtu_label"
tools:text="1500" />
<TextView
android:id="@+id/applications_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/applications_text"
android:text="@string/applications"
android:visibility="@{config.interface.includedApplications.isEmpty() &amp;&amp; config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/listen_port_text" />
<TextView
android:id="@+id/applications_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/applications"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{config.interface.includedApplications.isEmpty() ? @plurals/n_excluded_applications(config.interface.excludedApplications.size(), config.interface.excludedApplications.size()) : @plurals/n_included_applications(config.interface.includedApplications.size(), config.interface.includedApplications.size())}"
android:visibility="@{config.interface.includedApplications.isEmpty() &amp;&amp; config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/applications_label"
tools:text="8 excluded" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:id="@+id/peers_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:divider="@null"
android:orientation="vertical"
app:items="@{config.peers}"
app:layout="@{@layout/tunnel_detail_peer}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tunnel_detail_card"
tools:ignore="UselessLeaf" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>
+64 -8
View File
@@ -15,11 +15,7 @@
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardBackgroundColor="?attr/elevationOverlayColor"
app:cardCornerRadius="0dp"
app:cardElevation="2dp"
app:contentPadding="8dp">
android:layout_margin="8dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@@ -49,7 +45,7 @@
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/public_key_description"
android:contentDescription="@string/public_key"
android:ellipsize="end"
android:maxLines="1"
android:onClick="@{ClipboardUtils::copyTextView}"
@@ -59,6 +55,32 @@
app:layout_constraintTop_toBottomOf="@+id/public_key_label"
tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" />
<TextView
android:id="@+id/pre_shared_key_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/pre_shared_key_text"
android:text="@string/pre_shared_key"
android:visibility="@{item.preSharedKey.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/public_key_text" />
<TextView
android:id="@+id/pre_shared_key_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/pre_shared_key"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:text="@string/pre_shared_key_enabled"
android:visibility="@{item.preSharedKey.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pre_shared_key_label"
tools:text="8VyS8W8XeMcBWfKp1GuG3/fZlnUQFkqMNbrdmZtVQIM=" />
<TextView
android:id="@+id/allowed_ips_label"
android:layout_width="match_parent"
@@ -66,15 +88,19 @@
android:layout_marginTop="8dp"
android:labelFor="@+id/allowed_ips_text"
android:text="@string/allowed_ips"
android:visibility="@{item.allowedIps.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/public_key_text" />
app:layout_constraintTop_toBottomOf="@+id/pre_shared_key_text" />
<TextView
android:id="@+id/allowed_ips_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/allowed_ips"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{item.allowedIps}"
android:visibility="@{item.allowedIps.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/allowed_ips_label"
tools:text="0.0.0.0/5, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3" />
@@ -86,6 +112,7 @@
android:layout_marginTop="8dp"
android:labelFor="@+id/endpoint_text"
android:text="@string/endpoint"
android:visibility="@{item.endpoint.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/allowed_ips_text" />
@@ -94,11 +121,38 @@
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/endpoint"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{item.endpoint}"
android:visibility="@{item.endpoint.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/endpoint_label"
tools:text="192.168.0.1:51820" />
<TextView
android:id="@+id/persistent_keepalive_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:labelFor="@+id/persistent_keepalive_text"
android:text="@string/persistent_keepalive"
android:visibility="@{item.persistentKeepalive.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/endpoint_text" />
<TextView
android:id="@+id/persistent_keepalive_text"
style="@style/DetailText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/persistent_keepalive"
android:onClick="@{ClipboardUtils::copyTextView}"
android:text="@{@plurals/persistent_keepalive_seconds_unit(item.persistentKeepalive.orElse(0), item.persistentKeepalive.orElse(0))}"
android:visibility="@{item.persistentKeepalive.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/persistent_keepalive_label"
tools:text="every 3 seconds" />
<TextView
android:id="@+id/transfer_label"
android:layout_width="match_parent"
@@ -109,7 +163,7 @@
android:text="@string/transfer"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/endpoint_text"
app:layout_constraintTop_toBottomOf="@+id/persistent_keepalive_text"
tools:visibility="visible" />
<TextView
@@ -118,6 +172,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/transfer_label"
android:contentDescription="@string/transfer"
android:onClick="@{ClipboardUtils::copyTextView}"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/transfer_label"
@@ -45,11 +45,7 @@
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
app:cardBackgroundColor="?attr/elevationOverlayColor"
app:cardCornerRadius="0dp"
app:cardElevation="2dp"
app:contentPadding="8dp">
android:layout_marginBottom="16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@@ -220,8 +216,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:onClick="@{fragment::onRequestSetExcludedApplications}"
android:text="@{@plurals/set_excluded_applications(config.interface.excludedApplications.size, config.interface.excludedApplications.size)}"
android:onClick="@{fragment::onRequestSetExcludedIncludedApplications}"
android:text="@{config.interface.includedApplications.size > 0 ? @plurals/set_included_applications(config.interface.includedApplications.size, config.interface.includedApplications.size) : config.interface.excludedApplications.size > 0 ? @plurals/set_excluded_applications(config.interface.excludedApplications.size, config.interface.excludedApplications.size) : @string/all_applications}"
android:textColor="?attr/colorSecondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -8,6 +8,8 @@
<import type="com.wireguard.android.widget.KeyInputFilter" />
<import type="com.wireguard.android.databinding.BindingAdapters" />
<variable
name="collection"
type="androidx.databinding.ObservableList&lt;com.wireguard.android.viewmodel.PeerProxy&gt;" />
@@ -27,11 +29,7 @@
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
app:cardBackgroundColor="?attr/elevationOverlayColor"
app:cardCornerRadius="0dp"
app:cardElevation="2dp"
app:contentPadding="8dp">
android:layout_marginBottom="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@@ -108,6 +106,7 @@
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/persistent_keepalive"
app:suffixText="@{@plurals/persistent_keepalive_seconds_suffix(BindingAdapters.tryParseInt(item.persistentKeepalive))}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pre_shared_key_label_layout">
@@ -118,7 +117,7 @@
android:layout_height="wrap_content"
android:hint="@string/hint_optional_discouraged"
android:inputType="number"
android:text="@={item.persistentKeepalive}" />
android:text="@={item.persistentKeepalive}"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
@@ -159,7 +158,7 @@
</com.google.android.material.textfield.TextInputLayout>
<CheckBox
android:id="@+id/excluded_checkbox"
android:id="@+id/selected_checkbox"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="4dp"
@@ -66,14 +66,13 @@
android:textSize="20sp" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/create_fab"
style="@style/Widget.MaterialComponents.ExtendedFloatingActionButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:icon="@drawable/ic_action_add_white" />
app:srcCompat="@drawable/ic_action_add_white" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
+64 -29
View File
@@ -24,14 +24,47 @@
<item quantity="one">%d ausgeschlossene Anwendung</item>
<item quantity="other">%d ausgeschlossene Anwendungen</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="one">%d einbezogene Anwendung</item>
<item quantity="other">%d einbezogene Anwendungen</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="one">%d ausgeschlossen</item>
<item quantity="other">%d ausgeschlossen</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="one">%d einbezogen</item>
<item quantity="other">%d einbezogen</item>
</plurals>
<string name="all_applications">Alle Anwendungen</string>
<string name="exclude_from_tunnel">Ausschließen</string>
<string name="include_in_tunnel">Nur einbeziehen</string>
<plurals name="include_n_applications">
<item quantity="one">%d App einbeziehen</item>
<item quantity="other">%d App einbeziehen</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="one">%d App ausschließen</item>
<item quantity="other">%d App ausschließen</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="one">jede Sekunde</item>
<item quantity="other">alle %d Sekunden</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="one">Sekunde</item>
<item quantity="other">Sekunden</item>
</plurals>
<string name="use_all_applications">Alle Apps verwenden</string>
<string name="add_peer">Teilnehmer hinzufügen</string>
<string name="addresses">Adressen</string>
<string name="applications">Anwendungen</string>
<string name="allow_remote_control_intents_summary_off">Externe Apps dürfen keine Tunnel umschalten (empfohlen)</string>
<string name="allow_remote_control_intents_summary_on">Externe Apps dürfen Tunnel umschalten (erweitert)</string>
<string name="allow_remote_control_intents_title">Erlaube Steuerung über externe Apps</string>
<string name="allowed_ips">Erlaubte IPs</string>
<string name="app_name">WireGuard</string>
<string name="bad_config_context">%1$ss %2$s</string>
<string name="bad_config_context">%2$s des %1$s</string>
<string name="bad_config_context_top_level">%s</string>
<string name="bad_config_error">%1$s in %2$s</string>
<string name="bad_config_explanation_pka">: Muss positiv sein und nicht größer als 65535</string>
@@ -40,8 +73,8 @@
<string name="bad_config_reason_invalid_key">Ungültiger Schlüssel</string>
<string name="bad_config_reason_invalid_number">Ungültige Zahl</string>
<string name="bad_config_reason_invalid_value">Ungültiger Wert</string>
<string name="bad_config_reason_missing_attribute">Attribut fehlt</string>
<string name="bad_config_reason_missing_section">Fehlende Sektion</string>
<string name="bad_config_reason_missing_attribute">Fehlendes Attribut</string>
<string name="bad_config_reason_missing_section">Fehlender Abschnitt</string>
<string name="bad_config_reason_syntax_error">Syntaxfehler</string>
<string name="bad_config_reason_unknown_attribute">Unbekanntes Attribut</string>
<string name="bad_config_reason_unknown_section">Unbekannter Abschnitt</string>
@@ -56,27 +89,26 @@
<string name="config_save_error">Konfiguration für „%1$s“ kann nicht gespeichert werden: %2$s</string>
<string name="config_save_success">Konfiguration für „%s ” erfolgreich gespeichert</string>
<string name="create_activity_title">WireGuard-Tunnel erstellen</string>
<string name="create_bin_dir_error">Lokales Anwendungsverzeichnis konnte nicht erstellt werden</string>
<string name="create_downloads_file_error">Datei konnte im Download-Verzeichnis nicht erstellt werden</string>
<string name="create_bin_dir_error">Lokales Anwendungsverzeichnis kann nicht erstellt werden</string>
<string name="create_downloads_file_error">Datei kann im Download-Verzeichnis nicht erstellt werden</string>
<string name="create_empty">Neu erstellen</string>
<string name="create_from_file">Aus Datei oder Archiv importieren</string>
<string name="create_from_qr_code">Vom QR-Code scannen</string>
<string name="create_from_qr_code">Von QR-Code scannen</string>
<string name="create_output_dir_error">Konnte das Ausgabeverzeichnis nicht erstellen</string>
<string name="create_temp_dir_error">Lokales temporäres Verzeichnis konnte nicht erstellt werden</string>
<string name="create_temp_dir_error">Lokales temporäres Verzeichnis kann nicht erstellt werden</string>
<string name="create_tunnel">Tunnel erstellen</string>
<string name="dark_theme_summary_off">Helles (Tag) Design in Verwendung</string>
<string name="dark_theme_summary_on">Dunkles (Nacht) Design in Verwendung</string>
<string name="dark_theme_summary_off">Verwende helles Design (Tag)</string>
<string name="dark_theme_summary_on">Verwende dunkles Design (Nacht)</string>
<string name="dark_theme_title">Dunkles Design verwenden</string>
<string name="delete">Entfernen</string>
<string name="dns_servers">DNS-Server</string>
<string name="edit">Bearbeiten</string>
<string name="endpoint">Endpunkt</string>
<string name="error_down">Fehler beim Herunterfahren des Tunnels: %s</string>
<string name="error_down">Fehler beim Abschalten des Tunnels: %s</string>
<string name="error_fetching_apps">Fehler beim Abrufen der App-Liste: %s</string>
<string name="error_root">Bitte root-Zugriff anfordern und erneut versuchen</string>
<string name="error_up">Fehler beim Starten des Tunnels: %s</string>
<string name="exclude_private_ips">Private IPs ausschließen</string>
<string name="excluded_applications">Ausgeschlossene Anwendungen</string>
<string name="generate_new_private_key">Neuen privaten Schlüssel generieren</string>
<string name="generic_error">Unbekannter „%s“ Fehler</string>
<string name="hint_automatic">(auto)</string>
@@ -88,38 +120,38 @@
<string name="import_error">Kann Tunnel nicht importieren: %s</string>
<string name="import_from_qr_code">Tunnel aus QR-Code importieren</string>
<string name="import_success">„%s” importiert</string>
<string name="interface_title">Schnittstelle</string>
<string name="key_contents_error">Falsche Zeichen in Schlüssel</string>
<string name="interface_title">Interface</string>
<string name="key_contents_error">Unzulässige Zeichen im Schlüssel</string>
<string name="key_length_error">Falsche Schlüssellänge</string>
<string name="key_length_explanation_base64">: WireGuard base64-Schlüssel müssen 44 Zeichen enthalten (32 Bytes)</string>
<string name="key_length_explanation_binary">: WireGuard-Schlüssel müssen 32 Bytes groß sein</string>
<string name="key_length_explanation_hex">: WireGuard Hex-Schlüssel müssen 64 Zeichen (32 Bytes) groß sein</string>
<string name="listen_port">Eingangs-Port</string>
<string name="log_export_error">Fehler beim Exportieren des Logs: %s</string>
<string name="log_export_subject">WireGuard Android Log Datei</string>
<string name="log_export_error">Konnte Protokoll nicht exportieren: %s</string>
<string name="log_export_subject">WireGuard Android Protokolldatei</string>
<string name="log_export_success">Gespeichert in „%s”</string>
<string name="log_export_title">Logdatei exportieren</string>
<string name="log_saver_activity_label">Log speichern</string>
<string name="log_viewer_pref_summary">Logs können beim Debuggen helfen</string>
<string name="log_viewer_pref_title">Protokoll der Anwendung anzeigen</string>
<string name="log_viewer_title">Loggen</string>
<string name="log_saver_activity_label">Protokoll speichern</string>
<string name="log_viewer_pref_summary">Protokolle können beim Debuggen helfen</string>
<string name="log_viewer_pref_title">Anwendungs-Protokoll anzeigen</string>
<string name="log_viewer_title">Protokoll</string>
<string name="logcat_error">Konnte logcat nicht ausführen: </string>
<string name="module_disabler_disabled_summary">Das experimentelle Kernelmodul kann die Leistung verbessern</string>
<string name="module_disabler_disabled_title">Kernelmodul-Backend aktivieren</string>
<string name="module_disabler_enabled_summary">Das langsamere Userspace-Backend kann die Stabilität verbessern</string>
<string name="module_disabler_enabled_title">Kernelmodul-Backend deaktivieren</string>
<string name="module_installer_error">Es ist etwas schief gelaufen. Bitte versuchen Sie es später erneut</string>
<string name="module_installer_error">Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut</string>
<string name="module_installer_initial">Das experimentelle Kernelmodul kann die Leistung verbessern</string>
<string name="module_installer_not_found">Für Ihr Gerät sind keine Module verfügbar</string>
<string name="module_installer_title">Kernelmodul herunterladen und installieren</string>
<string name="module_installer_working">Herunterladen und Installieren…</string>
<string name="module_installer_working">Lade herunter und installiere…</string>
<string name="module_version_error">Konnte Version des Kernel-Moduls nicht ermitteln</string>
<string name="mtu">MTU</string>
<string name="multiple_tunnels_summary_off">Einschalten eines Tunnels wird andere ausschalten</string>
<string name="multiple_tunnels_summary_on">Mehrere Tunnel können gleichzeitig aktiviert werden</string>
<string name="multiple_tunnels_title">Erlaube mehrere Tunnel gleichzeitig</string>
<string name="multiple_tunnels_summary_off">Das einschalten eines Tunnels wird andere ausschalten</string>
<string name="multiple_tunnels_summary_on">Mehrere Tunnel können gleichzeitig aktiviert sein</string>
<string name="multiple_tunnels_title">Erlaube mehrere gleichzeitige Tunnel</string>
<string name="name">Name</string>
<string name="no_config_error">Versucht einen Tunnel ohne Konfiguration zu starten</string>
<string name="no_config_error">Es wurde versucht, einen Tunnel ohne Konfiguration zu starten</string>
<string name="no_configs_error">Keine Konfigurationen gefunden</string>
<string name="no_tunnels_error">Keine Tunnel vorhanden</string>
<string name="parse_error_generic">String (Zeichenkette)</string>
@@ -133,16 +165,15 @@
<string name="permission_label">WireGuard-Tunnel steuern</string>
<string name="persistent_keepalive">Dauerhafte Erhaltung</string>
<string name="pre_shared_key">Vorab geteilter Schlüssel</string>
<string name="pre_shared_key_enabled">aktiviert</string>
<string name="private_key">Privater Schlüssel</string>
<string name="public_key">Öffentlicher Schlüssel</string>
<string name="public_key_description">Öffentlicher Schlüssel</string>
<string name="qr_code_hint">Tipp: Mit `qrencode -t ansiutf8 &lt; tunnel.conf` generieren.</string>
<string name="restore_on_boot_summary_off">Wird aktivierte Tunnel beim Systemstart nicht automatisch starten</string>
<string name="restore_on_boot_summary_on">Wird aktivierte Tunnel beim Systemstart automatisch wieder starten</string>
<string name="restore_on_boot_summary_off">Aktivierte Tunnel beim Systemstart nicht automatisch starten</string>
<string name="restore_on_boot_summary_on">Aktivierte Tunnel beim Systemstart automatisch wieder starten</string>
<string name="restore_on_boot_title">Beim Neustart wiederherstellen</string>
<string name="save">Speichern</string>
<string name="select_all">Alle auswählen</string>
<string name="set_exclusions">Ausnahmen festlegen</string>
<string name="settings">Einstellungen</string>
<string name="shell_exit_status_read_error">Shell kann den Exit-Status nicht lesen</string>
<string name="shell_marker_count_error">Die Shell erwartete 4 Marker, erhielt aber %d</string>
@@ -191,4 +222,8 @@
<string name="zip_export_success">Gespeichert unter “%s”</string>
<string name="zip_export_summary">Zip-Datei wird im Download-Verzeichnis gespeichert</string>
<string name="zip_export_title">Tunnel als Zip-Datei exportieren</string>
<string name="biometric_prompt_zip_exporter_title">Authentifizieren, um Tunnel zu exportieren</string>
<string name="biometric_prompt_private_key_title">Authentifizieren, um privaten Schlüssel anzuzeigen</string>
<string name="biometric_auth_error">Authentifizierungsfehler</string>
<string name="biometric_auth_error_reason">Authentifizierungsfehler: %s</string>
</resources>
+229
View File
@@ -0,0 +1,229 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="delete_error">
<item quantity="one">Impossible de supprimer %d tunnel : %s</item>
<item quantity="other">Impossible de supprimer %d tunnels : %s</item>
</plurals>
<plurals name="delete_success">
<item quantity="one">Supprimé avec succès %d tunnel</item>
<item quantity="other">Supprimé avec succès %d tunnels</item>
</plurals>
<plurals name="delete_title">
<item quantity="one">%d tunnel sélectionné</item>
<item quantity="other">%d tunnels sélectionnés</item>
</plurals>
<plurals name="import_partial_success">
<item quantity="one">%1$d de %2$d tunnels importés</item>
<item quantity="other">%1$d de %2$d tunnels importés</item>
</plurals>
<plurals name="import_total_success">
<item quantity="one">%d tunnel importé</item>
<item quantity="other">%d tunnels importés</item>
</plurals>
<plurals name="set_excluded_applications">
<item quantity="one">%d application exclue</item>
<item quantity="other">%d applications exclues</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="one">%d application incluse</item>
<item quantity="other">%d applications incluses</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="one">%d exclue</item>
<item quantity="other">%d exclues</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="one">%d incluse</item>
<item quantity="other">%d incluses</item>
</plurals>
<string name="all_applications">Toutes les Applications</string>
<string name="exclude_from_tunnel">Exclure</string>
<string name="include_in_tunnel">Inclure uniquement</string>
<plurals name="include_n_applications">
<item quantity="one">Inclure %d application</item>
<item quantity="other">Inclure %d applications</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="one">Exclure %d application</item>
<item quantity="other">Exclure %d applications</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="one">chaque seconde</item>
<item quantity="other">tous les %d secondes</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="one">seconde</item>
<item quantity="other">secondes</item>
</plurals>
<string name="use_all_applications">Utiliser toutes les applications</string>
<string name="add_peer">Ajouter un pair</string>
<string name="addresses">Adresses</string>
<string name="applications">Applications</string>
<string name="allow_remote_control_intents_summary_off">Les applications externes ne peuvent pas activer les tunnels (recommandé)</string>
<string name="allow_remote_control_intents_summary_on">Les applications externes peuvent activer les tunnels (avancés)</string>
<string name="allow_remote_control_intents_title">Autoriser les applications de contrôle à distance</string>
<string name="allowed_ips">Adresses IP autorisées</string>
<string name="app_name">WireGuard</string>
<string name="bad_config_context">%1$s de %2$s</string>
<string name="bad_config_context_top_level">%s</string>
<string name="bad_config_error">%1$s dans %2$s</string>
<string name="bad_config_explanation_pka">: Doit être positif et ne pas dépasser 65535</string>
<string name="bad_config_explanation_positive_number">: Doit être positif</string>
<string name="bad_config_explanation_udp_port">: Doit être un numéro de port UDP valide</string>
<string name="bad_config_reason_invalid_key">Clef invalide</string>
<string name="bad_config_reason_invalid_number">Numéro invalide</string>
<string name="bad_config_reason_invalid_value">Valeur invalide</string>
<string name="bad_config_reason_missing_attribute">Attribut manquant</string>
<string name="bad_config_reason_missing_section">Section manquante</string>
<string name="bad_config_reason_syntax_error">Erreur de syntaxe</string>
<string name="bad_config_reason_unknown_attribute">Attribut inconnu</string>
<string name="bad_config_reason_unknown_section">Section inconnue</string>
<string name="bad_config_reason_value_out_of_range">Valeur hors limite</string>
<string name="bad_extension_error">Le fichier doit être .conf ou .zip</string>
<string name="cancel">Annuler</string>
<string name="config_delete_error">Impossible de supprimer le fichier de configuration %s</string>
<string name="config_exists_error">La configuration de « %s » existe déjà</string>
<string name="config_file_exists_error">Le fichier de configuration « %s » existe déjà</string>
<string name="config_not_found_error">Fichier de configuration «%s» introuvable</string>
<string name="config_rename_error">Impossible de renommer le fichier de configuration «%s»</string>
<string name="config_save_error">Impossible d’enregistrer la configuration pour «%1$s» : %2$s</string>
<string name="config_save_success">Configuration enregistrée avec succès pour “%s”</string>
<string name="create_activity_title">Créer un tunnel WireGuard</string>
<string name="create_bin_dir_error">Impossible de créer le répertoire binaire local</string>
<string name="create_downloads_file_error">Impossible de créer le fichier dans le répertoire des téléchargements</string>
<string name="create_empty">Créer à partir de zéro</string>
<string name="create_from_file">Importer depuis un fichier ou une archive</string>
<string name="create_from_qr_code">Créer avec un scan de QR code</string>
<string name="create_output_dir_error">Impossible de créer le répertoire de sortie</string>
<string name="create_temp_dir_error">Impossible de créer le répertoire temporaire local</string>
<string name="create_tunnel">Créer un tunnel</string>
<string name="dark_theme_summary_off">Utilisation en cours du thème clair (jour)</string>
<string name="dark_theme_summary_on">Utilisation en cours du thème sombre (nuit)</string>
<string name="dark_theme_title">Utilisez le thème sombre</string>
<string name="delete">Supprimer</string>
<string name="dns_servers">Serveurs DNS</string>
<string name="edit">Modifier</string>
<string name="endpoint">Point de terminaison</string>
<string name="error_down">Erreur lors de la désactivation du tunnel : %s</string>
<string name="error_fetching_apps">Erreur lors de la récupération de la liste d\'applications : %s</string>
<string name="error_root">Veuillez obtenir l\'accès root et essayez à nouveau</string>
<string name="error_up">Erreur lors de la mise en place du tunnel : %s</string>
<string name="exclude_private_ips">Exclure les IPs privées</string>
<string name="generate_new_private_key">Générer une nouvelle clé privée</string>
<string name="generic_error">Erreur inconnue « %s »</string>
<string name="hint_automatic">(auto)</string>
<string name="hint_generated">(généré)</string>
<string name="hint_optional">(facultatif)</string>
<string name="hint_optional_discouraged">(facultatif, non recommandé)</string>
<string name="hint_random">(aléatoire)</string>
<string name="illegal_filename_error">Nom de fichier invalide “%s”</string>
<string name="import_error">Impossible d\'importer le tunnel : %s</string>
<string name="import_from_qr_code">Importer un tunnel depuis un QR-code</string>
<string name="import_success">Importé «%s »</string>
<string name="interface_title">Interface</string>
<string name="key_contents_error">Mauvais caractères dans la clé</string>
<string name="key_length_error">Longueur de la clé incorrecte</string>
<string name="key_length_explanation_base64">: Les clés base64 WireGuard doivent comporter 44 caractères (32 octets)</string>
<string name="key_length_explanation_binary">: Les clés WireGuard doivent comporter 32 octets</string>
<string name="key_length_explanation_hex">: Les clés hexadécimales WireGuard doivent comporter 64 caractères (32 octets)</string>
<string name="listen_port">Port d\'écoute</string>
<string name="log_export_error">Impossible d\'exporter le journal : %s</string>
<string name="log_export_subject">Fichier journal d\'Android WireGuard</string>
<string name="log_export_success">Enregistré dans « %s »</string>
<string name="log_export_title">Exporter le fichier journal</string>
<string name="log_saver_activity_label">Enregistrer le journal</string>
<string name="log_viewer_pref_summary">Les journaux peuvent aider au débogage</string>
<string name="log_viewer_pref_title">Afficher le journal de l\'application</string>
<string name="log_viewer_title">Journal</string>
<string name="logcat_error">Impossible d\'exécuter logcat : </string>
<string name="module_disabler_disabled_summary">Le module expérimental du noyau peut améliorer les performances</string>
<string name="module_disabler_disabled_title">Activer le backend du module du noyau</string>
<string name="module_disabler_enabled_summary">Le backend plus lent de l\'espace utilisateur peut améliorer la stabilité</string>
<string name="module_disabler_enabled_title">Désactiver le backend du module du noyau</string>
<string name="module_installer_error">Une erreur est survenue. Veuillez réessayer</string>
<string name="module_installer_initial">Le module expérimental du noyau peut améliorer les performances</string>
<string name="module_installer_not_found">Aucun module n\'est disponible pour votre appareil</string>
<string name="module_installer_title">Télécharger et installer le module du noyau</string>
<string name="module_installer_working">Téléchargement et installation en cours…</string>
<string name="module_version_error">Impossible de déterminer la version du module noyau</string>
<string name="mtu">MTU</string>
<string name="multiple_tunnels_summary_off">Activer un tunnel éteindra les autres</string>
<string name="multiple_tunnels_summary_on">Plusieurs tunnels peuvent être activés simultanément</string>
<string name="multiple_tunnels_title">Autoriser plusieurs tunnels simultanés</string>
<string name="name">Nom</string>
<string name="no_config_error">Tentative d\'établir un tunnel sans configuration</string>
<string name="no_configs_error">Aucune configuration trouvée</string>
<string name="no_tunnels_error">Aucun tunnel existant</string>
<string name="parse_error_generic">chaîne de caractères</string>
<string name="parse_error_inet_address">Adresse IP</string>
<string name="parse_error_inet_endpoint">point de terminaison</string>
<string name="parse_error_inet_network">Réseau IP</string>
<string name="parse_error_integer">nombre</string>
<string name="parse_error_reason">Impossible d\'analyser %1$s “%2$s”</string>
<string name="peer">Pair</string>
<string name="permission_description">contrôler les tunnels WireGuard, activer et désactiver les tunnels à volonté, potentiellement détourner le trafic Internet</string>
<string name="permission_label">contrôler les tunnels WireGuard</string>
<string name="persistent_keepalive">Maintien de connexion permanente</string>
<string name="pre_shared_key">Clé pré-partagée</string>
<string name="pre_shared_key_enabled">activée</string>
<string name="private_key">Clé privée</string>
<string name="public_key">Clé publique</string>
<string name="qr_code_hint">Astuce : générez avec \"qrencode -t ansiutf8 &lt; tunnel.conf\".</string>
<string name="restore_on_boot_summary_off">N\'affichera pas les tunnels activés au démarrage</string>
<string name="restore_on_boot_summary_on">Les tunnels activés seront affichés au démarrage</string>
<string name="restore_on_boot_title">Restaurer au démarrage</string>
<string name="save">Enregistrer</string>
<string name="select_all">Tout sélectionner</string>
<string name="settings">Paramètres</string>
<string name="shell_exit_status_read_error">L\'interpréteur de commande ne peut pas lire l\'état de sortie</string>
<string name="shell_marker_count_error">L\'interpréteur de commandes attendait 4 marqueurs, %d reçus</string>
<string name="shell_start_error">L\'interpréteur de commande n\'a pas pu démarrer : %d</string>
<string name="success_application_will_restart">Succès. L\'application va redémarrer maintenant…</string>
<string name="toggle_all">Tout basculer</string>
<string name="toggle_error">Erreur lors de l\'activation du tunnel WireGuard : %s</string>
<string name="tools_installer_already">wg et wg-quick sont déjà installés</string>
<string name="tools_installer_failure">Impossible d\'installer les outils en ligne de commande (pas de root?)</string>
<string name="tools_installer_initial">Installer les outils optionnels pour le script</string>
<string name="tools_installer_initial_magisk">Installer les outils optionnels pour le script en tant que module Magisk</string>
<string name="tools_installer_initial_system">Installer les outils optionnels pour le script dans la partition système</string>
<string name="tools_installer_success_magisk">wg et wg-quick installés en tant que module Magisk (redémarrage requis)</string>
<string name="tools_installer_success_system">wg et wg-quick installés dans la partition système</string>
<string name="tools_installer_title">Installer les outils de ligne de commande</string>
<string name="tools_installer_working">Installation de wg et wg-quick</string>
<string name="tools_unavailable_error">Outils requis indisponibles</string>
<string name="transfer">Transférer</string>
<string name="transfer_bytes">%d Octets</string>
<string name="transfer_gibibytes">%.2f Go</string>
<string name="transfer_kibibytes">%.2f Ko</string>
<string name="transfer_mibibytes">%.2f Mo</string>
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
<string name="transfer_tibibytes">%.2f To</string>
<string name="tun_create_error">Impossible de créer le périphérique tun</string>
<string name="tunnel_config_error">Impossible de configurer le tunnel (wg-quick a retourné %d)</string>
<string name="tunnel_create_error">Impossible de créer le tunnel : %s</string>
<string name="tunnel_create_success">Tunnel «%s » créé avec succès</string>
<string name="tunnel_error_already_exists">Le tunnel « %s » existe déjà</string>
<string name="tunnel_error_invalid_name">Nom invalide</string>
<string name="tunnel_list_placeholder">Ajouter un tunnel en utilisant le bouton bleu</string>
<string name="tunnel_name">Nom du tunnel</string>
<string name="tunnel_on_error">Impossible d\'activer le tunnel (wgTurnOn a retourné %d)</string>
<string name="tunnel_rename_error">Impossible de renommer le tunnel : %s</string>
<string name="tunnel_rename_success">Tunnel renommé avec succès en «%s »</string>
<string name="type_name_go_userspace">Nom de l\'espace utilisateur</string>
<string name="type_name_kernel_module">Module noyau</string>
<string name="unknown_error">Erreur inconnue</string>
<string name="version_summary">%1$s backend v%2$s</string>
<string name="version_summary_checking">Vérification de la version %s du backend</string>
<string name="version_summary_unknown">Version %s inconnue</string>
<string name="version_title">WireGuard pour Android v%s</string>
<string name="vpn_not_authorized_error">Service VPN non autorisé par l\'utilisateur</string>
<string name="vpn_start_error">Impossible de démarrer le service VPN Android</string>
<string name="zip_export_error">Impossible d\'exporter les tunnels : %s</string>
<string name="zip_export_success">Enregistré dans « %s »</string>
<string name="zip_export_summary">L\'archive zip sera sauvegardée dans le dossier de téléchargement</string>
<string name="zip_export_title">Exporter les tunnels vers le fichier zip</string>
<string name="biometric_prompt_zip_exporter_title">S\'authentifier pour exporter des tunnels</string>
<string name="biometric_prompt_private_key_title">S\'authentifier pour voir la clé privée</string>
<string name="biometric_auth_error">Échec de l\'authentification</string>
<string name="biometric_auth_error_reason">Échec de l\'authentification : %s</string>
</resources>
-3
View File
@@ -72,7 +72,6 @@
<string name="error_root">कृपया रूट एक्सेस प्राप्त करें और पुनः प्रयास करें</string>
<string name="error_up">टनल को लाने में त्रुटि: %s</string>
<string name="exclude_private_ips">निजी आईपी को छोड़ दें</string>
<string name="excluded_applications">निकाले गए ऐप्स</string>
<string name="generic_error">अज्ञात “%s” त्रुटि</string>
<string name="hint_automatic">(ऑटो)</string>
<string name="hint_generated">(उत्पन्न)</string>
@@ -121,14 +120,12 @@
<string name="pre_shared_key">प्री-शेयर्ड कीस</string>
<string name="private_key">निजी कीस</string>
<string name="public_key">सार्वजनिक कीस</string>
<string name="public_key_description">सार्वजनिक कीस</string>
<string name="qr_code_hint">सुझाव: `qrencode -t ansiutf8 &lt; tunnel.conf` के साथ उत्पन्न करो</string>
<string name="restore_on_boot_summary_on">बूट पर सक्षम टनलस को लाएगा</string>
<string name="restore_on_boot_summary_off">बूट पर सक्षम टनलस को नहीं लाएगा</string>
<string name="restore_on_boot_title">बूट पर पुनर्स्थापित करें</string>
<string name="save">सहेजें</string>
<string name="select_all">सभी का चयन करे</string>
<string name="set_exclusions">बहिष्करण सेट करें</string>
<string name="settings">सेटिंग्स</string>
<string name="shell_exit_status_read_error">शेल बाहर निकलने की स्थिति नहीं पढ़ सकता</string>
<string name="shell_marker_count_error">शेल ने 4 मार्करों की अपेक्षा की, %d प्राप्त किया</string>
+93 -58
View File
@@ -1,112 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="delete_error">
<item quantity="one">Tidak dapat menghapus %d tunel: %s</item>
<item quantity="other">Tidak dapat menghapus %d tunel: %s</item>
<item quantity="other">Tidak dapat menghapus %d terowongan: %s</item>
</plurals>
<plurals name="delete_success">
<item quantity="one">Berhasil menghapus tunel %d</item>
<item quantity="other">Berhasil menghapus tunel %d</item>
<item quantity="other">Berhasil menghapus terowongan %d</item>
</plurals>
<plurals name="delete_title">
<item quantity="one">%d tunnel dipilih</item>
<item quantity="other">%d tunel dipilih</item>
<item quantity="other">%d terowongan dipilih</item>
</plurals>
<plurals name="import_partial_success">
<item quantity="one">Mengimpor tunel %d dari %d</item>
<item quantity="other">Mengimpor tunel %d dari %d</item>
<item quantity="other">Mengimpor %1$d terowongan dari %2$d</item>
</plurals>
<plurals name="import_total_success">
<item quantity="one">Mengimpor tunel %d</item>
<item quantity="other">Mengimpor tunel %d</item>
<item quantity="other">Mengimpor %d terowongan</item>
</plurals>
<plurals name="set_excluded_applications">
<item quantity="one">%d Aplikasi dikecualikan</item>
<item quantity="other">%d Aplikasi dikecualikan</item>
<item quantity="other">%d Aplikasi Dikecualikan</item>
</plurals>
<string name="add_peer">Tambahkan peer</string>
<plurals name="set_included_applications">
<item quantity="other">%d Aplikasi Dikecualikan</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="other">%d dikecualikan</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="other">%d termasuk</item>
</plurals>
<string name="all_applications">Semua aplikasi</string>
<string name="exclude_from_tunnel">Kecualikan</string>
<string name="include_in_tunnel">Berlaku hanya untuk</string>
<plurals name="include_n_applications">
<item quantity="other">Aplikasi %d yang disertakan</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="other">Aplikasi %d yang disertakan</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="other">setiap 10 detik</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="other">detik</item>
</plurals>
<string name="use_all_applications">Gunakan semua aplikasi</string>
<string name="add_peer">Tambahkan rekan</string>
<string name="addresses">Alamat</string>
<string name="applications">Aplikasi</string>
<string name="allow_remote_control_intents_summary_off">Apl eksternal tidak dapat mengalihkan tunnel (disarankan)</string>
<string name="allow_remote_control_intents_summary_on">Apl eksternal dapat mengalihkan tunnel (lanjutan)</string>
<string name="allow_remote_control_intents_title">Izinkan apl kendali jarak jauh</string>
<string name="allowed_ips">IP diizinkan</string>
<string name="app_name">WireGuard</string>
<string name="bad_config_context">%1$s\'s %2$s</string>
<string name="bad_config_context">%1$s %2$s</string>
<string name="bad_config_context_top_level">%s</string>
<string name="bad_config_error">%1$s di %2$s</string>
<string name="bad_config_explanation_pka">: Harus positif dan tidak lebih dari 65535</string>
<string name="bad_config_explanation_positive_number">: Angka harus positif</string>
<string name="bad_config_explanation_udp_port">: Harus nomor port UDP yang valid</string>
<string name="bad_config_reason_invalid_key">Kunci tidak valid</string>
<string name="bad_config_reason_invalid_number">Angka tidak valid</string>
<string name="bad_config_reason_invalid_value">Nilai tidak valid</string>
<string name="bad_config_reason_missing_attribute">Atribut yang hilang</string>
<string name="bad_config_reason_missing_section">Bagian yang hilang</string>
<string name="bad_config_reason_syntax_error">Kesalahan sintaks</string>
<string name="bad_config_reason_unknown_attribute">Atribut tidak diketahui</string>
<string name="bad_config_reason_unknown_section">Bagian tidak diketahui</string>
<string name="bad_config_reason_value_out_of_range">Nilai di luar jangkauan</string>
<string name="bad_extension_error">File harus .conf atau .zip</string>
<string name="cancel">Kembali</string>
<string name="config_delete_error">Tidak dapat menghapus file konfigurasi %s</string>
<string name="config_exists_error">Konfigurasi untuk “%s” sudah ada</string>
<string name="config_file_exists_error">Konfigurasi file “%s” sudah ada</string>
<string name="config_not_found_error">Konfigurasi file “%s” tidak ditemukan</string>
<string name="config_rename_error">Nama konfigurasi “%s” Tidak bisa diganti</string>
<string name="bad_config_explanation_positive_number">: Harus positif</string>
<string name="bad_config_explanation_udp_port">: Harus nomor porta UDP yang sah</string>
<string name="bad_config_reason_invalid_key">Kunci tidak sah</string>
<string name="bad_config_reason_invalid_number">Bilngan tidak sah</string>
<string name="bad_config_reason_invalid_value">Nilai tidak sah</string>
<string name="bad_config_reason_missing_attribute">Atribut hilang</string>
<string name="bad_config_reason_missing_section">Bagian hilang</string>
<string name="bad_config_reason_syntax_error">Galat sintaks</string>
<string name="bad_config_reason_unknown_attribute">Atribut tak diketahui</string>
<string name="bad_config_reason_unknown_section">Bagian tak diketahui</string>
<string name="bad_config_reason_value_out_of_range">Nilai di luar rentang</string>
<string name="bad_extension_error">Berkas harus .conf atau .zip</string>
<string name="cancel">Batalkan</string>
<string name="config_delete_error">Tidak dapat menghapus berkas konfigurasi %s</string>
<string name="config_exists_error">Sudah ada konfigurasi untuk “%s”</string>
<string name="config_file_exists_error">Sudah ada konfigurasi berkas “%s”</string>
<string name="config_not_found_error">Tidak menemukan konfigurasi berkas “%s”</string>
<string name="config_rename_error">Tidak bisa mengganti nama konfigurasi “%s”</string>
<string name="config_save_error">Konfigurasi “%1$s”: %2$s tidak bisa disimpan</string>
<string name="config_save_success">Konfigurasi “%s” berhasil disimpan</string>
<string name="create_activity_title">Buat tunel WireGuard</string>
<string name="create_bin_dir_error">Tidak dapat membuat direktori biner lokal</string>
<string name="create_empty">Buat dari awal</string>
<string name="create_output_dir_error">Tidak dapat membuat direktori keluaran</string>
<string name="create_downloads_file_error">Tidak dapat membuat file di direktori download</string>
<string name="create_empty">Buat dari awal</string>
<string name="create_from_file">Impor dari berkas atau arsip</string>
<string name="create_from_qr_code">Pindai dari kode QR</string>
<string name="create_output_dir_error">Tidak dapat membuat direktori keluaran</string>
<string name="create_temp_dir_error">Tidak dapat membuat direktori lokal sementara</string>
<string name="create_tunnel">Buat tunel</string>
<string name="dark_theme_summary_off">Saat ini menggunakan tema terang (siang)</string>
<string name="dark_theme_summary_on">Saat ini menggunakan tema gelap (malam)</string>
<string name="dark_theme_title">Gunakan tema gelap</string>
<string name="delete">Hapus</string>
<string name="toggle_all">Matikan semua</string>
<string name="dns_servers">Server DNS</string>
<string name="edit">Edit</string>
<string name="endpoint">Titik akhir</string>
<string name="error_down">Kesalahan mengurangi tunel: %s</string>
<string name="endpoint">Endpoint</string>
<string name="error_down">Kesalahan pada tunel: %s</string>
<string name="error_fetching_apps">Kesalahan mengambil daftar aplikasi: %s</string>
<string name="error_root">Izinkan akses root dan coba lagi</string>
<string name="error_up">Kesalahan menambahkan tunel: %s</string>
<string name="error_up">Kesalahan pada tunel: %s</string>
<string name="exclude_private_ips">Kecualikan IP pribadi</string>
<string name="excluded_applications">Kecualikan aplikasi</string>
<string name="generate_new_private_key">Buat kunci privat baru</string>
<string name="generic_error">Eror “%s” Tidak diketahui</string>
<string name="hint_automatic">(otomatis)</string>
<string name="hint_generated">(generate)</string>
<string name="hint_optional">(pilihan)</string>
<string name="hint_optional_discouraged">(opsional, tidak disarankan)</string>
<string name="hint_random">(acak)</string>
<string name="illegal_filename_error">Nama file “%s” ilegal</string>
<string name="import_error">Tunel %s tidak bisa diimpor</string>
<string name="import_from_qr_code">Mengimpor tunel dari kode QR</string>
<string name="import_success">“%s” Sudah diimpor</string>
<string name="interface_title">Antarmuka</string>
<string name="key_contents_error">Karakter buruk pada kunci</string>
<string name="key_length_error">Panjang kunci salah</string>
<string name="key_length_explanation_base64">: Kunci WireGuard base64 harus terdiri dari 44 karakter (32 bit)</string>
<string name="key_length_explanation_binary">: Kunci WireGuard harus terdiri dari 32 bit</string>
<string name="key_length_explanation_hex">: Kunci hex WireGuard Harus terdiri dari 64 karakter (32 bit)</string>
<string name="listen_port">Isi port</string>
<string name="log_export_error">Log tidak bisa diekspor: %s</string>
<string name="log_export_subject">Berkas Log WireGuard Android</string>
<string name="log_export_success">Simpan ke “%s”</string>
<string name="log_export_title">Ekspor file log</string>
<string name="log_saver_activity_label">Simpan log</string>
<string name="log_viewer_pref_summary">Log dapat membantu dengan pengawakutuan</string>
<string name="log_viewer_pref_title">Lihat log aplikasi</string>
<string name="log_viewer_title">Log</string>
<string name="logcat_error">Tidak bisa menjalankan logcat: </string>
<string name="module_version_error">Tidak dapat menentukan versi modul kernel</string>
<string name="module_installer_not_found">Tidak tersedia modul untuk perangkat anda</string>
<string name="module_disabler_disabled_summary">Modul kernel eksperimental dapat meningkatkan kinerja</string>
<string name="module_disabler_disabled_title">Aktifkan backend modul kernel</string>
<string name="module_disabler_enabled_summary">Backend userspace yang lebih lambat dapat meningkatkan stabilitas</string>
<string name="module_disabler_enabled_title">Nonaktifkan backend modul kernel</string>
<string name="module_installer_error">Ada yang salah. Silakan coba lagi</string>
<string name="module_installer_initial">Modul kernel eksperimental dapat meningkatkan kinerja</string>
<string name="module_installer_not_found">Tidak tersedia modul untuk perangkat anda</string>
<string name="module_installer_title">Unduh dan pasang modul kernel</string>
<string name="module_installer_working">Mengunduh and memasang…</string>
<string name="module_installer_error">Ada yang salah. Silakan coba lagi</string>
<string name="module_disabler_disabled_title">Aktifkan backend modul kernel</string>
<string name="module_disabler_disabled_summary">Modul kernel eksperimental dapat meningkatkan kinerja</string>
<string name="module_disabler_enabled_title">Nonaktifkan backend modul kernel</string>
<string name="module_disabler_enabled_summary">Backend userspace yang lebih lambat dapat meningkatkan stabilitas</string>
<string name="success_application_will_restart">Berhasil. Sekarang aplikasi akan memulai ulang…</string>
<string name="module_version_error">Tidak dapat menentukan versi modul kernel</string>
<string name="mtu">MTU</string>
<string name="multiple_tunnels_title">Izinkan beberapa sekaligus tunel</string>
<string name="multiple_tunnels_summary_on">Beberapa tunel dapat dihidupkan secara bersamaan</string>
<string name="multiple_tunnels_summary_off">Menyalakan satu tunel akan mematikan semuanya</string>
<string name="name">Name</string>
<string name="multiple_tunnels_summary_on">Beberapa tunel dapat dihidupkan secara bersamaan</string>
<string name="multiple_tunnels_title">Izinkan beberapa sekaligus tunel</string>
<string name="name">Nama</string>
<string name="no_config_error">Lihat tunel tanpa konfigurasi</string>
<string name="no_configs_error">Tidak ditemukan konfigurasi</string>
<string name="no_tunnels_error">Tidak ada tunel</string>
@@ -116,24 +147,26 @@
<string name="parse_error_inet_network">Jaringan IP</string>
<string name="parse_error_integer">angka</string>
<string name="parse_error_reason">%1$s “%2$s” Tidak dapat diuraikan</string>
<string name="peer">Peer</string>
<string name="peer">Rekan</string>
<string name="permission_description">mengontrol terowongan WireGuard, mengaktifkan dan menonaktifkannya sesuka hati, berpotensi salah melalu lintas Internet</string>
<string name="permission_label">Kontrol tunel WireGuard</string>
<string name="persistent_keepalive">Keepalive persisten</string>
<string name="pre_shared_key">Kunci Pra-bersama</string>
<string name="pre_shared_key_enabled">diaktifkan</string>
<string name="private_key">Kunci pribadi</string>
<string name="public_key">Kunci publik</string>
<string name="public_key_description">Kunci publik</string>
<string name="qr_code_hint">Tips: generate dengan `qrencode -t ansiutf8 &lt; tunnel.conf`.</string>
<string name="restore_on_boot_summary_on">Tunel yang diaktifkan akan dimunculkan saat boot</string>
<string name="restore_on_boot_summary_off">Tunel yang diaktifkan tidak akan ditampilkan saat boot</string>
<string name="restore_on_boot_summary_on">Tunel yang diaktifkan akan dimunculkan saat boot</string>
<string name="restore_on_boot_title">Pulihkan saat boot</string>
<string name="save">Simpan</string>
<string name="select_all">Pilih semua</string>
<string name="set_exclusions">Tetapkan pengecualian</string>
<string name="settings">Pengaturan</string>
<string name="shell_exit_status_read_error">Shell tidak dapat membaca status keluar</string>
<string name="shell_marker_count_error">Shell diharapkan 4 nilai, diterima %d</string>
<string name="shell_start_error">Gagal memulai shell: %d</string>
<string name="success_application_will_restart">Berhasil. Sekarang aplikasi akan memulai ulang…</string>
<string name="toggle_all">Matikan semua</string>
<string name="toggle_error">Tunel WireGuard %s gagal dialihkan</string>
<string name="tools_installer_already">wg and wg-quick sudah terpasang</string>
<string name="tools_installer_failure">Tidak dapat memasang alat command-line (tidak root?)</string>
@@ -146,11 +179,11 @@
<string name="tools_installer_working">Memasang wg and wg-quick</string>
<string name="tools_unavailable_error">Alat yang diperlukan tidak tersedia</string>
<string name="transfer">Transfer</string>
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
<string name="transfer_bytes">%d B</string>
<string name="transfer_gibibytes">%.2f GiB</string>
<string name="transfer_kibibytes">%.2f KiB</string>
<string name="transfer_mibibytes">%.2f MiB</string>
<string name="transfer_gibibytes">%.2f GiB</string>
<string name="transfer_rx_tx">trm: %1$s, krm: %2$s</string>
<string name="transfer_tibibytes">%.2f TiB</string>
<string name="tun_create_error">Tidak dapat membuat perangkat tun</string>
<string name="tunnel_config_error">Tidak bisa mengkonfigurasikan tunel (wg-quick %d dikembalikan)</string>
@@ -176,6 +209,8 @@
<string name="zip_export_success">Disimpan ke “%s”</string>
<string name="zip_export_summary">File Zip akan disimpan di folder download</string>
<string name="zip_export_title">Ekspor tunel ke file zip</string>
<string name="key_length_error">Panjang kunci salah</string>
<string name="key_contents_error">Karakter buruk pada kunci</string>
<string name="biometric_prompt_zip_exporter_title">Otentikasi untuk mengekspor terowongan</string>
<string name="biometric_prompt_private_key_title">Otentikasi untuk melihat kunci privat</string>
<string name="biometric_auth_error">Otentikasi gagal</string>
<string name="biometric_auth_error_reason">Otentikasi gagal: %s</string>
</resources>
+38 -3
View File
@@ -24,8 +24,41 @@
<item quantity="one">%d applicazione esclusa</item>
<item quantity="other">%d applicazioni escluse</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="one">%d applicazione esclusa</item>
<item quantity="other">%d applicazioni incluse</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="one">%d escluse</item>
<item quantity="other">%d escluse</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="one">%d escluse</item>
<item quantity="other">%d incluse</item>
</plurals>
<string name="all_applications">Tutte le applicazioni</string>
<string name="exclude_from_tunnel">Escludi</string>
<string name="include_in_tunnel">Includi solo</string>
<plurals name="include_n_applications">
<item quantity="one">Includi %d applicazione</item>
<item quantity="other">Includi %d applicazioni</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="one">Escludi %d applicazione</item>
<item quantity="other">Escludi %d applicazioni</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="one">ogni secondo</item>
<item quantity="other">ogni %d secondi</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="one">secondo</item>
<item quantity="other">secondi</item>
</plurals>
<string name="use_all_applications">Utilizza tutte le applicazioni</string>
<string name="add_peer">Aggiungi peer</string>
<string name="addresses">Indirizzi</string>
<string name="applications">Applicazioni</string>
<string name="allow_remote_control_intents_summary_off">Le applicazioni esterne non possono attivare tunnel (consigliato)</string>
<string name="allow_remote_control_intents_summary_on">Le applicazioni esterne possono attivare tunnel (avanzato)</string>
<string name="allow_remote_control_intents_title">Consenti applicazioni di controllo remoto</string>
@@ -76,7 +109,6 @@
<string name="error_root">Accedi come root e riprova</string>
<string name="error_up">Errore di attivazione del tunnel: %s</string>
<string name="exclude_private_ips">Escludi IP privati</string>
<string name="excluded_applications">Applicazioni escluse</string>
<string name="generate_new_private_key">Genera nuova chiave privata</string>
<string name="generic_error">Errore “%s” sconosciuto</string>
<string name="hint_automatic">(auto)</string>
@@ -133,16 +165,15 @@
<string name="permission_label">controlla tunnel WireGuard</string>
<string name="persistent_keepalive">Tieni sempre attivo</string>
<string name="pre_shared_key">Chiave condivisa (PSK)</string>
<string name="pre_shared_key_enabled">abilitata</string>
<string name="private_key">Chiave privata</string>
<string name="public_key">Chiave pubblica</string>
<string name="public_key_description">La chiave pubblica</string>
<string name="qr_code_hint">Suggerimento: genera con `qrencode -t ansiutf8 &lt; tunnel.conf`.</string>
<string name="restore_on_boot_summary_off">Non attiverà i tunnel configurati all\'avvio</string>
<string name="restore_on_boot_summary_on">Attiverà i tunnel configurati all\'avvio</string>
<string name="restore_on_boot_title">Ripristina all\'avvio</string>
<string name="save">Salva</string>
<string name="select_all">Seleziona tutto</string>
<string name="set_exclusions">Imposta esclusioni</string>
<string name="settings">Impostazioni</string>
<string name="shell_exit_status_read_error">La shell non riesce a leggere lo stato di uscita</string>
<string name="shell_marker_count_error">La shell si aspettava 4 marker, ne ha ricevuti %d</string>
@@ -191,4 +222,8 @@
<string name="zip_export_success">Salvato in “%s”</string>
<string name="zip_export_summary">Il file zip verrà salvato nella cartella di download</string>
<string name="zip_export_title">Esporta i tunnel in un file zip</string>
<string name="biometric_prompt_zip_exporter_title">Autenticati per esportare le chiavi i tunnel</string>
<string name="biometric_prompt_private_key_title">Autenticati per visualizzare le chiavi private</string>
<string name="biometric_auth_error">Autenticazione non riuscita</string>
<string name="biometric_auth_error_reason">Autenticazione non riuscita: %s</string>
</resources>
+32 -4
View File
@@ -18,8 +18,34 @@
<plurals name="set_excluded_applications">
<item quantity="other">除外アプリ %d 個</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="other">トンネリング対象アプリ %d 個</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="other">対象外アプリ %d 個</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="other">トンネル対象アプリ %d 個</item>
</plurals>
<string name="all_applications">すべてのアプリがトンネル対象</string>
<string name="exclude_from_tunnel">トンネルしない</string>
<string name="include_in_tunnel">トンネルする</string>
<plurals name="include_n_applications">
<item quantity="other">%d アプリが対象</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="other">%d アプリを除外</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="other">%d 秒ごと</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="other">秒</item>
</plurals>
<string name="use_all_applications">全アプリをトンネル対象にする</string>
<string name="add_peer">ピアを追加する</string>
<string name="addresses">アドレス</string>
<string name="applications">アプリ</string>
<string name="allow_remote_control_intents_summary_off">外部アプリはトンネルを制御できない(推奨)</string>
<string name="allow_remote_control_intents_summary_on">外部アプリにトンネルの制御を許可(上級者向け)</string>
<string name="allow_remote_control_intents_title">外部アプリからの制御</string>
@@ -70,7 +96,6 @@
<string name="error_root">root 権限を取得して再試行してください</string>
<string name="error_up">トンネル起動時エラー: %s</string>
<string name="exclude_private_ips">プライベート IP アドレスを除外</string>
<string name="excluded_applications">対象外とするアプリケーション</string>
<string name="generate_new_private_key">新しい秘密鍵を生成する</string>
<string name="generic_error">未知の “%s” エラー</string>
<string name="hint_automatic">(自動)</string>
@@ -127,22 +152,21 @@
<string name="permission_label">WireGuard トンネルの制御</string>
<string name="persistent_keepalive">持続的キープアライブ</string>
<string name="pre_shared_key">事前共有鍵</string>
<string name="pre_shared_key_enabled">有効</string>
<string name="private_key">秘密鍵</string>
<string name="public_key">公開鍵</string>
<string name="public_key_description">公開鍵</string>
<string name="qr_code_hint">Tip: `qrencode -t ansiutf8 &lt; tunnel.conf` で生成できます</string>
<string name="restore_on_boot_summary_off">起動時にトンネルを有効化しない</string>
<string name="restore_on_boot_summary_on">起動時に、前回有効だったトンネルを有効化する</string>
<string name="restore_on_boot_title">起動時に復元</string>
<string name="save">保存</string>
<string name="select_all">すべて選択</string>
<string name="set_exclusions">対象外アプリを設定</string>
<string name="settings">設定</string>
<string name="shell_exit_status_read_error">シェルは終了ステータスを取得できません</string>
<string name="shell_marker_count_error">シェルは 4 マーカーを期待していますが、 %d マーカーを受け取りました</string>
<string name="shell_start_error">シェルの起動に失敗しました: %d</string>
<string name="success_application_will_restart">成功。アプリケーションは再起動します…</string>
<string name="toggle_all">すべてのトンネルの状態を切り替え</string>
<string name="toggle_all">すべての状態を切り替え</string>
<string name="toggle_error">WireGuard トンネルの状態切り替え時にエラー: %s</string>
<string name="tools_installer_already">wg および wg-quick はインストール済みです</string>
<string name="tools_installer_failure">コマンドラインツールをインストールできません(root権限がない?)</string>
@@ -185,4 +209,8 @@
<string name="zip_export_success">“%s” に保存</string>
<string name="zip_export_summary">Zip ファイルはダウンロードフォルダに保存されます</string>
<string name="zip_export_title">トンネル設定を zip ファイルにエクスポート</string>
<string name="biometric_prompt_zip_exporter_title">トンネル設定をエクスポートするために認証を行います</string>
<string name="biometric_prompt_private_key_title">秘密鍵を表示するために認証を行います</string>
<string name="biometric_auth_error">認証に失敗</string>
<string name="biometric_auth_error_reason">認証に失敗: %s</string>
</resources>
+2 -2
View File
@@ -12,8 +12,8 @@
<!-- Theme variables -->
<color name="list_multiselect_background">#1aeeeeee</color>
<color name="status_bar_color">#21242424</color>
<color name="navigation_bar_color">#aa242424</color>
<color name="status_bar_color">@color/primary_color</color>
<color name="navigation_bar_color">#aa212121</color>
<!-- Log viewer tag colors -->
<color name="debug_tag_color">#aaaaaa</color>
+61 -12
View File
@@ -2,31 +2,31 @@
<resources>
<plurals name="delete_error">
<item quantity="one">Не удалось удалить %d туннель: %s</item>
<item quantity="few">Не удалось удалить %d туннелей: %s</item>
<item quantity="few">Не удалось удалить %d туннеля: %s</item>
<item quantity="many">Не удалось удалить %d туннелей: %s</item>
<item quantity="other">Не удалось удалить %d туннелей: %s</item>
</plurals>
<plurals name="delete_success">
<item quantity="one">Успешно удален %d туннель</item>
<item quantity="few">Успешно удалено %d туннелей</item>
<item quantity="few">Успешно удалено %d туннеля</item>
<item quantity="many">Успешно удалено %d туннелей</item>
<item quantity="other">Успешно удалено %d туннелей</item>
</plurals>
<plurals name="delete_title">
<item quantity="one">%d туннель выбран</item>
<item quantity="few">%d туннелей выбрано</item>
<item quantity="few">%d туннеля выбрано</item>
<item quantity="many">%d туннелей выбрано</item>
<item quantity="other">%d туннелей выбрано</item>
</plurals>
<plurals name="import_partial_success">
<item quantity="one">Импортирован %1$d из %2$d туннелей</item>
<item quantity="few">Импортировано %1$d из %2$d туннелей</item>
<item quantity="few">Импортировано %1$d из %2$d туннеля</item>
<item quantity="many">Импортировано %1$d из %2$d туннелей</item>
<item quantity="other">Импортировано %1$d из %2$d туннелей</item>
</plurals>
<plurals name="import_total_success">
<item quantity="one">Импортированный %d туннель</item>
<item quantity="few">Импортировано %d туннелей</item>
<item quantity="few">Импортировано %d туннеля</item>
<item quantity="many">Импортировано %d туннелей</item>
<item quantity="other">Импортировано %d туннелей</item>
</plurals>
@@ -36,8 +36,55 @@
<item quantity="many">%d Исключенных приложений</item>
<item quantity="other">%d Исключенных приложений</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="one">%d Включенное приложение</item>
<item quantity="few">%d Включенных приложений</item>
<item quantity="many">%d Включенных приложений</item>
<item quantity="other">%d Включенных приложений</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="one">%d исключен</item>
<item quantity="few">%d исключено</item>
<item quantity="many">%d исключено</item>
<item quantity="other">%d исключено</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="one">%d влючен</item>
<item quantity="few">%d включено</item>
<item quantity="many">%d включено</item>
<item quantity="other">%d включено</item>
</plurals>
<string name="all_applications">Все приложения</string>
<string name="exclude_from_tunnel">Исключить</string>
<string name="include_in_tunnel">Только включить</string>
<plurals name="include_n_applications">
<item quantity="one">Включить %d приложение</item>
<item quantity="few">Включить %d приложения</item>
<item quantity="many">Включить %d приложений</item>
<item quantity="other">Включить %d приложений</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="one">Исключить %d приложение</item>
<item quantity="few">Исключить %d приложения</item>
<item quantity="many">Исключить %d приложений</item>
<item quantity="other">Исключить %d приложений</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="one">каждую %d секунду</item>
<item quantity="few">каждые %d секунды</item>
<item quantity="many">каждые %d секунд</item>
<item quantity="other">каждые %d секунд</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="one">секунда</item>
<item quantity="few">секунд</item>
<item quantity="many">секунд</item>
<item quantity="other">секунд</item>
</plurals>
<string name="use_all_applications">Использовать все приложения</string>
<string name="add_peer">Добавить пира</string>
<string name="addresses">IP-адреса</string>
<string name="applications">Приложения</string>
<string name="allow_remote_control_intents_summary_off">Сторонние приложения не могут переключать туннели (рекомендуется)</string>
<string name="allow_remote_control_intents_summary_on">Сторонние приложения могут переключать туннели (дополнительно)</string>
<string name="allow_remote_control_intents_title">Доступ к другим приложениям</string>
@@ -72,7 +119,7 @@
<string name="create_downloads_file_error">Не удалось создать файл в каталоге загрузок</string>
<string name="create_empty">Создать вручную</string>
<string name="create_from_file">Импорт из файла или архива</string>
<string name="create_from_qr_code">Сканировать из QR-кода</string>
<string name="create_from_qr_code">Сканировать QR-код</string>
<string name="create_output_dir_error">Не удалось создать выходной каталог</string>
<string name="create_temp_dir_error">Не удалось создать временный локальный каталог</string>
<string name="create_tunnel">Создать туннель</string>
@@ -88,12 +135,11 @@
<string name="error_root">Пожалуйста, получите root-доступ и попробуйте снова</string>
<string name="error_up">Ошибка при запуске туннеля: %s</string>
<string name="exclude_private_ips">Исключить частные IP-адреса</string>
<string name="excluded_applications">Исключенные приложения</string>
<string name="generate_new_private_key">Сгенерировать новый приватный ключ</string>
<string name="generic_error">Неизвестная “%s” ошибка</string>
<string name="hint_automatic">(авто)</string>
<string name="hint_generated">(авто)</string>
<string name="hint_optional">(авто)</string>
<string name="hint_generated">(сгенерирован)</string>
<string name="hint_optional">(опционально)</string>
<string name="hint_optional_discouraged">(опционально, не рекомендуется)</string>
<string name="hint_random">(авто)</string>
<string name="illegal_filename_error">Неверное имя файла “%s”</string>
@@ -129,7 +175,7 @@
<string name="mtu">MTU</string>
<string name="multiple_tunnels_summary_off">Только один туннель, выключит другие</string>
<string name="multiple_tunnels_summary_on">Могут быть включены несколько туннелей одновременно</string>
<string name="multiple_tunnels_title">Несколько одновременных туннелей</string>
<string name="multiple_tunnels_title">Несколько туннелей</string>
<string name="name">Имя</string>
<string name="no_config_error">Попытка поднять туннель без конфигурации</string>
<string name="no_configs_error">Конфигурации не найдены</string>
@@ -145,16 +191,15 @@
<string name="permission_label">управлять туннелями WireGuard</string>
<string name="persistent_keepalive">Постоянное соединение</string>
<string name="pre_shared_key">Общий ключ</string>
<string name="pre_shared_key_enabled">включено</string>
<string name="private_key">Приватный ключ</string>
<string name="public_key">Публичный ключ</string>
<string name="public_key_description">Публичный ключ</string>
<string name="qr_code_hint">Совет: генерировать с `qrencode -t ansiutf8 &lt; tunnel.conf`.</string>
<string name="restore_on_boot_summary_off">Не поднимать ранее выбранные туннели при загрузке</string>
<string name="restore_on_boot_summary_on">Поднимать ранее выбранные туннели при загрузке</string>
<string name="restore_on_boot_title">Восстанавливать при загрузке</string>
<string name="save">Сохранить</string>
<string name="select_all">Выбрать все</string>
<string name="set_exclusions">ОК</string>
<string name="settings">Настройки</string>
<string name="shell_exit_status_read_error">Shell не может прочитать статус выхода</string>
<string name="shell_marker_count_error">Shell ожидает 4 маркера, получено %d</string>
@@ -203,4 +248,8 @@
<string name="zip_export_success">Сохранено в “%s”</string>
<string name="zip_export_summary">Zip-архив будет сохранен в папке загрузок</string>
<string name="zip_export_title">Экспорт туннелей в zip-архив</string>
<string name="biometric_prompt_zip_exporter_title">Аутентификация для экспорта туннелей</string>
<string name="biometric_prompt_private_key_title">Аутентификация для просмотра приватного ключа</string>
<string name="biometric_auth_error">Ошибка аутентификации</string>
<string name="biometric_auth_error_reason">Ошибка аутентификации: %s</string>
</resources>
+255
View File
@@ -0,0 +1,255 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="delete_error">
<item quantity="one">%d tunela ni bilo mogoče izbrisati: %s</item>
<item quantity="two">%d tunelov ni bilo mogoče izbrisati: %s</item>
<item quantity="few">%d tunelov ni bilo mogoče izbrisati: %s</item>
<item quantity="other">%d tunelov ni bilo mogoče izbrisati: %s</item>
</plurals>
<plurals name="delete_success">
<item quantity="one">%d tunel uspešno izbrisan</item>
<item quantity="two">%d tunela uspešno izbrisana</item>
<item quantity="few">%d tuneli uspešno izbrisani</item>
<item quantity="other">%d tunelov uspešno izbrisanih</item>
</plurals>
<plurals name="delete_title">
<item quantity="one">%d tunel izbran</item>
<item quantity="two">%d tunela izbrana</item>
<item quantity="few">%d tuneli izbrani</item>
<item quantity="other">%d tunelov izbranih</item>
</plurals>
<plurals name="import_partial_success">
<item quantity="one">%1$d tunel od %2$d uvožen</item>
<item quantity="two">%1$d tunela od %2$d uvožena</item>
<item quantity="few">%1$d tuneli od %2$d uvoženi</item>
<item quantity="other">%1$d tunelov od %2$d uvoženih</item>
</plurals>
<plurals name="import_total_success">
<item quantity="one">%d tunel uvožen</item>
<item quantity="two">%d tunela uvožena</item>
<item quantity="few">%d tuneli uvoženi</item>
<item quantity="other">%d tunelov uvoženih</item>
</plurals>
<plurals name="set_excluded_applications">
<item quantity="one">%d izvzeta aplikacija</item>
<item quantity="two">%d izvzeti aplikaciji</item>
<item quantity="few">%d izvzete aplikacije</item>
<item quantity="other">%d izvzetih aplikacij</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="one">%d vključena aplikacija</item>
<item quantity="two">%d vključeni aplikaciji</item>
<item quantity="few">%d vključene aplikacije</item>
<item quantity="other">%d vključenih aplikacij</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="one">%d izvzeta</item>
<item quantity="two">%d izvzeti</item>
<item quantity="few">%d izvzete</item>
<item quantity="other">%d izvzetih</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="one">%d vključena</item>
<item quantity="two">%d vključeni</item>
<item quantity="few">%d vključene</item>
<item quantity="other">%d vključenih</item>
</plurals>
<string name="all_applications">Vse aplikacije</string>
<string name="exclude_from_tunnel">Izvzemi</string>
<string name="include_in_tunnel">Vključi samo za</string>
<plurals name="include_n_applications">
<item quantity="one">Vključi za %d aplikacijo</item>
<item quantity="two">Vključi za %d aplikaciji</item>
<item quantity="few">Vključi za %d aplikacije</item>
<item quantity="other">Vključi za %d aplikacij</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="one">Izvzemi %d aplikacijo</item>
<item quantity="two">Izvzemi %d aplikaciji</item>
<item quantity="few">Izvzemi %d aplikacije</item>
<item quantity="other">Izvzemi %d aplikacij</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="one">vsako %d sekundo</item>
<item quantity="two">vsaki %d sekundi</item>
<item quantity="few">vsake %d sekunde</item>
<item quantity="other">vsakih %d sekund</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="one">sekunda</item>
<item quantity="two">sekundi</item>
<item quantity="few">sekunde</item>
<item quantity="other">sekund</item>
</plurals>
<string name="use_all_applications">Vse aplikacije</string>
<string name="add_peer">Dodaj vrstnike</string>
<string name="addresses">Naslovi</string>
<string name="applications">Aplikacije</string>
<string name="allow_remote_control_intents_summary_off">Zunanjim aplikacijam ni dovoljeno preklapljati tunelov (priporočeno)</string>
<string name="allow_remote_control_intents_summary_on">Zunanje aplikacije lahko preklapljajo tunele (napredno)</string>
<string name="allow_remote_control_intents_title">Dovoljeno upravljanje preko zunanjih aplikacij</string>
<string name="allowed_ips">Dovoljeni naslovi IP</string>
<string name="app_name">WireGuard</string>
<string name="bad_config_context">%1$s-ov %2$s</string>
<string name="bad_config_context_top_level">%s</string>
<string name="bad_config_error">%1$s v %2$s</string>
<string name="bad_config_explanation_pka">: Mora biti pozitivno in ne večje od 65535</string>
<string name="bad_config_explanation_positive_number">: Mora biti pozitivno</string>
<string name="bad_config_explanation_udp_port">: Mora biti veljavna številka vrat UDP</string>
<string name="bad_config_reason_invalid_key">Neveljaven ključ</string>
<string name="bad_config_reason_invalid_number">Neveljavno število</string>
<string name="bad_config_reason_invalid_value">Neveljavna vrednost</string>
<string name="bad_config_reason_missing_attribute">Manjka atribut</string>
<string name="bad_config_reason_missing_section">Manjka odsek</string>
<string name="bad_config_reason_syntax_error">Sintaktična napaka</string>
<string name="bad_config_reason_unknown_attribute">Neznan atribut</string>
<string name="bad_config_reason_unknown_section">Neznani odsek</string>
<string name="bad_config_reason_value_out_of_range">Vrednost je zunaj veljavnega območja</string>
<string name="bad_extension_error">Datoteka mora biti .conf ali .zip</string>
<string name="cancel">Prekliči</string>
<string name="config_delete_error">Konfiguracijske datoteke %s ni bilo mogoče izbrisati</string>
<string name="config_exists_error">Konfiguracija za „%s“ že obstaja</string>
<string name="config_file_exists_error">Konfiguracijska datoteka za „%s“ že obstaja</string>
<string name="config_not_found_error">Konfiguracijske datoteke za „%s“ ni bilo mogoče najti</string>
<string name="config_rename_error">Konfiguracijske datoteke „%s“ ni bilo mogoče preimenovati</string>
<string name="config_save_error">Konfiguracijske datoteke za „%1$s“ ni bilo mogoče shraniti: %2$s</string>
<string name="config_save_success">Konfiguracijska datoteka za „%s“ uspešno shranjena</string>
<string name="create_activity_title">Ustvarite tunel WireGuard</string>
<string name="create_bin_dir_error">Lokalnega imenika za aplikacijo ni bilo mogoče ustvariti</string>
<string name="create_downloads_file_error">Datoteke v mapi prenosov ni bilo mogoče ustvariti</string>
<string name="create_empty">Ustvari na novo</string>
<string name="create_from_file">Uvozi iz datoteke ali arhiva</string>
<string name="create_from_qr_code">Skreniraj kodo QR</string>
<string name="create_output_dir_error">Izhodnega imenika ni bilo mogoče ustvariti</string>
<string name="create_temp_dir_error">Lokalnega začasnega imenika ni bilo mogoče ustvariti</string>
<string name="create_tunnel">Ustvari tunel</string>
<string name="dark_theme_summary_off">V uporabi svetla (dnevna) tema</string>
<string name="dark_theme_summary_on">V uporabi temna (nočna) tema</string>
<string name="dark_theme_title">Uporabi temno temo</string>
<string name="delete">Izbriši</string>
<string name="dns_servers">Strežniki DNS</string>
<string name="edit">Uredi</string>
<string name="endpoint">Končna točka</string>
<string name="error_down">Napaka pri zaključevanju tunela: %s</string>
<string name="error_fetching_apps">Napaka pri poizvedovanju seznama aplikacij: %s</string>
<string name="error_root">Prosim omogočite dostop root in poskusite ponovno</string>
<string name="error_up">Napaka pri vzpostavitvi tunela: %s</string>
<string name="exclude_private_ips">Izvzemi zasebne naslove IP</string>
<string name="generate_new_private_key">Izdelaj nov zasebni ključ</string>
<string name="generic_error">Neznana napaka „%s“</string>
<string name="hint_automatic">(samodejno)</string>
<string name="hint_generated">(izdelano)</string>
<string name="hint_optional">(izbirno)</string>
<string name="hint_optional_discouraged">(izbirno, ni priporočljivo)</string>
<string name="hint_random">(naključno)</string>
<string name="illegal_filename_error">Neveljavno ime datoteke „%s“</string>
<string name="import_error">Tunela ni bilo mogoče uvoziti: %s</string>
<string name="import_from_qr_code">Uvozi tunel iz kode QR</string>
<string name="import_success">„%s“ uvožen</string>
<string name="interface_title">Vmesnik</string>
<string name="key_contents_error">Napačni znaki v ključu</string>
<string name="key_length_error">Napačna dolžina ključa</string>
<string name="key_length_explanation_base64">: WireGuardovi ključi base64 morajo vsebovati 44 znakov (32 bajtov)</string>
<string name="key_length_explanation_binary">: WireGuardovi ključi morajo biti veliki 32 bajtov</string>
<string name="key_length_explanation_hex">: WireGuardovi ključi hex morajo biti veliki 64 znakov (32 bajtov)</string>
<string name="listen_port">Vrata poslušanja</string>
<string name="log_export_error">Dnevnika ni bilo mogoče izvoziti: %s</string>
<string name="log_export_subject">Dnevniška datoteka WireGuard za Android</string>
<string name="log_export_success">Shranjeno v „%s“</string>
<string name="log_export_title">Izvozi dnevniško datoteko</string>
<string name="log_saver_activity_label">Shrani dnevnik</string>
<string name="log_viewer_pref_summary">Dnevniki lahko pomagajo pri razhroščevanju</string>
<string name="log_viewer_pref_title">Prikaži dnevnik aplikacije</string>
<string name="log_viewer_title">Dnevnik</string>
<string name="logcat_error">Ukaza logcat ni bilo mogoče izvesti: </string>
<string name="module_disabler_disabled_summary">Eksperimentalni modul jedra lahko izboljša zmogljivost</string>
<string name="module_disabler_disabled_title">Omogoči zaledje za modul jedra</string>
<string name="module_disabler_enabled_summary">Počasnejše uporabniško zaledje lahko izboljša stabilnost</string>
<string name="module_disabler_enabled_title">Onemogoči zaledje za modul jedra</string>
<string name="module_installer_error">Nekaj je šlo narobe, prosimo poskusite znova</string>
<string name="module_installer_initial">Eksperimentalni modul jedra lahko izboljša zmogljivost</string>
<string name="module_installer_not_found">Za vašo napravo ni razpoložljivih modulov</string>
<string name="module_installer_title">Prenesi in namesti modul jedra</string>
<string name="module_installer_working">Prenašanje in nameščanje …</string>
<string name="module_version_error">Verzije modula jedra ni bilo mogoče določiti</string>
<string name="mtu">MTU</string>
<string name="multiple_tunnels_summary_off">Vklop enega tunela bo izklopil druge</string>
<string name="multiple_tunnels_summary_on">Več tunelov je lahko aktiviranih sočasno</string>
<string name="multiple_tunnels_title">Dovoli več sočasnih tunelov</string>
<string name="name">Ime</string>
<string name="no_config_error">Poskus vzpostavitve tunela brez konfiguracije</string>
<string name="no_configs_error">Ni najdenih konfiguracij</string>
<string name="no_tunnels_error">Ni tunelov</string>
<string name="parse_error_generic">niz</string>
<string name="parse_error_inet_address">Naslov IP</string>
<string name="parse_error_inet_endpoint">končna točka</string>
<string name="parse_error_inet_network">Omrežje IP</string>
<string name="parse_error_integer">število</string>
<string name="parse_error_reason">Ni mogoče razčleniti %1$s „%2$s“</string>
<string name="peer">Vrstnik</string>
<string name="permission_description">upravljanje tunelov WireGuard, aktivacija in deaktivacija tunela, zaradi česar bo internetni promet mogoče napačno usmerjen</string>
<string name="permission_label">upravljanje tunelov WireGuard</string>
<string name="persistent_keepalive">Trajno ohranjanje povezave</string>
<string name="pre_shared_key">Ključ v skupni rabi</string>
<string name="pre_shared_key_enabled">omogočeno</string>
<string name="private_key">Zasebni ključ</string>
<string name="public_key">Javni ključ</string>
<string name="qr_code_hint">Namig: izdelajte z `qrencode -t ansiutf8 &lt; tunnel.conf`.</string>
<string name="restore_on_boot_summary_off">Pri zagonu telefona omogočeni tuneli ne bodo aktivirani</string>
<string name="restore_on_boot_summary_on">Pri zagonu telefona bodo omogočeni tuneli aktivirani</string>
<string name="restore_on_boot_title">Ponovna vzpostavitev ob zagonu</string>
<string name="save">Shrani</string>
<string name="select_all">Izberi vse</string>
<string name="settings">Nastavitve</string>
<string name="shell_exit_status_read_error">Lupina ne more prebrati izhodnega statusa</string>
<string name="shell_marker_count_error">Lupina je pričakovala 4 oznake, dobila pa je %d</string>
<string name="shell_start_error">Lupina se ni mogla zagnati: %d</string>
<string name="success_application_will_restart">Uspešno. Aplikacija se bo znova zagnala …</string>
<string name="toggle_all">Preklopi vse</string>
<string name="toggle_error">Napaka pri preklopu tunela WireGuard: %s</string>
<string name="tools_installer_already">wg in wg-quick sta že nameščena</string>
<string name="tools_installer_failure">Orodij ukazne vrstice ni bilo mogoče namestiti (ni dostopa root?)</string>
<string name="tools_installer_initial">Namestitev izbirnih orodij za skripte</string>
<string name="tools_installer_initial_magisk">Namestitev izbirnih orodij za skripte kot modula Magisk</string>
<string name="tools_installer_initial_system">Namestitev izbirnih orodij za skripte na sistemsko particijo</string>
<string name="tools_installer_success_magisk">wg in wg-quick kot modul Magisk nameščen (zahtevan ponovni zagon)</string>
<string name="tools_installer_success_system">wg und wg-quick nameščena na sistemsko particijo</string>
<string name="tools_installer_title">Namesti orodja za ukazno vrstico</string>
<string name="tools_installer_working">Nameščam wg in wg-quick</string>
<string name="tools_unavailable_error">Zahtevana orodja niso na voljo</string>
<string name="transfer">Prenos</string>
<string name="transfer_bytes">%d B</string>
<string name="transfer_gibibytes">%.2f GiB</string>
<string name="transfer_kibibytes">%.2f KiB</string>
<string name="transfer_mibibytes">%.2f MiB</string>
<string name="transfer_rx_tx">prejeto: %1$s, poslano: %2$s</string>
<string name="transfer_tibibytes">%.2f TiB</string>
<string name="tun_create_error">Naprave tun ni bilo mogoče ustvariti</string>
<string name="tunnel_config_error">Tunela ni bilo mogoče nastaviti (wg-quick je vrnil %d)</string>
<string name="tunnel_create_error">Tunela ni bilo mogoče ustvariti: %s</string>
<string name="tunnel_create_success">Tunel „%s“ uspešno ustvarjen</string>
<string name="tunnel_error_already_exists">Tunel „%s“ že obstaja</string>
<string name="tunnel_error_invalid_name">Neveljavno ime</string>
<string name="tunnel_list_placeholder">Dodaj tunel s klikom na modri gumb</string>
<string name="tunnel_name">Ime tunela</string>
<string name="tunnel_on_error">Tunela ni bilo mogoče vključiti (wgTurnOn je vrnil %d)</string>
<string name="tunnel_rename_error">Tunela ni bilo mogoče preimenovati: %s</string>
<string name="tunnel_rename_success">Tunel uspešno preimenovan v „%s“</string>
<string name="type_name_go_userspace">Uporabniški prostor Go</string>
<string name="type_name_kernel_module">Modul jedra</string>
<string name="unknown_error">Neznana napaka</string>
<string name="version_summary">Zaledje %1$s v%2$s</string>
<string name="version_summary_checking">Preverjam verzijo zaledja %s</string>
<string name="version_summary_unknown">Neznana verzija %s</string>
<string name="version_title">WireGuard za Android v%s</string>
<string name="vpn_not_authorized_error">Uporabnik ni odobril storitve VPN</string>
<string name="vpn_start_error">Storitve Android VPN ni bilo mogoče zagnati</string>
<string name="zip_export_error">Tunelov ni bilo mogoče izvoziti: %s</string>
<string name="zip_export_success">Shranjeno v „%s“</string>
<string name="zip_export_summary">Datoteka zip je bila shranjena v mapo Prenosi</string>
<string name="zip_export_title">Izvozi tunele v datoteko zip</string>
<string name="biometric_prompt_zip_exporter_title">Za izvoz tunelov se prijavite</string>
<string name="biometric_prompt_private_key_title">Za ogled zasebnega ključa se prijavite</string>
<string name="biometric_auth_error">Napaka pri overovljanju</string>
<string name="biometric_auth_error_reason">Napaka pri overovljanju: %s</string>
</resources>
+1 -1
View File
@@ -20,7 +20,7 @@
<item name="android:windowBackground">@color/primary_color</item>
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
<item name="actionBarPopupTheme">@style/ThemeOverlay.MaterialComponents.ActionBar</item>
<item name="textInputStyle">@style/TextInputLayoutBase</item>
<item name="materialCardViewStyle">@style/AppTheme.MaterialCardView</item>
</style>
</resources>
+1 -1
View File
@@ -23,7 +23,7 @@
<item name="android:windowBackground">@color/primary_color</item>
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
<item name="actionBarPopupTheme">@style/ThemeOverlay.MaterialComponents.ActionBar</item>
<item name="textInputStyle">@style/TextInputLayoutBase</item>
<item name="materialCardViewStyle">@style/AppTheme.MaterialCardView</item>
</style>
</resources>
+33 -5
View File
@@ -16,10 +16,36 @@
<item quantity="other">导入了 %d 项</item>
</plurals>
<plurals name="set_excluded_applications">
<item quantity="other">%d 个排除应用</item>
<item quantity="other">对 %d 个应用不生效</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="other">对 %d 个应用生效</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="other">对 %d 个应用不生效</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="other">对 %d 个应用生效</item>
</plurals>
<string name="all_applications">对全部应用生效</string>
<string name="exclude_from_tunnel">不生效</string>
<string name="include_in_tunnel">生效</string>
<plurals name="include_n_applications">
<item quantity="other">设定 %d 个应用</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="other">设定 %d 个应用</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="other">每隔 %d 秒</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="other">秒</item>
</plurals>
<string name="use_all_applications">不设定过滤</string>
<string name="add_peer">添加节点</string>
<string name="addresses">局域网 IP 地址</string>
<string name="applications">应用过滤</string>
<string name="allow_remote_control_intents_summary_off">外部应用当前不能控制隧道(不建议勾选)</string>
<string name="allow_remote_control_intents_summary_on">外部应用当前能够控制隧道(面向高级用户)</string>
<string name="allow_remote_control_intents_title">授权外部控制</string>
@@ -70,7 +96,6 @@
<string name="error_root">请获取 root 权限并重试</string>
<string name="error_up">建立连接时出错:%s</string>
<string name="exclude_private_ips">排除局域网</string>
<string name="excluded_applications">排除的应用</string>
<string name="generate_new_private_key">生成新的私钥</string>
<string name="generic_error">未知的 “%s” 错误</string>
<string name="hint_automatic">(自动)</string>
@@ -127,16 +152,15 @@
<string name="permission_label">控制 WireGuard 隧道</string>
<string name="persistent_keepalive">连接保活间隔</string>
<string name="pre_shared_key">预共享密钥</string>
<string name="pre_shared_key_enabled">已启用</string>
<string name="private_key">私钥</string>
<string name="public_key">公钥</string>
<string name="public_key_description">公钥</string>
<string name="qr_code_hint">提示:使用命令 `qrencode -t ansiutf8 &lt; tunnel.conf` 生成二维码</string>
<string name="restore_on_boot_summary_off">未启用</string>
<string name="restore_on_boot_summary_on">设备启动时自动开启上次使用的隧道</string>
<string name="restore_on_boot_title">启动时恢复</string>
<string name="save">保存</string>
<string name="select_all">全选</string>
<string name="set_exclusions">确定</string>
<string name="settings">设置</string>
<string name="shell_exit_status_read_error">Shell 无法读取退出状态</string>
<string name="shell_marker_count_error">Shell 应获取 4 个标记,获取到 %d 个</string>
@@ -184,5 +208,9 @@
<string name="zip_export_error">无法导出隧道配置:%s</string>
<string name="zip_export_success">已保存至 “%s”</string>
<string name="zip_export_summary">zip 压缩包将保存至下载文件夹</string>
<string name="zip_export_title">导出隧道配置为 zip 压缩包</string>
<string name="zip_export_title">导出隧道配置</string>
<string name="biometric_prompt_zip_exporter_title">导出配置需要认证指纹</string>
<string name="biometric_prompt_private_key_title">查看私钥需要认证指纹</string>
<string name="biometric_auth_error">认证失败</string>
<string name="biometric_auth_error_reason">认证失败:%s</string>
</resources>
+36 -3
View File
@@ -24,8 +24,41 @@
<item quantity="one">%d Excluded Application</item>
<item quantity="other">%d Excluded Applications</item>
</plurals>
<plurals name="set_included_applications">
<item quantity="one">%d Included Application</item>
<item quantity="other">%d Included Applications</item>
</plurals>
<plurals name="n_excluded_applications">
<item quantity="one">%d excluded</item>
<item quantity="other">%d excluded</item>
</plurals>
<plurals name="n_included_applications">
<item quantity="one">%d included</item>
<item quantity="other">%d included</item>
</plurals>
<string name="all_applications">All Applications</string>
<string name="exclude_from_tunnel">Exclude</string>
<string name="include_in_tunnel">Include only</string>
<plurals name="include_n_applications">
<item quantity="one">Include %d app</item>
<item quantity="other">Include %d apps</item>
</plurals>
<plurals name="exclude_n_applications">
<item quantity="one">Exclude %d app</item>
<item quantity="other">Exclude %d apps</item>
</plurals>
<plurals name="persistent_keepalive_seconds_unit">
<item quantity="one">every second</item>
<item quantity="other">every %d seconds</item>
</plurals>
<plurals name="persistent_keepalive_seconds_suffix">
<item quantity="one">second</item>
<item quantity="other">seconds</item>
</plurals>
<string name="use_all_applications">Use all apps</string>
<string name="add_peer">Add peer</string>
<string name="addresses">Addresses</string>
<string name="applications">Applications</string>
<string name="allow_remote_control_intents_summary_off">External apps may not toggle tunnels (recommended)</string>
<string name="allow_remote_control_intents_summary_on">External apps may toggle tunnels (advanced)</string>
<string name="allow_remote_control_intents_title">Allow remote control apps</string>
@@ -68,6 +101,8 @@
<string name="dark_theme_summary_on">Currently using dark (night) theme</string>
<string name="dark_theme_title">Use dark theme</string>
<string name="delete">Delete</string>
<string name="disable_config_export_title">Disable config exporting</string>
<string name="disable_config_export_description">Disabling config exporting makes private keys less accessible</string>
<string name="dns_servers">DNS servers</string>
<string name="edit">Edit</string>
<string name="endpoint">Endpoint</string>
@@ -76,7 +111,6 @@
<string name="error_root">Please obtain root access and try again</string>
<string name="error_up">Error bringing up tunnel: %s</string>
<string name="exclude_private_ips">Exclude private IPs</string>
<string name="excluded_applications">Excluded Applications</string>
<string name="generate_new_private_key">Generate new private key</string>
<string name="generic_error">Unknown “%s” error</string>
<string name="hint_automatic">(auto)</string>
@@ -133,16 +167,15 @@
<string name="permission_label">control WireGuard tunnels</string>
<string name="persistent_keepalive">Persistent keepalive</string>
<string name="pre_shared_key">Pre-shared key</string>
<string name="pre_shared_key_enabled">enabled</string>
<string name="private_key">Private key</string>
<string name="public_key">Public key</string>
<string name="public_key_description">Public key</string>
<string name="qr_code_hint">Tip: generate with `qrencode -t ansiutf8 &lt; tunnel.conf`.</string>
<string name="restore_on_boot_summary_off">Will not bring up enabled tunnels at boot</string>
<string name="restore_on_boot_summary_on">Will bring up enabled tunnels at boot</string>
<string name="restore_on_boot_title">Restore on boot</string>
<string name="save">Save</string>
<string name="select_all">Select all</string>
<string name="set_exclusions">Set Exclusions</string>
<string name="settings">Settings</string>
<string name="shell_exit_status_read_error">Shell cannot read exit status</string>
<string name="shell_marker_count_error">Shell expected 4 markers, received %d</string>
+8 -1
View File
@@ -19,8 +19,15 @@
<item name="android:windowBackground">@color/primary_color</item>
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
<item name="actionBarPopupTheme">@style/ThemeOverlay.MaterialComponents.ActionBar</item>
<item name="textInputStyle">@style/TextInputLayoutBase</item>
<item name="materialCardViewStyle">@style/AppTheme.MaterialCardView</item>
</style>
<style name="AppTheme.MaterialCardView" parent="Widget.MaterialComponents.CardView">
<item name="cornerRadius">4dp</item>
<item name="cardElevation">4dp</item>
<item name="contentPadding">8dp</item>
<item name="cardBackgroundColor">?attr/elevationOverlayColor</item>
</style>
<style name="AppTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog.Alert">
+13
View File
@@ -0,0 +1,13 @@
<!--
~ Copyright © 2020 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<restriction
android:defaultValue="false"
android:description="@string/disable_config_export_description"
android:key="disable_config_export"
android:restrictionType="bool"
android:title="@string/disable_config_export_title" />
</restrictions>
+2 -2
View File
@@ -1,6 +1,6 @@
buildscript {
ext {
wireguardVersionCode = 472
wireguardVersionName = '1.0.20200401'
wireguardVersionCode = 475
wireguardVersionName = '1.0.20200724'
}
}