diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2018-04-29 02:04:28 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2018-04-29 07:53:56 +0200 |
commit | 622f41f11f92005e2dd3791fd13b0ace294958d5 (patch) | |
tree | 7e811b6b9940881c36be757dbe3f4bd3223e0535 /app/src/main/java/com/wireguard/android/preference | |
parent | f4e462fabd366873cf0f1d6927469d6bac3bec0d (diff) |
Allow exporting to zip file
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'app/src/main/java/com/wireguard/android/preference')
-rw-r--r-- | app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java new file mode 100644 index 00000000..2101420f --- /dev/null +++ b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java @@ -0,0 +1,123 @@ +package com.wireguard.android.preference; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Environment; +import android.preference.Preference; +import android.util.AttributeSet; +import android.util.Log; + +import com.commonsware.cwac.crossport.design.widget.Snackbar; +import com.wireguard.android.Application; +import com.wireguard.android.Application.ApplicationComponent; +import com.wireguard.android.R; +import com.wireguard.android.activity.SettingsActivity; +import com.wireguard.android.model.Tunnel; +import com.wireguard.android.model.TunnelManager; +import com.wireguard.android.util.AsyncWorker; +import com.wireguard.android.util.ExceptionLoggers; +import com.wireguard.config.Config; + +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import java9.util.concurrent.CompletableFuture; + +/** + * Preference implementing a button that asynchronously exports config zips. + */ + +public class ZipExporterPreference extends Preference { + private static final String TAG = "WireGuard/" + ZipExporterPreference.class.getSimpleName(); + + private final AsyncWorker asyncWorker; + private final TunnelManager tunnelManager; + private String exportedFilePath = null; + + @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) + public ZipExporterPreference(final Context context, final AttributeSet attrs) { + super(context, attrs); + final ApplicationComponent applicationComponent = Application.getComponent(); + asyncWorker = applicationComponent.getAsyncWorker(); + tunnelManager = applicationComponent.getTunnelManager(); + } + + @Override + public CharSequence getSummary() { + if (exportedFilePath == null) + return getContext().getString(R.string.export_summary); + else + return getContext().getString(R.string.export_success, exportedFilePath); + } + + @Override + public CharSequence getTitle() { + return getContext().getString(getTitleRes()); + } + + @Override + public int getTitleRes() { + return R.string.zip_exporter_title; + } + + private void exportZip() { + List<Tunnel> tunnels = new ArrayList<>(tunnelManager.getTunnels()); + List<CompletableFuture<Config>> futureConfigs = new ArrayList<>(tunnels.size()); + for (final Tunnel tunnel : tunnels) + futureConfigs.add(tunnel.getConfigAsync().toCompletableFuture()); + if (futureConfigs.isEmpty()) { + exportZipComplete(null, new IllegalArgumentException("No tunnels exist")); + return; + } + CompletableFuture.allOf(futureConfigs.toArray(new CompletableFuture[futureConfigs.size()])) + .whenComplete((ignored1, exception) -> { + asyncWorker.supplyAsync(() -> { + if (exception != null) + throw exception; + final File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + final File file = new File(path, "wireguard-export.zip"); + try { + path.mkdirs(); + final ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(file)); + for (int i = 0; i < futureConfigs.size(); ++i) { + zip.putNextEntry(new ZipEntry(tunnels.get(i).getName() + ".conf")); + zip.write(futureConfigs.get(i).getNow(null).toString().getBytes(StandardCharsets.UTF_8)); + } + zip.closeEntry(); + zip.close(); + } catch (Exception e) { + file.delete(); + throw e; + } + return file.getAbsolutePath(); + }).whenComplete(this::exportZipComplete); + }); + } + + private void exportZipComplete(String filePath, Throwable throwable) { + if (throwable != null) { + final String error = ExceptionLoggers.unwrap(throwable).getMessage(); + final String message = getContext().getString(R.string.export_error, error); + Log.e(TAG, message, throwable); + Snackbar.make(((SettingsActivity)getContext()).findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG).show(); + } else { + exportedFilePath = filePath; + setEnabled(false); + notifyChanged(); + } + } + + @Override + protected void onClick() { + ((SettingsActivity)getContext()).ensurePermissions(new String[] { "android.permission.WRITE_EXTERNAL_STORAGE" }, (permissions, granted) -> { + if (granted.length > 0 && granted[0] == PackageManager.PERMISSION_GRANTED) + exportZip(); + }); + } + +} |