From 9652fe99df68db5c483ea8e170f6e09f06a5e0d1 Mon Sep 17 00:00:00 2001 From: Eric Kuck Date: Wed, 25 Jul 2018 19:30:34 -0500 Subject: TunnelDetailFragment now restores state correctly after process death Signed-off-by: Jason A. Donenfeld --- .../wireguard/android/activity/BaseActivity.java | 13 ++++---- .../com/wireguard/android/backend/GoBackend.java | 11 ++++--- .../android/fragment/TunnelListFragment.java | 36 ++++++++++++---------- .../com/wireguard/android/model/TunnelManager.java | 18 ++++++----- .../android/preference/ZipExporterPreference.java | 5 ++- .../main/java/com/wireguard/util/KeyedList.java | 4 +++ .../java/com/wireguard/util/SortedKeyedList.java | 4 +++ 7 files changed, 57 insertions(+), 34 deletions(-) (limited to 'app/src/main/java/com/wireguard') diff --git a/app/src/main/java/com/wireguard/android/activity/BaseActivity.java b/app/src/main/java/com/wireguard/android/activity/BaseActivity.java index 51357d89..57c70367 100644 --- a/app/src/main/java/com/wireguard/android/activity/BaseActivity.java +++ b/app/src/main/java/com/wireguard/android/activity/BaseActivity.java @@ -13,7 +13,6 @@ import android.support.annotation.Nullable; import com.wireguard.android.Application; import com.wireguard.android.model.Tunnel; -import com.wireguard.android.model.TunnelManager; import java.util.Objects; @@ -39,15 +38,17 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity { @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { // Restore the saved tunnel if there is one; otherwise grab it from the arguments. - String savedTunnelName = null; + final String savedTunnelName; if (savedInstanceState != null) savedTunnelName = savedInstanceState.getString(KEY_SELECTED_TUNNEL); else if (getIntent() != null) savedTunnelName = getIntent().getStringExtra(KEY_SELECTED_TUNNEL); - if (savedTunnelName != null) { - final TunnelManager tunnelManager = Application.getTunnelManager(); - selectedTunnel = tunnelManager.getTunnels().get(savedTunnelName); - } + else + savedTunnelName = null; + + if (savedTunnelName != null) + Application.getTunnelManager().getTunnels() + .thenAccept(tunnels -> setSelectedTunnel(tunnels.get(savedTunnelName))); // The selected tunnel must be set before the superclass method recreates fragments. super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/wireguard/android/backend/GoBackend.java b/app/src/main/java/com/wireguard/android/backend/GoBackend.java index a075913f..605f00eb 100644 --- a/app/src/main/java/com/wireguard/android/backend/GoBackend.java +++ b/app/src/main/java/com/wireguard/android/backend/GoBackend.java @@ -240,10 +240,13 @@ public final class GoBackend implements Backend { @Override public void onDestroy() { - for (final Tunnel tunnel : Application.getTunnelManager().getTunnels()) { - if (tunnel != null && tunnel.getState() != State.DOWN) - tunnel.setState(State.DOWN); - } + Application.getTunnelManager().getTunnels().thenAccept(tunnels -> { + for (final Tunnel tunnel : tunnels) { + if (tunnel != null && tunnel.getState() != State.DOWN) + tunnel.setState(State.DOWN); + } + }); + vpnService = vpnService.newIncompleteFuture(); super.onDestroy(); } 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 e2291f9c..7258f0a0 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java @@ -313,7 +313,7 @@ public class TunnelListFragment extends BaseFragment { } binding.setFragment(this); - binding.setTunnels(Application.getTunnelManager().getTunnels()); + Application.getTunnelManager().getTunnels().thenAccept(binding::setTunnels); binding.setRowConfigurationHandler((ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler) (binding, tunnel, position) -> { binding.setFragment(this); binding.getRoot().setOnClickListener(clicked -> { @@ -341,25 +341,29 @@ public class TunnelListFragment extends BaseFragment { public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { switch (item.getItemId()) { case R.id.menu_action_delete: - final Collection tunnelsToDelete = new ArrayList<>(); - for (final Integer position : checkedItems) { - tunnelsToDelete.add(Application.getTunnelManager().getTunnels().get(position)); - } - - final CompletableFuture[] futures = StreamSupport.stream(tunnelsToDelete) - .map(Tunnel::delete) - .toArray(CompletableFuture[]::new); - CompletableFuture.allOf(futures) - .thenApply(x -> futures.length) - .whenComplete(TunnelListFragment.this::onTunnelDeletionFinished); - + final Iterable copyCheckedItems = new HashSet<>(checkedItems); + Application.getTunnelManager().getTunnels().thenAccept(tunnels -> { + final Collection tunnelsToDelete = new ArrayList<>(); + for (final Integer position : copyCheckedItems) + tunnelsToDelete.add(tunnels.get(position)); + + final CompletableFuture[] futures = StreamSupport.stream(tunnelsToDelete) + .map(Tunnel::delete) + .toArray(CompletableFuture[]::new); + CompletableFuture.allOf(futures) + .thenApply(x -> futures.length) + .whenComplete(TunnelListFragment.this::onTunnelDeletionFinished); + + }); checkedItems.clear(); mode.finish(); return true; case R.id.menu_action_select_all: - for (int i = 0; i < Application.getTunnelManager().getTunnels().size(); ++i) { - setItemChecked(i, true); - } + Application.getTunnelManager().getTunnels().thenAccept(tunnels -> { + for (int i = 0; i < tunnels.size(); ++i) { + setItemChecked(i, true); + } + }); return true; default: return false; diff --git a/app/src/main/java/com/wireguard/android/model/TunnelManager.java b/app/src/main/java/com/wireguard/android/model/TunnelManager.java index f7b18c07..0032724e 100644 --- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java +++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java @@ -19,7 +19,6 @@ import com.wireguard.android.configStore.ConfigStore; import com.wireguard.android.model.Tunnel.State; import com.wireguard.android.model.Tunnel.Statistics; import com.wireguard.android.util.ExceptionLoggers; -import com.wireguard.android.util.ObservableKeyedList; import com.wireguard.android.util.ObservableSortedKeyedArrayList; import com.wireguard.android.util.ObservableSortedKeyedList; import com.wireguard.config.Config; @@ -47,6 +46,7 @@ public final class TunnelManager extends BaseObservable { private static final String KEY_RUNNING_TUNNELS = "enabled_configs"; private final ConfigStore configStore; + private final CompletableFuture> completableTunnels = new CompletableFuture<>(); private final ObservableSortedKeyedList tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR); @Nullable private Tunnel lastUsedTunnel; private boolean haveLoaded; @@ -121,8 +121,8 @@ public final class TunnelManager extends BaseObservable { .thenApply(tunnel::onStatisticsChanged); } - public ObservableKeyedList getTunnels() { - return tunnels; + public CompletableFuture> getTunnels() { + return completableTunnels; } public void onCreate() { @@ -152,6 +152,8 @@ public final class TunnelManager extends BaseObservable { f.completeExceptionally(t); } }); + + completableTunnels.complete(tunnels); } public void refreshTunnelStates() { @@ -285,10 +287,12 @@ public final class TunnelManager extends BaseObservable { final String tunnelName = intent.getStringExtra("tunnel"); if (tunnelName == null) return; - final Tunnel tunnel = manager.getTunnels().get(tunnelName); - if (tunnel == null) - return; - manager.setTunnelState(tunnel, state); + manager.getTunnels().thenAccept(tunnels -> { + final Tunnel tunnel = tunnels.get(tunnelName); + if (tunnel == null) + return; + manager.setTunnelState(tunnel, state); + }); } } } diff --git a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java index a1477214..140cffa3 100644 --- a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java +++ b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java @@ -48,7 +48,10 @@ public class ZipExporterPreference extends Preference { } private void exportZip() { - final List tunnels = new ArrayList<>(Application.getTunnelManager().getTunnels()); + Application.getTunnelManager().getTunnels().thenAccept(this::exportZip); + } + + private void exportZip(final List tunnels) { final List> futureConfigs = new ArrayList<>(tunnels.size()); for (final Tunnel tunnel : tunnels) futureConfigs.add(tunnel.getConfigAsync().toCompletableFuture()); diff --git a/app/src/main/java/com/wireguard/util/KeyedList.java b/app/src/main/java/com/wireguard/util/KeyedList.java index c4ee975e..aab8ff21 100644 --- a/app/src/main/java/com/wireguard/util/KeyedList.java +++ b/app/src/main/java/com/wireguard/util/KeyedList.java @@ -5,6 +5,8 @@ package com.wireguard.util; +import android.support.annotation.Nullable; + import java.util.Collection; import java.util.List; @@ -18,8 +20,10 @@ public interface KeyedList> extends List { boolean containsKey(K key); + @Nullable E get(K key); + @Nullable E getLast(K key); int indexOfKey(K key); diff --git a/app/src/main/java/com/wireguard/util/SortedKeyedList.java b/app/src/main/java/com/wireguard/util/SortedKeyedList.java index f166cd92..a57e9739 100644 --- a/app/src/main/java/com/wireguard/util/SortedKeyedList.java +++ b/app/src/main/java/com/wireguard/util/SortedKeyedList.java @@ -5,6 +5,8 @@ package com.wireguard.util; +import android.support.annotation.Nullable; + import java.util.Collection; import java.util.Comparator; import java.util.Set; @@ -17,10 +19,12 @@ import java.util.Set; public interface SortedKeyedList> extends KeyedList { Comparator comparator(); + @Nullable K firstKey(); Set keySet(); + @Nullable K lastKey(); Collection values(); -- cgit v1.2.3