Convert the list of tunnels to a KeyedObservableList
Signed-off-by: Samuel Holland <samuel@sholland.org>
This commit is contained in:
parent
c73287f64b
commit
ff0bb081a0
@ -6,7 +6,8 @@ import android.content.SharedPreferences;
|
|||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
import android.databinding.Observable;
|
import android.databinding.Observable;
|
||||||
import android.databinding.Observable.OnPropertyChangedCallback;
|
import android.databinding.Observable.OnPropertyChangedCallback;
|
||||||
import android.databinding.ObservableMap.OnMapChangedCallback;
|
import android.databinding.ObservableList;
|
||||||
|
import android.databinding.ObservableList.OnListChangedCallback;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.service.quicksettings.Tile;
|
import android.service.quicksettings.Tile;
|
||||||
@ -19,8 +20,8 @@ import com.wireguard.android.activity.MainActivity;
|
|||||||
import com.wireguard.android.activity.SettingsActivity;
|
import com.wireguard.android.activity.SettingsActivity;
|
||||||
import com.wireguard.android.model.Tunnel;
|
import com.wireguard.android.model.Tunnel;
|
||||||
import com.wireguard.android.model.Tunnel.State;
|
import com.wireguard.android.model.Tunnel.State;
|
||||||
import com.wireguard.android.model.TunnelCollection;
|
|
||||||
import com.wireguard.android.model.TunnelManager;
|
import com.wireguard.android.model.TunnelManager;
|
||||||
|
import com.wireguard.android.util.KeyedObservableList;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -33,9 +34,8 @@ import java.util.Objects;
|
|||||||
@TargetApi(Build.VERSION_CODES.N)
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
public class QuickTileService extends TileService implements OnSharedPreferenceChangeListener {
|
public class QuickTileService extends TileService implements OnSharedPreferenceChangeListener {
|
||||||
private static final String TAG = QuickTileService.class.getSimpleName();
|
private static final String TAG = QuickTileService.class.getSimpleName();
|
||||||
|
private final OnTunnelListChangedCallback listCallback = new OnTunnelListChangedCallback();
|
||||||
private final OnTunnelStateChangedCallback tunnelCallback = new OnTunnelStateChangedCallback();
|
private final OnTunnelStateChangedCallback tunnelCallback = new OnTunnelStateChangedCallback();
|
||||||
private final OnTunnelMapChangedCallback tunnelMapCallback = new OnTunnelMapChangedCallback();
|
|
||||||
private SharedPreferences preferences;
|
private SharedPreferences preferences;
|
||||||
private Tunnel tunnel;
|
private Tunnel tunnel;
|
||||||
private TunnelManager tunnelManager;
|
private TunnelManager tunnelManager;
|
||||||
@ -75,7 +75,7 @@ public class QuickTileService extends TileService implements OnSharedPreferenceC
|
|||||||
@Override
|
@Override
|
||||||
public void onStartListening() {
|
public void onStartListening() {
|
||||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||||
tunnelManager.getTunnels().addOnMapChangedCallback(tunnelMapCallback);
|
tunnelManager.getTunnels().addOnListChangedCallback(listCallback);
|
||||||
if (tunnel != null)
|
if (tunnel != null)
|
||||||
tunnel.addOnPropertyChangedCallback(tunnelCallback);
|
tunnel.addOnPropertyChangedCallback(tunnelCallback);
|
||||||
updateTile();
|
updateTile();
|
||||||
@ -84,7 +84,7 @@ public class QuickTileService extends TileService implements OnSharedPreferenceC
|
|||||||
@Override
|
@Override
|
||||||
public void onStopListening() {
|
public void onStopListening() {
|
||||||
preferences.unregisterOnSharedPreferenceChangeListener(this);
|
preferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
tunnelManager.getTunnels().removeOnMapChangedCallback(tunnelMapCallback);
|
tunnelManager.getTunnels().removeOnListChangedCallback(listCallback);
|
||||||
if (tunnel != null)
|
if (tunnel != null)
|
||||||
tunnel.removeOnPropertyChangedCallback(tunnelCallback);
|
tunnel.removeOnPropertyChangedCallback(tunnelCallback);
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ public class QuickTileService extends TileService implements OnSharedPreferenceC
|
|||||||
final String currentName = tunnel != null ? tunnel.getName() : null;
|
final String currentName = tunnel != null ? tunnel.getName() : null;
|
||||||
final String newName = preferences.getString(TunnelManager.KEY_PRIMARY_TUNNEL, null);
|
final String newName = preferences.getString(TunnelManager.KEY_PRIMARY_TUNNEL, null);
|
||||||
if (!Objects.equals(currentName, newName)) {
|
if (!Objects.equals(currentName, newName)) {
|
||||||
final TunnelCollection tunnels = tunnelManager.getTunnels();
|
final KeyedObservableList<String, Tunnel> tunnels = tunnelManager.getTunnels();
|
||||||
final Tunnel newTunnel = newName != null ? tunnels.get(newName) : null;
|
final Tunnel newTunnel = newName != null ? tunnels.get(newName) : null;
|
||||||
if (tunnel != null)
|
if (tunnel != null)
|
||||||
tunnel.removeOnPropertyChangedCallback(tunnelCallback);
|
tunnel.removeOnPropertyChangedCallback(tunnelCallback);
|
||||||
@ -134,12 +134,35 @@ public class QuickTileService extends TileService implements OnSharedPreferenceC
|
|||||||
tile.updateTile();
|
tile.updateTile();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class OnTunnelMapChangedCallback
|
private final class OnTunnelListChangedCallback
|
||||||
extends OnMapChangedCallback<TunnelCollection, String, Tunnel> {
|
extends OnListChangedCallback<ObservableList<Tunnel>> {
|
||||||
@Override
|
@Override
|
||||||
public void onMapChanged(final TunnelCollection sender, final String key) {
|
public void onChanged(final ObservableList<Tunnel> sender) {
|
||||||
if (!key.equals(preferences.getString(TunnelManager.KEY_PRIMARY_TUNNEL, null)))
|
updateTile();
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemRangeChanged(final ObservableList<Tunnel> sender,
|
||||||
|
final int positionStart, final int itemCount) {
|
||||||
|
updateTile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemRangeInserted(final ObservableList<Tunnel> sender,
|
||||||
|
final int positionStart, final int itemCount) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemRangeMoved(final ObservableList<Tunnel> sender,
|
||||||
|
final int fromPosition, final int toPosition,
|
||||||
|
final int itemCount) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemRangeRemoved(final ObservableList<Tunnel> sender,
|
||||||
|
final int positionStart, final int itemCount) {
|
||||||
updateTile();
|
updateTile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import android.widget.ListView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.wireguard.android.R;
|
import com.wireguard.android.R;
|
||||||
|
import com.wireguard.android.util.Keyed;
|
||||||
|
import com.wireguard.android.util.KeyedObservableList;
|
||||||
import com.wireguard.android.widget.ToggleSwitch;
|
import com.wireguard.android.widget.ToggleSwitch;
|
||||||
|
|
||||||
import org.threeten.bp.Instant;
|
import org.threeten.bp.Instant;
|
||||||
@ -63,14 +65,15 @@ public final class BindingAdapters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@BindingAdapter({"items", "layout"})
|
@BindingAdapter({"items", "layout"})
|
||||||
public static <T> void setItems(final ListView view,
|
public static <K, E extends Keyed<? extends K>>
|
||||||
final ObservableList<T> oldList, final int oldLayoutId,
|
void setItems(final ListView view,
|
||||||
final ObservableList<T> newList, final int newLayoutId) {
|
final KeyedObservableList<K, E> oldList, final int oldLayoutId,
|
||||||
|
final KeyedObservableList<K, E> newList, final int newLayoutId) {
|
||||||
if (oldList == newList && oldLayoutId == newLayoutId)
|
if (oldList == newList && oldLayoutId == newLayoutId)
|
||||||
return;
|
return;
|
||||||
// The ListAdapter interface is not generic, so this cannot be checked.
|
// The ListAdapter interface is not generic, so this cannot be checked.
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked") KeyedObservableListAdapter<K, E> adapter =
|
||||||
ObservableListAdapter<T> adapter = (ObservableListAdapter<T>) view.getAdapter();
|
(KeyedObservableListAdapter<K, E>) view.getAdapter();
|
||||||
// If the layout changes, any existing adapter must be replaced.
|
// If the layout changes, any existing adapter must be replaced.
|
||||||
if (adapter != null && oldList != null && oldLayoutId != newLayoutId) {
|
if (adapter != null && oldList != null && oldLayoutId != newLayoutId) {
|
||||||
adapter.setList(null);
|
adapter.setList(null);
|
||||||
@ -80,7 +83,7 @@ public final class BindingAdapters {
|
|||||||
if (newList == null || newLayoutId == 0)
|
if (newList == null || newLayoutId == 0)
|
||||||
return;
|
return;
|
||||||
if (adapter == null) {
|
if (adapter == null) {
|
||||||
adapter = new ObservableListAdapter<>(view.getContext(), newLayoutId, newList);
|
adapter = new KeyedObservableListAdapter<>(view.getContext(), newLayoutId, newList);
|
||||||
view.setAdapter(adapter);
|
view.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
// Either the list changed, or this is an entirely new listener because the layout changed.
|
// Either the list changed, or this is an entirely new listener because the layout changed.
|
||||||
|
@ -9,6 +9,7 @@ import com.wireguard.android.BR;
|
|||||||
import com.wireguard.android.backend.Backend;
|
import com.wireguard.android.backend.Backend;
|
||||||
import com.wireguard.android.configStore.ConfigStore;
|
import com.wireguard.android.configStore.ConfigStore;
|
||||||
import com.wireguard.android.util.ExceptionLoggers;
|
import com.wireguard.android.util.ExceptionLoggers;
|
||||||
|
import com.wireguard.android.util.Keyed;
|
||||||
import com.wireguard.config.Config;
|
import com.wireguard.config.Config;
|
||||||
|
|
||||||
import org.threeten.bp.Instant;
|
import org.threeten.bp.Instant;
|
||||||
@ -23,7 +24,7 @@ import java9.util.concurrent.CompletionStage;
|
|||||||
* Encapsulates the volatile and nonvolatile state of a WireGuard tunnel.
|
* Encapsulates the volatile and nonvolatile state of a WireGuard tunnel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Tunnel extends BaseObservable implements Comparable<Tunnel> {
|
public class Tunnel extends BaseObservable implements Keyed<String> {
|
||||||
public static final int NAME_MAX_LENGTH = 16;
|
public static final int NAME_MAX_LENGTH = 16;
|
||||||
private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,16}");
|
private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,16}");
|
||||||
private static final String TAG = Tunnel.class.getSimpleName();
|
private static final String TAG = Tunnel.class.getSimpleName();
|
||||||
@ -48,11 +49,6 @@ public class Tunnel extends BaseObservable implements Comparable<Tunnel> {
|
|||||||
return name != null && NAME_PATTERN.matcher(name).matches();
|
return name != null && NAME_PATTERN.matcher(name).matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(@NonNull final Tunnel tunnel) {
|
|
||||||
return name.compareTo(tunnel.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bindable
|
@Bindable
|
||||||
public Config getConfig() {
|
public Config getConfig() {
|
||||||
if (config == null)
|
if (config == null)
|
||||||
@ -66,6 +62,11 @@ public class Tunnel extends BaseObservable implements Comparable<Tunnel> {
|
|||||||
return CompletableFuture.completedFuture(config);
|
return CompletableFuture.completedFuture(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
@Bindable
|
@Bindable
|
||||||
public Instant getLastStateChange() {
|
public Instant getLastStateChange() {
|
||||||
return lastStateChange;
|
return lastStateChange;
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package com.wireguard.android.model;
|
|
||||||
|
|
||||||
import com.wireguard.android.databinding.ObservableTreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by samuel on 12/19/17.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class TunnelCollection extends ObservableTreeMap<String, Tunnel> {
|
|
||||||
}
|
|
@ -8,6 +8,8 @@ import com.wireguard.android.backend.Backend;
|
|||||||
import com.wireguard.android.configStore.ConfigStore;
|
import com.wireguard.android.configStore.ConfigStore;
|
||||||
import com.wireguard.android.model.Tunnel.State;
|
import com.wireguard.android.model.Tunnel.State;
|
||||||
import com.wireguard.android.util.ExceptionLoggers;
|
import com.wireguard.android.util.ExceptionLoggers;
|
||||||
|
import com.wireguard.android.util.KeyedObservableList;
|
||||||
|
import com.wireguard.android.util.SortedKeyedObservableArrayList;
|
||||||
import com.wireguard.config.Config;
|
import com.wireguard.config.Config;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -35,7 +37,8 @@ public final class TunnelManager {
|
|||||||
private final Backend backend;
|
private final Backend backend;
|
||||||
private final ConfigStore configStore;
|
private final ConfigStore configStore;
|
||||||
private final SharedPreferences preferences;
|
private final SharedPreferences preferences;
|
||||||
private final TunnelCollection tunnels = new TunnelCollection();
|
private final KeyedObservableList<String, Tunnel> tunnels =
|
||||||
|
new SortedKeyedObservableArrayList<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TunnelManager(final Backend backend, final ConfigStore configStore,
|
public TunnelManager(final Backend backend, final ConfigStore configStore,
|
||||||
@ -47,7 +50,7 @@ public final class TunnelManager {
|
|||||||
|
|
||||||
private Tunnel add(final String name, final Config config) {
|
private Tunnel add(final String name, final Config config) {
|
||||||
final Tunnel tunnel = new Tunnel(backend, configStore, name, config);
|
final Tunnel tunnel = new Tunnel(backend, configStore, name, config);
|
||||||
tunnels.put(name, tunnel);
|
tunnels.add(tunnel);
|
||||||
return tunnel;
|
return tunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,13 +74,13 @@ public final class TunnelManager {
|
|||||||
return backend.setState(tunnel, State.DOWN)
|
return backend.setState(tunnel, State.DOWN)
|
||||||
.thenCompose(x -> configStore.delete(tunnel.getName()))
|
.thenCompose(x -> configStore.delete(tunnel.getName()))
|
||||||
.thenAccept(x -> {
|
.thenAccept(x -> {
|
||||||
tunnels.remove(tunnel.getName());
|
tunnels.remove(tunnel);
|
||||||
if (tunnel.getName().equals(preferences.getString(KEY_PRIMARY_TUNNEL, null)))
|
if (tunnel.getName().equals(preferences.getString(KEY_PRIMARY_TUNNEL, null)))
|
||||||
preferences.edit().remove(KEY_PRIMARY_TUNNEL).apply();
|
preferences.edit().remove(KEY_PRIMARY_TUNNEL).apply();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public TunnelCollection getTunnels() {
|
public KeyedObservableList<String, Tunnel> getTunnels() {
|
||||||
return tunnels;
|
return tunnels;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +108,7 @@ public final class TunnelManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CompletionStage<Void> saveState() {
|
public CompletionStage<Void> saveState() {
|
||||||
final Set<String> runningTunnels = StreamSupport.stream(tunnels.values())
|
final Set<String> runningTunnels = StreamSupport.stream(tunnels)
|
||||||
.filter(tunnel -> tunnel.getState() == State.UP)
|
.filter(tunnel -> tunnel.getState() == State.UP)
|
||||||
.map(Tunnel::getName)
|
.map(Tunnel::getName)
|
||||||
.collect(Collectors.toUnmodifiableSet());
|
.collect(Collectors.toUnmodifiableSet());
|
||||||
|
@ -5,19 +5,23 @@ import android.preference.ListPreference;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
import com.wireguard.android.Application;
|
||||||
|
import com.wireguard.android.model.Tunnel;
|
||||||
|
import com.wireguard.android.model.TunnelManager;
|
||||||
|
|
||||||
import java.util.Set;
|
import java9.util.stream.StreamSupport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ListPreference that is automatically filled with the list of configurations.
|
* ListPreference that is automatically filled with the list of tunnels.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class TunnelListPreference extends ListPreference {
|
public class TunnelListPreference extends ListPreference {
|
||||||
public TunnelListPreference(final Context context, final AttributeSet attrs,
|
public TunnelListPreference(final Context context, final AttributeSet attrs,
|
||||||
final int defStyleAttr, final int defStyleRes) {
|
final int defStyleAttr, final int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
final Set<String> entrySet = Application.getComponent().getTunnelManager().getTunnels().keySet();
|
final TunnelManager tunnelManager = Application.getComponent().getTunnelManager();
|
||||||
final CharSequence[] entries = entrySet.toArray(new CharSequence[entrySet.size()]);
|
final CharSequence[] entries = StreamSupport.stream(tunnelManager.getTunnels())
|
||||||
|
.map(Tunnel::getName)
|
||||||
|
.toArray(String[]::new);
|
||||||
setEntries(entries);
|
setEntries(entries);
|
||||||
setEntryValues(entries);
|
setEntryValues(entries);
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,15 @@
|
|||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
|
<import type="com.wireguard.android.model.Tunnel" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="fragment"
|
name="fragment"
|
||||||
type="com.wireguard.android.fragment.TunnelListFragment" />
|
type="com.wireguard.android.fragment.TunnelListFragment" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="tunnels"
|
name="tunnels"
|
||||||
type="com.wireguard.android.model.TunnelCollection" />
|
type="com.wireguard.android.util.KeyedObservableList<String, Tunnel>" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<com.commonsware.cwac.crossport.design.widget.CoordinatorLayout
|
<com.commonsware.cwac.crossport.design.widget.CoordinatorLayout
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
|
<import type="com.wireguard.android.model.Tunnel" />
|
||||||
|
|
||||||
<import type="com.wireguard.android.model.Tunnel.State" />
|
<import type="com.wireguard.android.model.Tunnel.State" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="collection"
|
name="collection"
|
||||||
type="com.wireguard.android.model.TunnelCollection" />
|
type="com.wireguard.android.util.KeyedObservableList<String, Tunnel>" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="key"
|
name="key"
|
||||||
|
Loading…
Reference in New Issue
Block a user