diff options
author | Samuel Holland <samuel@sholland.org> | 2018-01-08 20:30:03 -0600 |
---|---|---|
committer | Samuel Holland <samuel@sholland.org> | 2018-01-08 20:30:03 -0600 |
commit | 710ffc7bb3b7d9e568d2447de890438d4be9a0de (patch) | |
tree | fcf0119274b4571dfd85f2083da03784c803bc5f | |
parent | 6361628e165d4275a47ae5f976c8891fb644b51a (diff) |
Fragment/Tile: Make success/error messages translatable
Signed-off-by: Samuel Holland <samuel@sholland.org>
8 files changed, 102 insertions, 74 deletions
diff --git a/app/src/main/java/com/wireguard/android/QuickTileService.java b/app/src/main/java/com/wireguard/android/QuickTileService.java index 0468f83f..7cbcf559 100644 --- a/app/src/main/java/com/wireguard/android/QuickTileService.java +++ b/app/src/main/java/com/wireguard/android/QuickTileService.java @@ -16,7 +16,6 @@ import com.wireguard.android.model.Tunnel; import com.wireguard.android.model.Tunnel.State; import com.wireguard.android.model.TunnelManager; import com.wireguard.android.util.ExceptionLoggers; -import com.wireguard.android.util.RootShell; import java.util.Objects; @@ -63,16 +62,13 @@ public class QuickTileService extends TileService { tunnelManager.removeOnPropertyChangedCallback(onTunnelChangedCallback); } - @SuppressWarnings("unused") - private Void onToggleFinished(final State state, final Throwable throwable) { + private void onToggleFinished(final State state, final Throwable throwable) { if (throwable == null) - return null; - Log.e(TAG, "Cannot toggle tunnel", throwable); - final String message = throwable instanceof RootShell.NoRootException ? - getApplicationContext().getString(R.string.error_rootshell) : - getApplicationContext().getString(R.string.error_toggle) + ": " + throwable.getMessage(); - Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); - return null; + return; + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + final String message = getString(R.string.toggle_error, error); + Log.e(TAG, message, throwable); + Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } private void updateTile() { diff --git a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java b/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java index 5ac27af4..cb5eae5d 100644 --- a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java +++ b/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java @@ -55,7 +55,7 @@ public final class WgQuickBackend implements Backend { try { if (rootShell.run(output, "wg show interfaces") != 0 || output.isEmpty()) return Collections.emptySet(); - } catch (Exception e) { + } catch (final Exception ignored) { return Collections.emptySet(); } // wg puts all interface names on the same line. Split them into separate elements. diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelController.java b/app/src/main/java/com/wireguard/android/fragment/TunnelController.java index 1a9fed6b..fd265d20 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelController.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelController.java @@ -19,7 +19,6 @@ import com.wireguard.android.databinding.TunnelListItemBinding; import com.wireguard.android.model.Tunnel; import com.wireguard.android.model.Tunnel.State; import com.wireguard.android.util.ExceptionLoggers; -import com.wireguard.android.util.RootShell; /** * Helper method shared by TunnelListFragment and TunnelDetailFragment. @@ -48,7 +47,6 @@ public final class TunnelController { tunnel.setState(State.of(checked)).whenComplete((state, throwable) -> { if (throwable == null) return; - Log.e(TAG, "Cannot set state of tunnel " + tunnel.getName(), throwable); final Context context = view.getContext(); if (throwable instanceof ErrnoException && ((ErrnoException) throwable).errno == OsConstants.ENODEV) { @@ -61,13 +59,13 @@ public final class TunnelController { // Make links work. ((TextView) dialog.findViewById(android.R.id.message)) .setMovementMethod(LinkMovementMethod.getInstance()); - } else if (throwable instanceof RootShell.NoRootException) { - Snackbar.make(view, R.string.error_rootshell, Snackbar.LENGTH_LONG).show(); + Log.e(TAG, "WireGuard not supported"); } else { - final String message = - context.getString(checked ? R.string.error_up : R.string.error_down) + ": " - + ExceptionLoggers.unwrap(throwable).getMessage(); + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + final int messageResId = checked ? R.string.error_up : R.string.error_down; + final String message = context.getString(messageResId, error); Snackbar.make(view, message, Snackbar.LENGTH_LONG).show(); + Log.e(TAG, message, throwable); } }); } diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java index f1cd7263..f72a6aea 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java @@ -60,17 +60,19 @@ public class TunnelEditorFragment extends BaseFragment { } private void onConfigSaved(final Config config, final Throwable throwable) { - if (throwable != null) { - Log.e(TAG, "Cannot save configuration", throwable); - final String message = "Cannot save configuration: " - + ExceptionLoggers.unwrap(throwable).getMessage(); + final String message; + if (throwable == null) { + message = getString(R.string.config_save_success, localTunnel.getName()); + Log.d(TAG, message); + onFinished(); + } else { + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + message = getString(R.string.config_save_error, localTunnel.getName(), error); + Log.e(TAG, message, throwable); if (binding != null) { final CoordinatorLayout container = binding.mainContainer; Snackbar.make(container, message, Snackbar.LENGTH_LONG).show(); } - } else { - Log.d(TAG, "Successfully saved configuration for " + localTunnel.getName()); - onFinished(); } } @@ -191,38 +193,40 @@ public class TunnelEditorFragment extends BaseFragment { } private void onTunnelCreated(final Tunnel tunnel, final Throwable throwable) { - if (throwable != null) { - Log.e(TAG, "Cannot create tunnel", throwable); - final String message = "Cannot create tunnel: " - + ExceptionLoggers.unwrap(throwable).getMessage(); + final String message; + if (throwable == null) { + message = getString(R.string.tunnel_create_success, tunnel.getName()); + Log.d(TAG, message); + onFinished(); + } else { + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + message = getString(R.string.tunnel_create_error, error); + Log.e(TAG, message, throwable); if (binding != null) { final CoordinatorLayout container = binding.mainContainer; Snackbar.make(container, message, Snackbar.LENGTH_LONG).show(); } - } else { - Log.d(TAG, "Successfully created tunnel " + tunnel.getName()); - localTunnel = tunnel; - onFinished(); } } - private void onTunnelRenamed(final Tunnel tunnel, final Throwable throwable) { - if (throwable != null) { - Log.e(TAG, "Cannot rename tunnel", throwable); - final String message = "Cannot rename tunnel: " - + ExceptionLoggers.unwrap(throwable).getMessage(); + final String message; + if (throwable == null) { + message = getString(R.string.tunnel_rename_success, localTunnel.getName(), + tunnel.getName()); + Log.d(TAG, message); + localTunnel = tunnel; + // Now save the rest of configuration changes. + Log.d(TAG, "Attempting to save config of renamed tunnel " + tunnel.getName()); + tunnel.setConfig(localConfig).whenComplete(this::onConfigSaved); + } else { + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + message = getString(R.string.tunnel_rename_error, error); + Log.e(TAG, message, throwable); if (binding != null) { final CoordinatorLayout container = binding.mainContainer; Snackbar.make(container, message, Snackbar.LENGTH_LONG).show(); } - } else { - Log.d(TAG, "Successfully renamed tunnel to " + tunnel.getName()); - localTunnel = tunnel; - // Now save the rest of configuration changes. - Log.d(TAG, "Attempting to save config of " + tunnel.getName()); - tunnel.setConfig(localConfig) - .whenComplete(this::onConfigSaved); } } diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java index 4634889c..79bf5d02 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java @@ -148,13 +148,12 @@ public class TunnelListFragment extends BaseFragment { private void onTunnelDeletionFinished(final Integer count, final Throwable throwable) { final String message; - final String plural = count == 1 ? "" : "s"; if (throwable == null) { - message = "Successfully deleted " + count + " tunnel" + plural; + message = getResources().getQuantityString(R.plurals.delete_success, count, count); } else { - message = "Unable to delete tunnel" + plural + ": " - + ExceptionLoggers.unwrap(throwable).getMessage(); - Log.e(TAG, "Cannot delete tunnel" + plural, throwable); + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + message = getResources().getQuantityString(R.plurals.delete_error, count, count, error); + Log.e(TAG, message, throwable); } if (binding != null) { final CoordinatorLayout container = binding.mainContainer; @@ -165,11 +164,11 @@ public class TunnelListFragment extends BaseFragment { private void onTunnelImportFinished(final Tunnel tunnel, final Throwable throwable) { final String message; if (throwable == null) { - message = "Successfully imported tunnel '" + tunnel.getName() + '\''; + message = getString(R.string.import_success, tunnel.getName()); } else { - message = "Cannot import tunnel: " - + ExceptionLoggers.unwrap(throwable).getMessage(); - Log.e(TAG, "Cannot import tunnel", throwable); + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + message = getString(R.string.import_error, error); + Log.e(TAG, message, throwable); } if (binding != null) { final CoordinatorLayout container = binding.mainContainer; @@ -245,7 +244,7 @@ public class TunnelListFragment extends BaseFragment { private void updateTitle(final ActionMode mode) { final int count = (int) getCheckedPositions().count(); - mode.setTitle(resources.getQuantityString(R.plurals.list_delete_title, count, count)); + mode.setTitle(resources.getQuantityString(R.plurals.delete_title, count, count)); } } diff --git a/app/src/main/java/com/wireguard/android/util/RootShell.java b/app/src/main/java/com/wireguard/android/util/RootShell.java index 116fbd2c..2c498131 100644 --- a/app/src/main/java/com/wireguard/android/util/RootShell.java +++ b/app/src/main/java/com/wireguard/android/util/RootShell.java @@ -7,12 +7,14 @@ import android.util.Log; import com.wireguard.android.Application.ApplicationContext; import com.wireguard.android.Application.ApplicationScope; +import com.wireguard.android.R; import java.io.BufferedWriter; import java.io.BufferedReader; import java.io.OutputStreamWriter; import java.io.InputStreamReader; import java.io.File; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.UUID; @@ -34,6 +36,7 @@ public class RootShell { {"libwg-quick.so", "wg-quick"} }; + private final String exceptionMessage; private final String preamble; private BufferedWriter stdin; @@ -59,6 +62,7 @@ public class RootShell { builder.append(String.format("export PATH=\"%s:$PATH\" TMPDIR=\"%s\";", binDir, tmpDir)); builder.append("id;\n"); + exceptionMessage = context.getString(R.string.error_root); preamble = builder.toString(); } @@ -72,7 +76,7 @@ public class RootShell { return false; } - private void ensureRoot() throws Exception { + private void ensureRoot() throws ErrnoException, IOException, NoRootException { try { if (process != null) { process.exitValue(); @@ -83,7 +87,7 @@ public class RootShell { } if (!isExecutable("su")) - throw new NoRootException(); + throw new NoRootException(exceptionMessage); try { final ProcessBuilder builder = new ProcessBuilder(); @@ -103,8 +107,8 @@ public class RootShell { int errno = process.exitValue(); String line; while ((line = stderr.readLine()) != null) { - if (line.contains("Permission denied")) - throw new NoRootException(); + if (line.contains("Permission denied")) + throw new NoRootException(exceptionMessage); } throw new ErrnoException("Unknown error when obtaining root access", errno); } catch (IllegalThreadStateException e) { @@ -112,7 +116,7 @@ public class RootShell { } if (id == null || !id.contains("uid=0")) - throw new NoRootException(); + throw new NoRootException(exceptionMessage); } catch (Exception e) { Log.w(TAG, "Session failed with exception", e); process.destroy(); @@ -121,7 +125,7 @@ public class RootShell { if (match.find()) { final int errno = Integer.valueOf(match.group(1)); if (errno == OsConstants.EACCES) - throw new NoRootException(); + throw new NoRootException(exceptionMessage); else throw new ErrnoException("Unknown error when obtaining root access", errno); } @@ -137,7 +141,8 @@ public class RootShell { * @param command Command to run as root. * @return The exit value of the last command run, or -1 if there was an internal error. */ - public int run(final List<String> output, final String command) throws Exception { + public int run(final List<String> output, final String command) + throws ErrnoException, IOException, NoRootException { ensureRoot(); StringBuilder builder = new StringBuilder(); @@ -205,6 +210,9 @@ public class RootShell { return errnoStdout; } - public class NoRootException extends Exception { + public static class NoRootException extends Exception { + public NoRootException(final String message) { + super(message); + } } } diff --git a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java index aeffa364..4b844991 100644 --- a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java +++ b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java @@ -1,12 +1,15 @@ package com.wireguard.android.util; import android.content.Context; +import android.system.ErrnoException; import android.system.OsConstants; import com.wireguard.android.Application.ApplicationContext; import com.wireguard.android.Application.ApplicationScope; +import com.wireguard.android.util.RootShell.NoRootException; import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -67,7 +70,11 @@ public final class ToolsInstaller { } try { return rootShell.run(null, script.toString()); - } catch (Exception e) { + } catch (final ErrnoException e) { + return e.errno; + } catch (final IOException ignored) { + return OsConstants.EXIT_FAILURE; + } catch (final NoRootException ignored) { return OsConstants.EACCES; } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7d129454..7140bb7b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,13 +1,23 @@ <?xml version="1.0" encoding="utf-8"?> -<resources> - <plurals name="list_delete_title"> - <item quantity="one">%d configuration selected</item> - <item quantity="other">%d configurations selected</item> +<resources xmlns:tools="http://schemas.android.com/tools"> + <plurals name="delete_error"> + <item quantity="one">Unable to delete %d tunnel: %s</item> + <item quantity="other">Unable to delete %d tunnels: %s</item> + </plurals> + <plurals name="delete_success"> + <item quantity="one">Successfully deleted %d tunnel</item> + <item quantity="other">Successfully deleted %d tunnels</item> + </plurals> + <plurals name="delete_title"> + <item quantity="one">%d tunnel selected</item> + <item quantity="other">%d tunnels selected</item> </plurals> <string name="add_peer">Add peer</string> <string name="addresses">Addresses</string> <string name="allowed_ips">Allowed IPs</string> <string name="app_name">WireGuard</string> + <string name="config_save_error">Unable to configuration for “%s”: %s</string> + <string name="config_save_success">Successfully saved configuration for “%s”</string> <string name="create_activity_title">Create WireGuard Tunnel</string> <string name="create_empty">Create from scratch</string> <string name="create_from_file">Create from file</string> @@ -15,20 +25,21 @@ <string name="dns_servers">DNS servers</string> <string name="edit">Edit</string> <string name="endpoint">Endpoint</string> - <string name="error_down">Error bringing down WireGuard tunnel</string> - <string name="error_up">Error bringing up WireGuard tunnel</string> - <string name="error_toggle">Error toggling WireGuard tunnel</string> - <string name="error_rootshell">Please obtain root access and try again</string> + <string name="error_down">Error bringing down tunnel: %s</string> + <string name="error_root">Please obtain root access and try again</string> + <string name="error_up">Error bringing up tunnel: %s</string> <string name="generate">Generate</string> <string name="hint_automatic">(auto)</string> <string name="hint_generated">(generated)</string> <string name="hint_optional">(optional)</string> <string name="hint_random">(random)</string> + <string name="import_error">Unable to import tunnel: %s</string> + <string name="import_success">Successfully imported “%s”</string> <string name="interface_title">Interface</string> <string name="listen_port">Listen port</string> <string name="mtu">MTU</string> <string name="name">Name</string> - <string name="not_supported_message"><![CDATA[ + <string name="not_supported_message" tools:ignore="TypographyQuotes"><![CDATA[ <p>Your Android device does not <em>currently</em> have the WireGuard kernel module. Please talk to the manufacturer of your Android device or the author of your device’s ROM about including the WireGuard kernel module.</p> @@ -55,10 +66,15 @@ <string name="restore_on_boot_title">Restore on boot</string> <string name="save">Save</string> <string name="settings">Settings</string> + <string name="toggle_error">Error toggling WireGuard tunnel: %s</string> <string name="tools_installer_already">wg and wg-quick are already installed</string> - <string name="tools_installer_failure">Command line tools could not be installed (no root?)</string> + <string name="tools_installer_failure">Unable to install command-line tools (no root?)</string> <string name="tools_installer_initial">Install optional tools for scripting into the system partition</string> <string name="tools_installer_success">wg and wg-quick installed into the system partition</string> <string name="tools_installer_title">Install command line tools</string> <string name="tools_installer_working">Installing wg and wg-quick into the system partition</string> + <string name="tunnel_create_error">Unable to create tunnel: %s</string> + <string name="tunnel_create_success">Successfully created tunnel “%s”</string> + <string name="tunnel_rename_error">Unable to rename tunnel: %s</string> + <string name="tunnel_rename_success">Successfully renamed tunnel “%s” to “%s”</string> </resources> |