Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>master
@@ -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); | |||
@@ -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(); | |||
} | |||
@@ -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<TunnelListItemBinding, Tunnel>) (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<Tunnel> 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<Integer> copyCheckedItems = new HashSet<>(checkedItems); | |||
Application.getTunnelManager().getTunnels().thenAccept(tunnels -> { | |||
final Collection<Tunnel> 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; | |||
@@ -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<ObservableSortedKeyedList<String, Tunnel>> completableTunnels = new CompletableFuture<>(); | |||
private final ObservableSortedKeyedList<String, Tunnel> 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<String, Tunnel> getTunnels() { | |||
return tunnels; | |||
public CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> 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); | |||
}); | |||
} | |||
} | |||
} |
@@ -48,7 +48,10 @@ public class ZipExporterPreference extends Preference { | |||
} | |||
private void exportZip() { | |||
final List<Tunnel> tunnels = new ArrayList<>(Application.getTunnelManager().getTunnels()); | |||
Application.getTunnelManager().getTunnels().thenAccept(this::exportZip); | |||
} | |||
private void exportZip(final List<Tunnel> tunnels) { | |||
final List<CompletableFuture<Config>> futureConfigs = new ArrayList<>(tunnels.size()); | |||
for (final Tunnel tunnel : tunnels) | |||
futureConfigs.add(tunnel.getConfigAsync().toCompletableFuture()); | |||
@@ -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<K, E extends Keyed<? extends K>> extends List<E> { | |||
boolean containsKey(K key); | |||
@Nullable | |||
E get(K key); | |||
@Nullable | |||
E getLast(K key); | |||
int indexOfKey(K key); | |||
@@ -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<K, E extends Keyed<? extends K>> extends KeyedList<K, E> { | |||
Comparator<? super K> comparator(); | |||
@Nullable | |||
K firstKey(); | |||
Set<K> keySet(); | |||
@Nullable | |||
K lastKey(); | |||
Collection<E> values(); | |||