summaryrefslogtreecommitdiffhomepage
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/com/wireguard/android/Application.java106
-rw-r--r--app/src/main/java/com/wireguard/android/QuickTileService.java36
-rw-r--r--app/src/main/java/com/wireguard/android/activity/SettingsActivity.java4
-rw-r--r--app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java7
-rw-r--r--app/src/main/java/com/wireguard/android/backend/Backend.java18
-rw-r--r--app/src/main/java/com/wireguard/android/backend/GoBackend.java16
-rw-r--r--app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java26
-rw-r--r--app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java28
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java70
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/BaseFragment.java27
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.java56
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java135
-rw-r--r--app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java82
-rw-r--r--app/src/main/java/com/wireguard/android/model/ApplicationData.java10
-rw-r--r--app/src/main/java/com/wireguard/android/model/Tunnel.java3
-rw-r--r--app/src/main/java/com/wireguard/android/model/TunnelManager.java27
-rw-r--r--app/src/main/java/com/wireguard/android/preference/VersionPreference.java3
-rw-r--r--app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java3
-rw-r--r--app/src/main/java/com/wireguard/android/util/ToolsInstaller.java65
-rw-r--r--app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java10
-rw-r--r--app/src/main/java/com/wireguard/android/widget/SlashDrawable.java191
-rw-r--r--app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java22
-rw-r--r--app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java455
-rw-r--r--app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java14
-rw-r--r--app/src/main/java/com/wireguard/config/Config.java2
-rw-r--r--app/src/main/java/com/wireguard/config/Interface.java10
-rw-r--r--app/src/main/java/com/wireguard/config/Peer.java87
-rw-r--r--app/src/main/java/com/wireguard/util/NonNullForAll.java3
-rw-r--r--app/src/main/res/drawable/ic_action_select_all.xml8
-rw-r--r--app/src/main/res/drawable/ic_settings.xml2
-rw-r--r--app/src/main/res/drawable/list_item_background.xml8
-rw-r--r--app/src/main/res/layout/app_list_dialog_fragment.xml4
-rw-r--r--app/src/main/res/layout/app_list_item.xml9
-rw-r--r--app/src/main/res/layout/config_naming_dialog_fragment.xml1
-rw-r--r--app/src/main/res/layout/tunnel_editor_fragment.xml6
-rw-r--r--app/src/main/res/layout/tunnel_editor_peer.xml3
-rw-r--r--app/src/main/res/layout/tunnel_list_fragment.xml38
-rw-r--r--app/src/main/res/menu/main_activity.xml4
-rw-r--r--app/src/main/res/values/attrs.xml4
-rw-r--r--app/src/main/res/values/fab.xml20
-rw-r--r--app/src/main/res/xml/preferences.xml2
42 files changed, 819 insertions, 810 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b97dbc7d..02930b27 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,10 +11,10 @@
<permission
android:name="${applicationId}.permission.CONTROL_TUNNELS"
- android:protectionLevel="dangerous"
+ android:description="@string/permission_description"
android:icon="@mipmap/ic_launcher"
android:label="@string/permission_label"
- android:description="@string/permission_description" />
+ android:protectionLevel="dangerous" />
<application
android:name=".Application"
diff --git a/app/src/main/java/com/wireguard/android/Application.java b/app/src/main/java/com/wireguard/android/Application.java
index d528629a..9921f615 100644
--- a/app/src/main/java/com/wireguard/android/Application.java
+++ b/app/src/main/java/com/wireguard/android/Application.java
@@ -53,18 +53,50 @@ import java9.util.concurrent.CompletableFuture;
compress = true)
public class Application extends android.app.Application {
@SuppressWarnings("NullableProblems") private static WeakReference<Application> weakSelf;
+ private final CompletableFuture<Backend> futureBackend = new CompletableFuture<>();
@SuppressWarnings("NullableProblems") private AsyncWorker asyncWorker;
+ @Nullable private Backend backend;
@SuppressWarnings("NullableProblems") private RootShell rootShell;
@SuppressWarnings("NullableProblems") private SharedPreferences sharedPreferences;
@SuppressWarnings("NullableProblems") private ToolsInstaller toolsInstaller;
@SuppressWarnings("NullableProblems") private TunnelManager tunnelManager;
- @Nullable private Backend backend;
- private final CompletableFuture<Backend> futureBackend = new CompletableFuture<>();
public Application() {
weakSelf = new WeakReference<>(this);
}
+ public static Application get() {
+ return weakSelf.get();
+ }
+
+ public static AsyncWorker getAsyncWorker() {
+ return get().asyncWorker;
+ }
+
+ public static Backend getBackend() {
+ final Application app = get();
+ synchronized (app.futureBackend) {
+ if (app.backend == null) {
+ Backend backend = null;
+ if (new File("/sys/module/wireguard").exists()) {
+ try {
+ app.rootShell.start();
+ backend = new WgQuickBackend(app.getApplicationContext());
+ } catch (final Exception ignored) {
+ }
+ }
+ if (backend == null)
+ backend = new GoBackend(app.getApplicationContext());
+ app.backend = backend;
+ }
+ return app.backend;
+ }
+ }
+
+ public static CompletableFuture<Backend> getBackendAsync() {
+ return get().futureBackend;
+ }
+
/* The ACRA password can be trivially reverse engineered and is open source anyway,
* so there's no point in trying to protect it. However, we do want to at least
* prevent innocent self-builders from uploading stuff to our crash reporter. So, we
@@ -91,12 +123,30 @@ public class Application extends android.app.Application {
return "F-Droid";
}
}
- } catch (final Exception ignored) { }
+ } catch (final Exception ignored) {
+ }
}
- } catch (final Exception ignored) { }
+ } catch (final Exception ignored) {
+ }
return null;
}
+ public static RootShell getRootShell() {
+ return get().rootShell;
+ }
+
+ public static SharedPreferences getSharedPreferences() {
+ return get().sharedPreferences;
+ }
+
+ public static ToolsInstaller getToolsInstaller() {
+ return get().toolsInstaller;
+ }
+
+ public static TunnelManager getTunnelManager() {
+ return get().tunnelManager;
+ }
+
@Override
protected void attachBaseContext(final Context context) {
super.attachBaseContext(context);
@@ -117,54 +167,6 @@ public class Application extends android.app.Application {
}
}
- public static Application get() {
- return weakSelf.get();
- }
-
- public static AsyncWorker getAsyncWorker() {
- return get().asyncWorker;
- }
-
- public static Backend getBackend() {
- final Application app = get();
- synchronized (app.futureBackend) {
- if (app.backend == null) {
- Backend backend = null;
- if (new File("/sys/module/wireguard").exists()) {
- try {
- app.rootShell.start();
- backend = new WgQuickBackend(app.getApplicationContext());
- } catch (final Exception ignored) {
- }
- }
- if (backend == null)
- backend = new GoBackend(app.getApplicationContext());
- app.backend = backend;
- }
- return app.backend;
- }
- }
-
- public static CompletableFuture<Backend> getBackendAsync() {
- return get().futureBackend;
- }
-
- public static RootShell getRootShell() {
- return get().rootShell;
- }
-
- public static SharedPreferences getSharedPreferences() {
- return get().sharedPreferences;
- }
-
- public static ToolsInstaller getToolsInstaller() {
- return get().toolsInstaller;
- }
-
- public static TunnelManager getTunnelManager() {
- return get().tunnelManager;
- }
-
@Override
public void onCreate() {
super.onCreate();
diff --git a/app/src/main/java/com/wireguard/android/QuickTileService.java b/app/src/main/java/com/wireguard/android/QuickTileService.java
index 28e2b2ee..2463896e 100644
--- a/app/src/main/java/com/wireguard/android/QuickTileService.java
+++ b/app/src/main/java/com/wireguard/android/QuickTileService.java
@@ -40,9 +40,9 @@ public class QuickTileService extends TileService {
private final OnStateChangedCallback onStateChangedCallback = new OnStateChangedCallback();
private final OnTunnelChangedCallback onTunnelChangedCallback = new OnTunnelChangedCallback();
- @Nullable private Tunnel tunnel;
- @Nullable private Icon iconOn;
@Nullable private Icon iconOff;
+ @Nullable private Icon iconOn;
+ @Nullable private Tunnel tunnel;
/* This works around an annoying unsolved frameworks bug some people are hitting. */
@Override
@@ -58,6 +58,22 @@ public class QuickTileService extends TileService {
}
@Override
+ public void onClick() {
+ if (tunnel != null) {
+ final Tile tile = getQsTile();
+ if (tile != null) {
+ tile.setIcon(tile.getIcon() == iconOn ? iconOff : iconOn);
+ tile.updateTile();
+ }
+ tunnel.setState(State.TOGGLE).whenComplete(this::onToggleFinished);
+ } else {
+ final Intent intent = new Intent(this, MainActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivityAndCollapse(intent);
+ }
+ }
+
+ @Override
public void onCreate() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
iconOff = iconOn = Icon.createWithResource(this, R.drawable.ic_tile);
@@ -80,22 +96,6 @@ public class QuickTileService extends TileService {
}
@Override
- public void onClick() {
- if (tunnel != null) {
- final Tile tile = getQsTile();
- if (tile != null) {
- tile.setIcon(tile.getIcon() == iconOn ? iconOff : iconOn);
- tile.updateTile();
- }
- tunnel.setState(State.TOGGLE).whenComplete(this::onToggleFinished);
- } else {
- final Intent intent = new Intent(this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivityAndCollapse(intent);
- }
- }
-
- @Override
public void onStartListening() {
Application.getTunnelManager().addOnPropertyChangedCallback(onTunnelChangedCallback);
if (tunnel != null)
diff --git a/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java b/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
index f8fea403..b827ca1b 100644
--- a/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
@@ -92,8 +92,8 @@ public class SettingsActivity extends ThemeChangeAwareActivity {
public void onCreatePreferences(final Bundle savedInstanceState, final String key) {
addPreferencesFromResource(R.xml.preferences);
final Preference wgQuickOnlyPrefs[] = {
- getPreferenceManager().findPreference("tools_installer"),
- getPreferenceManager().findPreference("restore_on_boot")
+ getPreferenceManager().findPreference("tools_installer"),
+ getPreferenceManager().findPreference("restore_on_boot")
};
for (final Preference pref : wgQuickOnlyPrefs)
pref.setVisible(false);
diff --git a/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java b/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java
index 9a6e2edc..fbae2165 100644
--- a/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java
@@ -19,9 +19,9 @@ import java.lang.reflect.Field;
public abstract class ThemeChangeAwareActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "WireGuard/" + ThemeChangeAwareActivity.class.getSimpleName();
-
- @Nullable private static Resources lastResources;
private static boolean lastDarkMode;
+ @Nullable private static Resources lastResources;
+
private static synchronized void invalidateDrawableCache(final Resources resources, final boolean darkMode) {
if (resources == lastResources && darkMode == lastDarkMode)
return;
@@ -33,7 +33,8 @@ public abstract class ThemeChangeAwareActivity extends AppCompatActivity impleme
f = o.getClass().getDeclaredField("mResourcesImpl");
f.setAccessible(true);
o = f.get(o);
- } catch (final Exception ignored) { }
+ } catch (final Exception ignored) {
+ }
f = o.getClass().getDeclaredField("mDrawableCache");
f.setAccessible(true);
o = f.get(o);
diff --git a/app/src/main/java/com/wireguard/android/backend/Backend.java b/app/src/main/java/com/wireguard/android/backend/Backend.java
index 000a572a..64bb3d02 100644
--- a/app/src/main/java/com/wireguard/android/backend/Backend.java
+++ b/app/src/main/java/com/wireguard/android/backend/Backend.java
@@ -53,14 +53,11 @@ public interface Backend {
Statistics getStatistics(Tunnel tunnel) throws Exception;
/**
- * Set the state of a tunnel.
+ * Determine type name of underlying backend.
*
- * @param tunnel The tunnel to control the state of.
- * @param state The new state for this tunnel. Must be {@code UP}, {@code DOWN}, or
- * {@code TOGGLE}.
- * @return The updated state of the tunnel.
+ * @return Type name
*/
- State setState(Tunnel tunnel, State state) throws Exception;
+ String getTypeName();
/**
* Determine version of underlying backend.
@@ -71,9 +68,12 @@ public interface Backend {
String getVersion() throws Exception;
/**
- * Determine type name of underlying backend.
+ * Set the state of a tunnel.
*
- * @return Type name
+ * @param tunnel The tunnel to control the state of.
+ * @param state The new state for this tunnel. Must be {@code UP}, {@code DOWN}, or
+ * {@code TOGGLE}.
+ * @return The updated state of the tunnel.
*/
- String getTypeName();
+ State setState(Tunnel tunnel, State state) throws Exception;
}
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 0d21c599..295df9d0 100644
--- a/app/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/app/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -60,12 +60,6 @@ public final class GoBackend implements Backend {
private static native String wgVersion();
@Override
- public String getVersion() { return wgVersion(); }
-
- @Override
- public String getTypeName() { return "Go userspace"; }
-
- @Override
public Config applyConfig(final Tunnel tunnel, final Config config) throws Exception {
if (tunnel.getState() == State.UP) {
// Restart the tunnel to apply the new config.
@@ -102,6 +96,16 @@ public final class GoBackend implements Backend {
}
@Override
+ public String getTypeName() {
+ return "Go userspace";
+ }
+
+ @Override
+ public String getVersion() {
+ return wgVersion();
+ }
+
+ @Override
public State setState(final Tunnel tunnel, State state) throws Exception {
final State originalState = getState(tunnel);
if (state == State.TOGGLE)
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 a4edfc27..bfc363a4 100644
--- a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
+++ b/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
@@ -41,18 +41,6 @@ public final class WgQuickBackend implements Backend {
}
@Override
- public String getVersion() throws Exception {
- final List<String> output = new ArrayList<>();
- if (Application.getRootShell()
- .run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty())
- throw new Exception("Unable to determine kernel module version");
- return output.get(0);
- }
-
- @Override
- public String getTypeName() { return "Kernel module"; }
-
- @Override
public Config applyConfig(final Tunnel tunnel, final Config config) throws Exception {
if (tunnel.getState() == State.UP) {
// Restart the tunnel to apply the new config.
@@ -95,6 +83,20 @@ public final class WgQuickBackend implements Backend {
}
@Override
+ public String getTypeName() {
+ return "Kernel module";
+ }
+
+ @Override
+ public String getVersion() throws Exception {
+ final List<String> output = new ArrayList<>();
+ if (Application.getRootShell()
+ .run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty())
+ throw new Exception("Unable to determine kernel module version");
+ return output.get(0);
+ }
+
+ @Override
public State setState(final Tunnel tunnel, State state) throws Exception {
final State originalState = getState(tunnel);
if (state == State.TOGGLE)
diff --git a/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java b/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java
index 0420dee0..26e7687f 100644
--- a/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java
+++ b/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java
@@ -40,11 +40,6 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
setList(list);
}
- @Override
- public int getItemCount() {
- return list != null ? list.size() : 0;
- }
-
@Nullable
private E getItem(final int position) {
if (list == null || position < 0 || position >= list.size())
@@ -53,6 +48,11 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
}
@Override
+ public int getItemCount() {
+ return list != null ? list.size() : 0;
+ }
+
+ @Override
public long getItemId(final int position) {
final K key = getKey(position);
return key != null ? key.hashCode() : -1;
@@ -64,11 +64,6 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
return item != null ? item.getKey() : null;
}
- @Override
- public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
- return new ViewHolder(DataBindingUtil.inflate(layoutInflater, layoutId, parent, false));
- }
-
@SuppressWarnings("unchecked")
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
@@ -85,6 +80,11 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
}
}
+ @Override
+ public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
+ return new ViewHolder(DataBindingUtil.inflate(layoutInflater, layoutId, parent, false));
+ }
+
void setList(@Nullable final ObservableKeyedList<K, E> newList) {
if (list != null)
list.removeOnListChangedCallback(callback);
@@ -99,6 +99,10 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
this.rowConfigurationHandler = rowConfigurationHandler;
}
+ public interface RowConfigurationHandler<B extends ViewDataBinding, T> {
+ void onConfigureRow(B binding, T item, int position);
+ }
+
private static final class OnListChangedCallback<E extends Keyed<?>>
extends ObservableList.OnListChangedCallback<ObservableList<E>> {
@@ -152,8 +156,4 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
}
}
- public interface RowConfigurationHandler<B extends ViewDataBinding, T> {
- void onConfigureRow(B binding, T item, int position);
- }
-
}
diff --git a/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java b/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java
index 8bc44ddf..8bf5a22d 100644
--- a/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java
@@ -34,9 +34,8 @@ import java.util.List;
public class AppListDialogFragment extends DialogFragment {
private static final String KEY_EXCLUDED_APPS = "excludedApps";
-
- private List<String> currentlyExcludedApps;
private final ObservableKeyedList<String, ApplicationData> appData = new ObservableKeyedArrayList<>();
+ private List<String> currentlyExcludedApps;
public static <T extends Fragment & AppExclusionListener> AppListDialogFragment newInstance(final String[] excludedApps, final T target) {
final Bundle extras = new Bundle();
@@ -47,39 +46,6 @@ public class AppListDialogFragment extends DialogFragment {
return fragment;
}
- @Override
- public void onCreate(@Nullable final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
- }
-
- @Override
- public Dialog onCreateDialog(final Bundle savedInstanceState) {
- final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
- alertDialogBuilder.setTitle(R.string.excluded_applications);
-
- final AppListDialogFragmentBinding binding = AppListDialogFragmentBinding.inflate(getActivity().getLayoutInflater(), null, false);
- binding.executePendingBindings();
- alertDialogBuilder.setView(binding.getRoot());
-
- alertDialogBuilder.setPositiveButton(R.string.set_exclusions, (dialog, which) -> setExclusionsAndDismiss());
- alertDialogBuilder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
- alertDialogBuilder.setNeutralButton(R.string.deselect_all, (dialog, which) -> { });
-
- binding.setFragment(this);
- binding.setAppData(appData);
-
- loadData();
-
- final AlertDialog dialog = alertDialogBuilder.create();
- dialog.setOnShowListener(d -> dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(view -> {
- for (final ApplicationData app : appData)
- app.setExcludedFromTunnel(false);
- }));
- return dialog;
- }
-
private void loadData() {
final Activity activity = getActivity();
if (activity == null) {
@@ -113,6 +79,40 @@ public class AppListDialogFragment extends DialogFragment {
}));
}
+ @Override
+ public void onCreate(@Nullable final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
+ }
+
+ @Override
+ public Dialog onCreateDialog(final Bundle savedInstanceState) {
+ final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
+ alertDialogBuilder.setTitle(R.string.excluded_applications);
+
+ final AppListDialogFragmentBinding binding = AppListDialogFragmentBinding.inflate(getActivity().getLayoutInflater(), null, false);
+ binding.executePendingBindings();
+ alertDialogBuilder.setView(binding.getRoot());
+
+ alertDialogBuilder.setPositiveButton(R.string.set_exclusions, (dialog, which) -> setExclusionsAndDismiss());
+ alertDialogBuilder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
+ alertDialogBuilder.setNeutralButton(R.string.deselect_all, (dialog, which) -> {
+ });
+
+ binding.setFragment(this);
+ binding.setAppData(appData);
+
+ loadData();
+
+ final AlertDialog dialog = alertDialogBuilder.create();
+ dialog.setOnShowListener(d -> dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(view -> {
+ for (final ApplicationData app : appData)
+ app.setExcludedFromTunnel(false);
+ }));
+ return dialog;
+ }
+
void setExclusionsAndDismiss() {
final List<String> excludedApps = new ArrayList<>();
for (final ApplicationData data : appData) {
diff --git a/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java b/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java
index ca1b9922..e3003f2e 100644
--- a/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java
@@ -33,9 +33,8 @@ import com.wireguard.android.util.ExceptionLoggers;
*/
public abstract class BaseFragment extends Fragment implements OnSelectedTunnelChangedListener {
- private static final String TAG = "WireGuard/" + BaseFragment.class.getSimpleName();
private static final int REQUEST_CODE_VPN_PERMISSION = 23491;
-
+ private static final String TAG = "WireGuard/" + BaseFragment.class.getSimpleName();
@Nullable private BaseActivity activity;
@Nullable private Tunnel pendingTunnel;
@Nullable private Boolean pendingTunnelUp;
@@ -46,6 +45,18 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
}
@Override
+ public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == REQUEST_CODE_VPN_PERMISSION) {
+ if (pendingTunnel != null && pendingTunnelUp != null)
+ setTunnelStateWithPermissionsResult(pendingTunnel, pendingTunnelUp);
+ pendingTunnel = null;
+ pendingTunnelUp = null;
+ }
+ }
+
+ @Override
public void onAttach(final Context context) {
super.onAttach(context);
if (context instanceof BaseActivity) {
@@ -64,18 +75,6 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
super.onDetach();
}
- @Override
- public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode == REQUEST_CODE_VPN_PERMISSION) {
- if (pendingTunnel != null && pendingTunnelUp != null)
- setTunnelStateWithPermissionsResult(pendingTunnel, pendingTunnelUp);
- pendingTunnel = null;
- pendingTunnelUp = null;
- }
- }
-
protected void setSelectedTunnel(@Nullable final Tunnel tunnel) {
if (activity != null)
activity.setSelectedTunnel(tunnel);
diff --git a/app/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.java b/app/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.java
index 3d2c6294..83799818 100644
--- a/app/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.java
@@ -13,7 +13,6 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
-import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import com.wireguard.android.Application;
@@ -27,9 +26,8 @@ import java.util.Objects;
public class ConfigNamingDialogFragment extends DialogFragment {
private static final String KEY_CONFIG_TEXT = "config_text";
-
- @Nullable private Config config;
@Nullable private ConfigNamingDialogFragmentBinding binding;
+ @Nullable private Config config;
@Nullable private InputMethodManager imm;
public static ConfigNamingDialogFragment newInstance(final String configText) {
@@ -40,6 +38,26 @@ public class ConfigNamingDialogFragment extends DialogFragment {
return fragment;
}
+ private void createTunnelAndDismiss() {
+ if (binding != null) {
+ final String name = binding.tunnelNameText.getText().toString();
+
+ Application.getTunnelManager().create(name, config).whenComplete((tunnel, throwable) -> {
+ if (tunnel != null) {
+ dismiss();
+ } else {
+ binding.tunnelNameTextLayout.setError(throwable.getMessage());
+ }
+ });
+ }
+ }
+
+ @Override
+ public void dismiss() {
+ setKeyboardVisible(false);
+ super.dismiss();
+ }
+
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -51,17 +69,6 @@ public class ConfigNamingDialogFragment extends DialogFragment {
}
}
- @Override public void onResume() {
- super.onResume();
-
- final AlertDialog dialog = (AlertDialog) getDialog();
- if (dialog != null) {
- dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> createTunnelAndDismiss());
-
- setKeyboardVisible(true);
- }
- }
-
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Activity activity = getActivity();
@@ -81,23 +88,14 @@ public class ConfigNamingDialogFragment extends DialogFragment {
return alertDialogBuilder.create();
}
- @Override
- public void dismiss() {
- setKeyboardVisible(false);
- super.dismiss();
- }
+ @Override public void onResume() {
+ super.onResume();
- private void createTunnelAndDismiss() {
- if (binding != null) {
- final String name = binding.tunnelNameText.getText().toString();
+ final AlertDialog dialog = (AlertDialog) getDialog();
+ if (dialog != null) {
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> createTunnelAndDismiss());
- Application.getTunnelManager().create(name, config).whenComplete((tunnel, throwable) -> {
- if (tunnel != null) {
- dismiss();
- } else {
- binding.tunnelNameTextLayout.setError(throwable.getMessage());
- }
- });
+ setKeyboardVisible(true);
}
}
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 b51feb37..8f319e1e 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
@@ -48,8 +48,59 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
private static final String KEY_LOCAL_CONFIG = "local_config";
private static final String KEY_ORIGINAL_NAME = "original_name";
private static final String TAG = "WireGuard/" + TunnelEditorFragment.class.getSimpleName();
-
+ private final Collection<Object> breakObjectOrientedLayeringHandlerReceivers = new ArrayList<>();
@Nullable private TunnelEditorFragmentBinding binding;
+ private final Observable.OnPropertyChangedCallback breakObjectOrientedLayeringHandler = new Observable.OnPropertyChangedCallback() {
+ @Override
+ public void onPropertyChanged(final Observable sender, final int propertyId) {
+ if (binding == null)
+ return;
+ final Config.Observable config = binding.getConfig();
+ if (config == null)
+ return;
+ if (propertyId == BR.config) {
+ config.addOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
+ breakObjectOrientedLayeringHandlerReceivers.add(config);
+ config.getInterfaceSection().addOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
+ breakObjectOrientedLayeringHandlerReceivers.add(config.getInterfaceSection());
+ config.getPeers().addOnListChangedCallback(breakObjectListOrientedLayeringHandler);
+ breakObjectOrientedLayeringHandlerReceivers.add(config.getPeers());
+ } else if (propertyId == BR.dnses || propertyId == BR.peers)
+ ;
+ else
+ return;
+ final int numSiblings = config.getPeers().size() - 1;
+ for (final Peer.Observable peer : config.getPeers()) {
+ peer.setInterfaceDNSRoutes(config.getInterfaceSection().getDnses());
+ peer.setNumSiblings(numSiblings);
+ }
+ }
+ };
+ private final ObservableList.OnListChangedCallback<? extends ObservableList<Peer.Observable>> breakObjectListOrientedLayeringHandler = new ObservableList.OnListChangedCallback<ObservableList<Peer.Observable>>() {
+ @Override
+ public void onChanged(final ObservableList<Peer.Observable> sender) {
+ }
+
+ @Override
+ public void onItemRangeChanged(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) {
+ }
+
+ @Override
+ public void onItemRangeInserted(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) {
+ if (binding != null)
+ breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
+ }
+
+ @Override
+ public void onItemRangeMoved(final ObservableList<Peer.Observable> sender, final int fromPosition, final int toPosition, final int itemCount) {
+ }
+
+ @Override
+ public void onItemRangeRemoved(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) {
+ if (binding != null)
+ breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
+ }
+ };
@Nullable private Tunnel tunnel;
private void onConfigLoaded(final String name, final Config config) {
@@ -87,54 +138,6 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
inflater.inflate(R.menu.config_editor, menu);
}
- private final ObservableList.OnListChangedCallback<? extends ObservableList<Peer.Observable>> breakObjectListOrientedLayeringHandler = new ObservableList.OnListChangedCallback<ObservableList<Peer.Observable>>() {
- @Override
- public void onChanged(final ObservableList<Peer.Observable> sender) { }
- @Override
- public void onItemRangeChanged(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) { }
- @Override
- public void onItemRangeMoved(final ObservableList<Peer.Observable> sender, final int fromPosition, final int toPosition, final int itemCount) { }
-
- @Override
- public void onItemRangeInserted(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) {
- if (binding != null)
- breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
- }
- @Override
- public void onItemRangeRemoved(final ObservableList<Peer.Observable> sender, final int positionStart, final int itemCount) {
- if (binding != null)
- breakObjectOrientedLayeringHandler.onPropertyChanged(binding.getConfig(), BR.peers);
- }
- };
-
- private final Collection<Object> breakObjectOrientedLayeringHandlerReceivers = new ArrayList<>();
- private final Observable.OnPropertyChangedCallback breakObjectOrientedLayeringHandler = new Observable.OnPropertyChangedCallback() {
- @Override
- public void onPropertyChanged(final Observable sender, final int propertyId) {
- if (binding == null)
- return;
- final Config.Observable config = binding.getConfig();
- if (config == null)
- return;
- if (propertyId == BR.config) {
- config.addOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
- breakObjectOrientedLayeringHandlerReceivers.add(config);
- config.getInterfaceSection().addOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
- breakObjectOrientedLayeringHandlerReceivers.add(config.getInterfaceSection());
- config.getPeers().addOnListChangedCallback(breakObjectListOrientedLayeringHandler);
- breakObjectOrientedLayeringHandlerReceivers.add(config.getPeers());
- } else if (propertyId == BR.dnses || propertyId == BR.peers)
- ;
- else
- return;
- final int numSiblings = config.getPeers().size() - 1;
- for (final Peer.Observable peer : config.getPeers()) {
- peer.setInterfaceDNSRoutes(config.getInterfaceSection().getDnses());
- peer.setNumSiblings(numSiblings);
- }
- }
- };
-
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
@@ -152,13 +155,19 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
binding = null;
for (final Object o : breakObjectOrientedLayeringHandlerReceivers) {
if (o instanceof Observable)
- ((Observable)o).removeOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
+ ((Observable) o).removeOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
else if (o instanceof ObservableList)
- ((ObservableList)o).removeOnListChangedCallback(breakObjectListOrientedLayeringHandler);
+ ((ObservableList) o).removeOnListChangedCallback(breakObjectListOrientedLayeringHandler);
}
super.onDestroyView();
}
+ @Override
+ public void onExcludedAppsSelected(final List<String> excludedApps) {
+ Objects.requireNonNull(binding, "Tried to set excluded apps while no view was loaded");
+ binding.getConfig().getInterfaceSection().setExcludedApplications(Attribute.iterableToString(excludedApps));
+ }
+
private void onFinished() {
// Hide the keyboard; it rarely goes away on its own.
final Activity activity = getActivity();
@@ -217,6 +226,15 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
}
}
+ public void onRequestSetExcludedApplications(@SuppressWarnings("unused") final View view) {
+ final FragmentManager fragmentManager = getFragmentManager();
+ if (fragmentManager != null && binding != null) {
+ final String[] excludedApps = Attribute.stringToList(binding.getConfig().getInterfaceSection().getExcludedApplications());
+ final AppListDialogFragment fragment = AppListDialogFragment.newInstance(excludedApps, this);
+ fragment.show(fragmentManager, null);
+ }
+ }
+
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(KEY_LOCAL_CONFIG, binding.getConfig());
@@ -294,19 +312,4 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
super.onViewStateRestored(savedInstanceState);
}
- public void onRequestSetExcludedApplications(@SuppressWarnings("unused") final View view) {
- final FragmentManager fragmentManager = getFragmentManager();
- if (fragmentManager != null && binding != null) {
- final String[] excludedApps = Attribute.stringToList(binding.getConfig().getInterfaceSection().getExcludedApplications());
- final AppListDialogFragment fragment = AppListDialogFragment.newInstance(excludedApps, this);
- fragment.show(fragmentManager, null);
- }
- }
-
- @Override
- public void onExcludedAppsSelected(final List<String> excludedApps) {
- Objects.requireNonNull(binding, "Tried to set excluded apps while no view was loaded");
- binding.getConfig().getInterfaceSection().setExcludedApplications(Attribute.iterableToString(excludedApps));
- }
-
}
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 80895041..7509e40c 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
@@ -38,13 +38,11 @@ import com.wireguard.android.databinding.TunnelListFragmentBinding;
import com.wireguard.android.databinding.TunnelListItemBinding;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.util.ExceptionLoggers;
-import com.wireguard.android.util.ObservableSortedKeyedList;
import com.wireguard.android.widget.MultiselectableRelativeLayout;
import com.wireguard.android.widget.fab.FloatingActionsMenuRecyclerViewScrollListener;
import com.wireguard.config.Config;
import java.io.BufferedReader;
-import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -186,6 +184,19 @@ public class TunnelListFragment extends BaseFragment {
}
@Override
+ public void onActivityCreated(@Nullable final Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ final Collection<Integer> checkedItems = savedInstanceState.getIntegerArrayList("CHECKED_ITEMS");
+ if (checkedItems != null) {
+ for (final Integer i : checkedItems)
+ actionModeListener.setItemChecked(i, true);
+ }
+ }
+ }
+
+ @Override
public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
switch (requestCode) {
case REQUEST_IMPORT:
@@ -228,6 +239,14 @@ public class TunnelListFragment extends BaseFragment {
super.onDestroyView();
}
+ @Override
+ public void onPause() {
+ if (binding != null) {
+ binding.createMenu.collapse();
+ }
+ super.onPause();
+ }
+
public void onRequestCreateConfig(@SuppressWarnings("unused") final View view) {
startActivity(new Intent(getActivity(), TunnelCreatorActivity.class));
if (binding != null)
@@ -255,15 +274,10 @@ public class TunnelListFragment extends BaseFragment {
}
@Override
- public void onPause() {
- if (binding != null) {
- binding.createMenu.collapse();
- }
- super.onPause();
- }
+ public void onSaveInstanceState(final Bundle outState) {
+ super.onSaveInstanceState(outState);
- private MultiselectableRelativeLayout viewForTunnel(final Tunnel tunnel, final List tunnels) {
- return (MultiselectableRelativeLayout)binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(tunnel)).itemView;
+ outState.putIntegerArrayList("CHECKED_ITEMS", actionModeListener.getCheckedItems());
}
@Override
@@ -318,26 +332,6 @@ public class TunnelListFragment extends BaseFragment {
}
@Override
- public void onSaveInstanceState(final Bundle outState) {
- super.onSaveInstanceState(outState);
-
- outState.putIntegerArrayList("CHECKED_ITEMS", actionModeListener.getCheckedItems());
- }
-
- @Override
- public void onActivityCreated(@Nullable final Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- if (savedInstanceState != null) {
- final Collection<Integer> checkedItems = savedInstanceState.getIntegerArrayList("CHECKED_ITEMS");
- if (checkedItems != null) {
- for (final Integer i : checkedItems)
- actionModeListener.setItemChecked(i, true);
- }
- }
- }
-
- @Override
public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
@@ -362,17 +356,25 @@ public class TunnelListFragment extends BaseFragment {
});
if (actionMode != null)
- ((MultiselectableRelativeLayout)binding.getRoot()).setMultiSelected(actionModeListener.checkedItems.contains(position));
+ ((MultiselectableRelativeLayout) binding.getRoot()).setMultiSelected(actionModeListener.checkedItems.contains(position));
else
- ((MultiselectableRelativeLayout)binding.getRoot()).setSingleSelected(getSelectedTunnel() == tunnel);
+ ((MultiselectableRelativeLayout) binding.getRoot()).setSingleSelected(getSelectedTunnel() == tunnel);
});
}
+ private MultiselectableRelativeLayout viewForTunnel(final Tunnel tunnel, final List tunnels) {
+ return (MultiselectableRelativeLayout) binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(tunnel)).itemView;
+ }
+
private final class ActionModeListener implements ActionMode.Callback {
private final Collection<Integer> checkedItems = new HashSet<>();
@Nullable private Resources resources;
+ public ArrayList<Integer> getCheckedItems() {
+ return new ArrayList<>(checkedItems);
+ }
+
@Override
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
switch (item.getItemId()) {
@@ -425,12 +427,10 @@ public class TunnelListFragment extends BaseFragment {
binding.tunnelList.getAdapter().notifyDataSetChanged();
}
- void toggleItemChecked(final int position) {
- setItemChecked(position, !checkedItems.contains(position));
- }
-
- public ArrayList<Integer> getCheckedItems() {
- return new ArrayList<>(checkedItems);
+ @Override
+ public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
+ updateTitle(mode);
+ return false;
}
void setItemChecked(final int position, final boolean checked) {
@@ -454,10 +454,8 @@ public class TunnelListFragment extends BaseFragment {
updateTitle(actionMode);
}
- @Override
- public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
- updateTitle(mode);
- return false;
+ void toggleItemChecked(final int position) {
+ setItemChecked(position, !checkedItems.contains(position));
}
private void updateTitle(@Nullable final ActionMode mode) {
diff --git a/app/src/main/java/com/wireguard/android/model/ApplicationData.java b/app/src/main/java/com/wireguard/android/model/ApplicationData.java
index 15e2d5c3..efe1ef87 100644
--- a/app/src/main/java/com/wireguard/android/model/ApplicationData.java
+++ b/app/src/main/java/com/wireguard/android/model/ApplicationData.java
@@ -30,6 +30,11 @@ public class ApplicationData extends BaseObservable implements Keyed<String> {
return icon;
}
+ @Override
+ public String getKey() {
+ return name;
+ }
+
public String getName() {
return name;
}
@@ -47,9 +52,4 @@ public class ApplicationData extends BaseObservable implements Keyed<String> {
this.excludedFromTunnel = excludedFromTunnel;
notifyPropertyChanged(BR.excludedFromTunnel);
}
-
- @Override
- public String getKey() {
- return name;
- }
}
diff --git a/app/src/main/java/com/wireguard/android/model/Tunnel.java b/app/src/main/java/com/wireguard/android/model/Tunnel.java
index 7eeb2d9e..6d37e009 100644
--- a/app/src/main/java/com/wireguard/android/model/Tunnel.java
+++ b/app/src/main/java/com/wireguard/android/model/Tunnel.java
@@ -151,5 +151,6 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
}
}
- public static class Statistics extends BaseObservable { }
+ public static class Statistics extends BaseObservable {
+ }
}
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 c6bc5e75..3fd7bfc0 100644
--- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java
+++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
@@ -44,19 +44,28 @@ public final class TunnelManager extends BaseObservable {
private static final String KEY_LAST_USED_TUNNEL = "last_used_tunnel";
private static final String KEY_RESTORE_ON_BOOT = "restore_on_boot";
private static final String KEY_RUNNING_TUNNELS = "enabled_configs";
-
+ private final CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> completableTunnels = new CompletableFuture<>();
private final ConfigStore configStore;
private final Context context = Application.get();
- private final CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> completableTunnels = new CompletableFuture<>();
+ private final ArrayList<CompletableFuture<Void>> delayedLoadRestoreTunnels = new ArrayList<>();
private final ObservableSortedKeyedList<String, Tunnel> tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR);
- @Nullable private Tunnel lastUsedTunnel;
private boolean haveLoaded;
- private final ArrayList<CompletableFuture<Void>> delayedLoadRestoreTunnels = new ArrayList<>();
+ @Nullable private Tunnel lastUsedTunnel;
public TunnelManager(final ConfigStore configStore) {
this.configStore = configStore;
}
+ static CompletionStage<State> getTunnelState(final Tunnel tunnel) {
+ return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getState(tunnel))
+ .thenApply(tunnel::onStateChanged);
+ }
+
+ static CompletionStage<Statistics> getTunnelStatistics(final Tunnel tunnel) {
+ return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getStatistics(tunnel))
+ .thenApply(tunnel::onStatisticsChanged);
+ }
+
private Tunnel addToList(final String name, @Nullable final Config config, final State state) {
final Tunnel tunnel = new Tunnel(this, name, config, state);
tunnels.add(tunnel);
@@ -112,16 +121,6 @@ public final class TunnelManager extends BaseObservable {
.thenApply(tunnel::onConfigChanged);
}
- static CompletionStage<State> getTunnelState(final Tunnel tunnel) {
- return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getState(tunnel))
- .thenApply(tunnel::onStateChanged);
- }
-
- static CompletionStage<Statistics> getTunnelStatistics(final Tunnel tunnel) {
- return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getStatistics(tunnel))
- .thenApply(tunnel::onStatisticsChanged);
- }
-
public CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> getTunnels() {
return completableTunnels;
}
diff --git a/app/src/main/java/com/wireguard/android/preference/VersionPreference.java b/app/src/main/java/com/wireguard/android/preference/VersionPreference.java
index 7f39b1eb..228facc7 100644
--- a/app/src/main/java/com/wireguard/android/preference/VersionPreference.java
+++ b/app/src/main/java/com/wireguard/android/preference/VersionPreference.java
@@ -50,7 +50,8 @@ public class VersionPreference extends Preference {
intent.setData(Uri.parse("https://www.wireguard.com/"));
try {
getContext().startActivity(intent);
- } catch (final ActivityNotFoundException ignored) { }
+ } catch (final ActivityNotFoundException ignored) {
+ }
}
}
diff --git a/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java b/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java
index 6270d0fe..d6032a18 100644
--- a/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java
+++ b/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java
@@ -19,7 +19,8 @@ import java.util.zip.ZipFile;
public final class SharedLibraryLoader {
private static final String TAG = "WireGuard/" + SharedLibraryLoader.class.getSimpleName();
- private SharedLibraryLoader() { }
+ private SharedLibraryLoader() {
+ }
public static void loadSharedLibrary(final Context context, final String libName) {
Throwable noAbiException;
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 5a667baa..143a8724 100644
--- a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java
+++ b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java
@@ -26,11 +26,10 @@ import java.util.List;
public final class ToolsInstaller {
public static final int ERROR = 0x0;
- public static final int YES = 0x1;
- public static final int NO = 0x2;
public static final int MAGISK = 0x4;
+ public static final int NO = 0x2;
public static final int SYSTEM = 0x8;
-
+ public static final int YES = 0x1;
private static final String[][] EXECUTABLES = {
{"libwg.so", "wg"},
{"libwg-quick.so", "wg-quick"},
@@ -107,34 +106,8 @@ public final class ToolsInstaller {
}
}
- private boolean willInstallAsMagiskModule() {
- synchronized (lock) {
- if (installAsMagiskModule == null) {
- try {
- installAsMagiskModule = Application.getRootShell().run(null, "[ -d /sbin/.core/mirror -a -d /sbin/.core/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
- } catch (final Exception ignored) {
- installAsMagiskModule = false;
- }
- }
- return installAsMagiskModule;
- }
- }
-
- private int installSystem() throws NoRootException {
- if (INSTALL_DIR == null)
- return OsConstants.ENOENT;
- final StringBuilder script = new StringBuilder("set -ex; ");
- script.append("trap 'mount -o ro,remount /system' EXIT; mount -o rw,remount /system; ");
- for (final String[] names : EXECUTABLES) {
- final File destination = new File(INSTALL_DIR, names[1]);
- script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; restorecon '%s' || true; ",
- new File(nativeLibraryDir, names[0]), destination, destination, destination));
- }
- try {
- return Application.getRootShell().run(null, script.toString()) == 0 ? YES | SYSTEM : ERROR;
- } catch (final IOException ignored) {
- return ERROR;
- }
+ public int install() throws NoRootException {
+ return willInstallAsMagiskModule() ? installMagisk() : installSystem();
}
private int installMagisk() throws NoRootException {
@@ -158,8 +131,21 @@ public final class ToolsInstaller {
}
}
- public int install() throws NoRootException {
- return willInstallAsMagiskModule() ? installMagisk() : installSystem();
+ private int installSystem() throws NoRootException {
+ if (INSTALL_DIR == null)
+ return OsConstants.ENOENT;
+ final StringBuilder script = new StringBuilder("set -ex; ");
+ script.append("trap 'mount -o ro,remount /system' EXIT; mount -o rw,remount /system; ");
+ for (final String[] names : EXECUTABLES) {
+ final File destination = new File(INSTALL_DIR, names[1]);
+ script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; restorecon '%s' || true; ",
+ new File(nativeLibraryDir, names[0]), destination, destination, destination));
+ }
+ try {
+ return Application.getRootShell().run(null, script.toString()) == 0 ? YES | SYSTEM : ERROR;
+ } catch (final IOException ignored) {
+ return ERROR;
+ }
}
public int symlink() throws NoRootException {
@@ -184,4 +170,17 @@ public final class ToolsInstaller {
return OsConstants.EXIT_FAILURE;
}
}
+
+ private boolean willInstallAsMagiskModule() {
+ synchronized (lock) {
+ if (installAsMagiskModule == null) {
+ try {
+ installAsMagiskModule = Application.getRootShell().run(null, "[ -d /sbin/.core/mirror -a -d /sbin/.core/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
+ } catch (final Exception ignored) {
+ installAsMagiskModule = false;
+ }
+ }
+ return installAsMagiskModule;
+ }
+ }
}
diff --git a/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java b/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java
index 8fa4f9ae..0759903b 100644
--- a/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java
+++ b/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java
@@ -12,23 +12,25 @@ import android.widget.RelativeLayout;
import com.wireguard.android.R;
public class MultiselectableRelativeLayout extends RelativeLayout {
+ private static final int[] STATE_MULTISELECTED = {R.attr.state_multiselected};
+ private boolean multiselected;
+
public MultiselectableRelativeLayout(final Context context) {
super(context);
}
+
public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
+
public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
+
public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
- private static final int[] STATE_MULTISELECTED = { R.attr.state_multiselected };
-
- private boolean multiselected;
-
@Override
protected int[] onCreateDrawableState(final int extraSpace) {
if (multiselected) {
diff --git a/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java b/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java
index d4d3d8cc..408d7888 100644
--- a/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java
+++ b/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java
@@ -31,95 +31,43 @@ import android.util.FloatProperty;
@TargetApi(Build.VERSION_CODES.N)
public class SlashDrawable extends Drawable {
+ private static final float CENTER_X = 10.65f;
+ private static final float CENTER_Y = 11.869239f;
private static final float CORNER_RADIUS = Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0f : 1f;
+ // Draw the slash washington-monument style; rotate to no-u-turn style
+ private static final float DEFAULT_ROTATION = -45f;
private static final long QS_ANIM_LENGTH = 350;
-
- private final Path mPath = new Path();
- private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
+ private static final float SCALE = 24f;
+ private static final float SLASH_HEIGHT = 28f;
// These values are derived in un-rotated (vertical) orientation
private static final float SLASH_WIDTH = 1.8384776f;
- private static final float SLASH_HEIGHT = 28f;
- private static final float CENTER_X = 10.65f;
- private static final float CENTER_Y = 11.869239f;
- private static final float SCALE = 24f;
-
// Bottom is derived during animation
private static final float LEFT = (CENTER_X - (SLASH_WIDTH / 2)) / SCALE;
- private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE;
private static final float RIGHT = (CENTER_X + (SLASH_WIDTH / 2)) / SCALE;
- // Draw the slash washington-monument style; rotate to no-u-turn style
- private static final float DEFAULT_ROTATION = -45f;
-
- private final Drawable mDrawable;
- private final RectF mSlashRect = new RectF(0, 0, 0, 0);
- private float mRotation;
- private boolean mSlashed;
- private boolean mAnimationEnabled = true;
-
- public SlashDrawable(final Drawable d) {
- mDrawable = d;
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mDrawable.getIntrinsicHeight();
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mDrawable.getIntrinsicWidth();
- }
-
- @Override
- protected void onBoundsChange(final Rect bounds) {
- super.onBoundsChange(bounds);
- mDrawable.setBounds(bounds);
- }
-
- public void setRotation(final float rotation) {
- if (mRotation == rotation)
- return;
- mRotation = rotation;
- invalidateSelf();
- }
-
- public void setAnimationEnabled(final boolean enabled) {
- mAnimationEnabled = enabled;
- }
-
- // Animate this value on change
- private float mCurrentSlashLength;
+ private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE;
private static final FloatProperty mSlashLengthProp = new FloatProperty<SlashDrawable>("slashLength") {
@Override
- public void setValue(final SlashDrawable object, final float value) {
- object.mCurrentSlashLength = value;
+ public Float get(final SlashDrawable object) {
+ return object.mCurrentSlashLength;
}
@Override
- public Float get(final SlashDrawable object) {
- return object.mCurrentSlashLength;
+ public void setValue(final SlashDrawable object, final float value) {
+ object.mCurrentSlashLength = value;
}
};
+ private final Drawable mDrawable;
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Path mPath = new Path();
+ private final RectF mSlashRect = new RectF(0, 0, 0, 0);
+ private boolean mAnimationEnabled = true;
+ // Animate this value on change
+ private float mCurrentSlashLength;
+ private float mRotation;
+ private boolean mSlashed;
- @SuppressWarnings("unchecked")
- public void setSlashed(final boolean slashed) {
- if (mSlashed == slashed) return;
-
- mSlashed = slashed;
-
- final float end = mSlashed ? SLASH_HEIGHT / SCALE : 0f;
- final float start = mSlashed ? 0f : SLASH_HEIGHT / SCALE;
-
- if (mAnimationEnabled) {
- final ObjectAnimator anim = ObjectAnimator.ofFloat(this, mSlashLengthProp, start, end);
- anim.addUpdateListener((ValueAnimator valueAnimator) -> invalidateSelf());
- anim.setDuration(QS_ANIM_LENGTH);
- anim.start();
- } else {
- mCurrentSlashLength = end;
- invalidateSelf();
- }
+ public SlashDrawable(final Drawable d) {
+ mDrawable = d;
}
@SuppressWarnings("deprecation")
@@ -166,15 +114,76 @@ public class SlashDrawable extends Drawable {
canvas.restore();
}
+ @Override
+ public int getIntrinsicHeight() {
+ return mDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+
+ @Override
+ protected void onBoundsChange(final Rect bounds) {
+ super.onBoundsChange(bounds);
+ mDrawable.setBounds(bounds);
+ }
+
private float scale(final float frac, final int width) {
return frac * width;
}
- private void updateRect(final float left, final float top, final float right, final float bottom) {
- mSlashRect.left = left;
- mSlashRect.top = top;
- mSlashRect.right = right;
- mSlashRect.bottom = bottom;
+ @Override
+ public void setAlpha(@IntRange(from = 0, to = 255) final int alpha) {
+ mDrawable.setAlpha(alpha);
+ mPaint.setAlpha(alpha);
+ }
+
+ public void setAnimationEnabled(final boolean enabled) {
+ mAnimationEnabled = enabled;
+ }
+
+ @Override
+ public void setColorFilter(@Nullable final ColorFilter colorFilter) {
+ mDrawable.setColorFilter(colorFilter);
+ mPaint.setColorFilter(colorFilter);
+ }
+
+ private void setDrawableTintList(@Nullable final ColorStateList tint) {
+ mDrawable.setTintList(tint);
+ }
+
+ public void setRotation(final float rotation) {
+ if (mRotation == rotation)
+ return;
+ mRotation = rotation;
+ invalidateSelf();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void setSlashed(final boolean slashed) {
+ if (mSlashed == slashed) return;
+
+ mSlashed = slashed;
+
+ final float end = mSlashed ? SLASH_HEIGHT / SCALE : 0f;
+ final float start = mSlashed ? 0f : SLASH_HEIGHT / SCALE;
+
+ if (mAnimationEnabled) {
+ final ObjectAnimator anim = ObjectAnimator.ofFloat(this, mSlashLengthProp, start, end);
+ anim.addUpdateListener((ValueAnimator valueAnimator) -> invalidateSelf());
+ anim.setDuration(QS_ANIM_LENGTH);
+ anim.start();
+ } else {
+ mCurrentSlashLength = end;
+ invalidateSelf();
+ }
}
@Override
@@ -192,30 +201,16 @@ public class SlashDrawable extends Drawable {
invalidateSelf();
}
- private void setDrawableTintList(@Nullable final ColorStateList tint) {
- mDrawable.setTintList(tint);
- }
-
@Override
public void setTintMode(final Mode tintMode) {
super.setTintMode(tintMode);
mDrawable.setTintMode(tintMode);
}
- @Override
- public void setAlpha(@IntRange(from = 0, to = 255) final int alpha) {
- mDrawable.setAlpha(alpha);
- mPaint.setAlpha(alpha);
- }
-
- @Override
- public void setColorFilter(@Nullable final ColorFilter colorFilter) {
- mDrawable.setColorFilter(colorFilter);
- mPaint.setColorFilter(colorFilter);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.OPAQUE;
+ private void updateRect(final float left, final float top, final float right, final float bottom) {
+ mSlashRect.left = left;
+ mSlashRect.top = top;
+ mSlashRect.right = right;
+ mSlashRect.bottom = bottom;
}
}
diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java
index 54679046..3741c29e 100644
--- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java
+++ b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java
@@ -18,19 +18,13 @@ import android.view.View;
public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionsMenu> {
+ private static final long ANIMATION_DURATION = 250;
+ private static final TimeInterpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
+
public FloatingActionButtonBehavior(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- @Override
- public boolean layoutDependsOn(final CoordinatorLayout parent, final FloatingActionsMenu child,
- final View dependency) {
- return dependency instanceof Snackbar.SnackbarLayout;
- }
-
- private static final long ANIMATION_DURATION = 250;
- private static final TimeInterpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
-
private static void animateChange(final FloatingActionsMenu child, final float destination, final float fullSpan) {
final float origin = child.getBehaviorYTranslation();
if (Math.abs(destination - origin) < fullSpan / 2) {
@@ -40,18 +34,24 @@ public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<Flo
final ValueAnimator animator = new ValueAnimator();
animator.setFloatValues(origin, destination);
animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
- animator.setDuration((long)(ANIMATION_DURATION * (Math.abs(destination - origin) / fullSpan)));
+ animator.setDuration((long) (ANIMATION_DURATION * (Math.abs(destination - origin) / fullSpan)));
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator a) {
child.setBehaviorYTranslation(destination);
}
});
- animator.addUpdateListener(a -> child.setBehaviorYTranslation((float)a.getAnimatedValue()));
+ animator.addUpdateListener(a -> child.setBehaviorYTranslation((float) a.getAnimatedValue()));
animator.start();
}
@Override
+ public boolean layoutDependsOn(final CoordinatorLayout parent, final FloatingActionsMenu child,
+ final View dependency) {
+ return dependency instanceof Snackbar.SnackbarLayout;
+ }
+
+ @Override
public boolean onDependentViewChanged(final CoordinatorLayout parent, final FloatingActionsMenu child,
final View dependency) {
animateChange(child, Math.min(0, dependency.getTranslationY() - dependency.getMeasuredHeight()), dependency.getMeasuredHeight());
diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java
index 8a5a193b..ed838914 100644
--- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java
+++ b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java
@@ -37,39 +37,38 @@ import android.widget.TextView;
import com.wireguard.android.R;
public class FloatingActionsMenu extends ViewGroup {
- public static final int EXPAND_UP = 0;
public static final int EXPAND_DOWN = 1;
public static final int EXPAND_LEFT = 2;
public static final int EXPAND_RIGHT = 3;
-
+ public static final int EXPAND_UP = 0;
public static final int LABELS_ON_LEFT_SIDE = 0;
public static final int LABELS_ON_RIGHT_SIDE = 1;
-
+ private static final TimeInterpolator ALPHA_EXPAND_INTERPOLATOR = new DecelerateInterpolator();
private static final int ANIMATION_DURATION = 300;
+ private static final boolean BROKEN_LABEL_STYLE = Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.BRAND.equals("ASUS");
private static final float COLLAPSED_PLUS_ROTATION = 0f;
+ private static final TimeInterpolator COLLAPSE_INTERPOLATOR = new DecelerateInterpolator(3f);
private static final float EXPANDED_PLUS_ROTATION = 90f + 45f;
private static final TimeInterpolator EXPAND_INTERPOLATOR = new OvershootInterpolator();
- private static final TimeInterpolator COLLAPSE_INTERPOLATOR = new DecelerateInterpolator(3f);
- private static final TimeInterpolator ALPHA_EXPAND_INTERPOLATOR = new DecelerateInterpolator();
- private int mExpandDirection;
+ private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
+ private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
+ private final Rect touchArea = new Rect(0, 0, 0, 0);
+ private float behaviorYTranslation;
+ @Nullable private FloatingActionButton mAddButton;
private int mButtonSpacing;
+ private int mButtonsCount;
+ private int mExpandDirection;
+ private boolean mExpanded;
private int mLabelsMargin;
+ private int mLabelsPosition;
+ private int mLabelsStyle;
private int mLabelsVerticalOffset;
- private boolean mExpanded;
- private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
- private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
- @Nullable private FloatingActionButton mAddButton;
- @Nullable private RotatingDrawable mRotatingDrawable;
- private int mMaxButtonWidth;
+ @Nullable private OnFloatingActionsMenuUpdateListener mListener;
private int mMaxButtonHeight;
- private int mLabelsStyle;
- private int mLabelsPosition;
- private int mButtonsCount;
+ private int mMaxButtonWidth;
+ @Nullable private RotatingDrawable mRotatingDrawable;
@Nullable private TouchDelegateGroup mTouchDelegateGroup;
- @Nullable private OnFloatingActionsMenuUpdateListener mListener;
- private final Rect touchArea = new Rect(0, 0, 0, 0);
private float scrollYTranslation;
- private float behaviorYTranslation;
public FloatingActionsMenu(final Context context) {
this(context, null);
@@ -85,51 +84,39 @@ public class FloatingActionsMenu extends ViewGroup {
init(context, attrs);
}
- private void init(final Context context, @Nullable final AttributeSet attributeSet) {
- mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing));
- mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin);
- mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);
-
- mTouchDelegateGroup = new TouchDelegateGroup(this);
- setTouchDelegate(mTouchDelegateGroup);
-
- final TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0);
- mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP);
- mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0);
- mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE);
- attr.recycle();
-
- if (mLabelsStyle != 0 && expandsHorizontally()) {
- throw new IllegalStateException("Action labels in horizontal expand orientation is not supported.");
- }
-
- createAddButton(context);
+ private static int adjustForOvershoot(final int dimension) {
+ return dimension * 12 / 10;
}
- public float getScrollYTranslation() {
- return scrollYTranslation;
- }
+ public void addButton(final LabeledFloatingActionButton button) {
+ addView(button, mButtonsCount - 1);
+ mButtonsCount++;
- public void setScrollYTranslation(final float scrollYTranslation) {
- this.scrollYTranslation = scrollYTranslation;
- setTranslationY(behaviorYTranslation + scrollYTranslation);
+ if (mLabelsStyle != 0) {
+ createLabels();
+ }
}
- public float getBehaviorYTranslation() {
- return behaviorYTranslation;
+ public void collapse() {
+ collapse(false);
}
- public void setBehaviorYTranslation(final float behaviorYTranslation) {
- this.behaviorYTranslation = behaviorYTranslation;
- setTranslationY(behaviorYTranslation + scrollYTranslation);
- }
+ private void collapse(final boolean immediately) {
+ if (mExpanded) {
+ mExpanded = false;
+ mTouchDelegateGroup.setEnabled(false);
+ mCollapseAnimation.setDuration(immediately ? 0 : ANIMATION_DURATION);
+ mCollapseAnimation.start();
+ mExpandAnimation.cancel();
- public void setOnFloatingActionsMenuUpdateListener(final OnFloatingActionsMenuUpdateListener listener) {
- mListener = listener;
+ if (mListener != null) {
+ mListener.onMenuCollapsed();
+ }
+ }
}
- private boolean expandsHorizontally() {
- return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT;
+ public void collapseImmediately() {
+ collapse(true);
}
private void createAddButton(final Context context) {
@@ -156,85 +143,101 @@ public class FloatingActionsMenu extends ViewGroup {
mButtonsCount++;
}
- public void addButton(final LabeledFloatingActionButton button) {
- addView(button, mButtonsCount - 1);
- mButtonsCount++;
+ private void createLabels() {
+ final Context context = BROKEN_LABEL_STYLE ? getContext() : new ContextThemeWrapper(getContext(), mLabelsStyle);
- if (mLabelsStyle != 0) {
- createLabels();
+ for (int i = 0; i < mButtonsCount; i++) {
+ final FloatingActionButton button = (FloatingActionButton) getChildAt(i);
+
+ if (button instanceof LabeledFloatingActionButton) {
+ final String title = ((LabeledFloatingActionButton) button).getTitle();
+
+ final AppCompatTextView label = new AppCompatTextView(context);
+ if (!BROKEN_LABEL_STYLE)
+ label.setTextAppearance(context, mLabelsStyle);
+ label.setText(title);
+ addView(label);
+
+ button.setTag(R.id.fab_label, label);
+ }
}
}
- public void removeButton(final LabeledFloatingActionButton button) {
- removeView(button.getLabelView());
- removeView(button);
- button.setTag(R.id.fab_label, null);
- mButtonsCount--;
+ public void expand() {
+ if (!mExpanded) {
+ mExpanded = true;
+ mTouchDelegateGroup.setEnabled(true);
+ mCollapseAnimation.cancel();
+ mExpandAnimation.start();
+
+ if (mListener != null) {
+ mListener.onMenuExpanded();
+ }
+ }
+ }
+
+ private boolean expandsHorizontally() {
+ return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT;
}
@Override
- protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
- measureChildren(widthMeasureSpec, heightMeasureSpec);
+ protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+ return new LayoutParams(super.generateDefaultLayoutParams());
+ }
- int width = 0;
- int height = 0;
+ @Override
+ public ViewGroup.LayoutParams generateLayoutParams(final AttributeSet attrs) {
+ return new LayoutParams(super.generateLayoutParams(attrs));
+ }
- mMaxButtonWidth = 0;
- mMaxButtonHeight = 0;
- int maxLabelWidth = 0;
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(final ViewGroup.LayoutParams p) {
+ return new LayoutParams(super.generateLayoutParams(p));
+ }
- for (int i = 0; i < mButtonsCount; i++) {
- final View child = getChildAt(i);
+ public float getBehaviorYTranslation() {
+ return behaviorYTranslation;
+ }
- if (child.getVisibility() == GONE) {
- continue;
- }
+ public float getScrollYTranslation() {
+ return scrollYTranslation;
+ }
- switch (mExpandDirection) {
- case EXPAND_UP:
- case EXPAND_DOWN:
- mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());
- height += child.getMeasuredHeight();
- break;
- case EXPAND_LEFT:
- case EXPAND_RIGHT:
- width += child.getMeasuredWidth();
- mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight());
- break;
- }
+ private void init(final Context context, @Nullable final AttributeSet attributeSet) {
+ mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing));
+ mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin);
+ mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);
- if (!expandsHorizontally()) {
- final TextView label = (TextView) child.getTag(R.id.fab_label);
- if (label != null) {
- maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth());
- }
- }
- }
+ mTouchDelegateGroup = new TouchDelegateGroup(this);
+ setTouchDelegate(mTouchDelegateGroup);
- if (expandsHorizontally()) {
- height = mMaxButtonHeight;
- } else {
- width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0);
- }
+ final TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0);
+ mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP);
+ mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0);
+ mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE);
+ attr.recycle();
- switch (mExpandDirection) {
- case EXPAND_UP:
- case EXPAND_DOWN:
- height += mButtonSpacing * (mButtonsCount - 1);
- height = adjustForOvershoot(height);
- break;
- case EXPAND_LEFT:
- case EXPAND_RIGHT:
- width += mButtonSpacing * (mButtonsCount - 1);
- width = adjustForOvershoot(width);
- break;
+ if (mLabelsStyle != 0 && expandsHorizontally()) {
+ throw new IllegalStateException("Action labels in horizontal expand orientation is not supported.");
}
- setMeasuredDimension(width, height);
+ createAddButton(context);
}
- private static int adjustForOvershoot(final int dimension) {
- return dimension * 12 / 10;
+ public boolean isExpanded() {
+ return mExpanded;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ bringChildToFront(mAddButton);
+ mButtonsCount = getChildCount();
+
+ if (mLabelsStyle != 0) {
+ createLabels();
+ }
}
@Override
@@ -367,99 +370,102 @@ public class FloatingActionsMenu extends ViewGroup {
}
@Override
- protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
- return new LayoutParams(super.generateDefaultLayoutParams());
- }
-
- @Override
- public ViewGroup.LayoutParams generateLayoutParams(final AttributeSet attrs) {
- return new LayoutParams(super.generateLayoutParams(attrs));
- }
-
- @Override
- protected ViewGroup.LayoutParams generateLayoutParams(final ViewGroup.LayoutParams p) {
- return new LayoutParams(super.generateLayoutParams(p));
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- bringChildToFront(mAddButton);
- mButtonsCount = getChildCount();
-
- if (mLabelsStyle != 0) {
- createLabels();
- }
- }
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
+ measureChildren(widthMeasureSpec, heightMeasureSpec);
- private static final boolean BROKEN_LABEL_STYLE = Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.BRAND.equals("ASUS");
+ int width = 0;
+ int height = 0;
- private void createLabels() {
- final Context context = BROKEN_LABEL_STYLE ? getContext() : new ContextThemeWrapper(getContext(), mLabelsStyle);
+ mMaxButtonWidth = 0;
+ mMaxButtonHeight = 0;
+ int maxLabelWidth = 0;
for (int i = 0; i < mButtonsCount; i++) {
- final FloatingActionButton button = (FloatingActionButton) getChildAt(i);
+ final View child = getChildAt(i);
- if (button instanceof LabeledFloatingActionButton) {
- final String title = ((LabeledFloatingActionButton) button).getTitle();
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
- final AppCompatTextView label = new AppCompatTextView(context);
- if (!BROKEN_LABEL_STYLE)
- label.setTextAppearance(context, mLabelsStyle);
- label.setText(title);
- addView(label);
+ switch (mExpandDirection) {
+ case EXPAND_UP:
+ case EXPAND_DOWN:
+ mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());
+ height += child.getMeasuredHeight();
+ break;
+ case EXPAND_LEFT:
+ case EXPAND_RIGHT:
+ width += child.getMeasuredWidth();
+ mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight());
+ break;
+ }
- button.setTag(R.id.fab_label, label);
+ if (!expandsHorizontally()) {
+ final TextView label = (TextView) child.getTag(R.id.fab_label);
+ if (label != null) {
+ maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth());
+ }
}
}
- }
- public void collapse() {
- collapse(false);
- }
+ if (expandsHorizontally()) {
+ height = mMaxButtonHeight;
+ } else {
+ width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0);
+ }
- public void collapseImmediately() {
- collapse(true);
+ switch (mExpandDirection) {
+ case EXPAND_UP:
+ case EXPAND_DOWN:
+ height += mButtonSpacing * (mButtonsCount - 1);
+ height = adjustForOvershoot(height);
+ break;
+ case EXPAND_LEFT:
+ case EXPAND_RIGHT:
+ width += mButtonSpacing * (mButtonsCount - 1);
+ width = adjustForOvershoot(width);
+ break;
+ }
+
+ setMeasuredDimension(width, height);
}
- private void collapse(final boolean immediately) {
- if (mExpanded) {
- mExpanded = false;
- mTouchDelegateGroup.setEnabled(false);
- mCollapseAnimation.setDuration(immediately ? 0 : ANIMATION_DURATION);
- mCollapseAnimation.start();
- mExpandAnimation.cancel();
+ @Override
+ public void onRestoreInstanceState(final Parcelable state) {
+ if (state instanceof SavedState) {
+ final SavedState savedState = (SavedState) state;
+ mExpanded = savedState.mExpanded;
+ mTouchDelegateGroup.setEnabled(mExpanded);
- if (mListener != null) {
- mListener.onMenuCollapsed();
+ if (mRotatingDrawable != null) {
+ mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION);
}
- }
- }
- public void toggle() {
- if (mExpanded) {
- collapse();
+ super.onRestoreInstanceState(savedState.getSuperState());
} else {
- expand();
+ super.onRestoreInstanceState(state);
}
}
- public void expand() {
- if (!mExpanded) {
- mExpanded = true;
- mTouchDelegateGroup.setEnabled(true);
- mCollapseAnimation.cancel();
- mExpandAnimation.start();
+ @Override
+ public Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ final SavedState savedState = new SavedState(superState);
+ savedState.mExpanded = mExpanded;
- if (mListener != null) {
- mListener.onMenuExpanded();
- }
- }
+ return savedState;
}
- public boolean isExpanded() {
- return mExpanded;
+ public void removeButton(final LabeledFloatingActionButton button) {
+ removeView(button.getLabelView());
+ removeView(button);
+ button.setTag(R.id.fab_label, null);
+ mButtonsCount--;
+ }
+
+ public void setBehaviorYTranslation(final float behaviorYTranslation) {
+ this.behaviorYTranslation = behaviorYTranslation;
+ setTranslationY(behaviorYTranslation + scrollYTranslation);
}
@Override
@@ -469,36 +475,27 @@ public class FloatingActionsMenu extends ViewGroup {
mAddButton.setEnabled(enabled);
}
- @Override
- public Parcelable onSaveInstanceState() {
- final Parcelable superState = super.onSaveInstanceState();
- final SavedState savedState = new SavedState(superState);
- savedState.mExpanded = mExpanded;
-
- return savedState;
+ public void setOnFloatingActionsMenuUpdateListener(final OnFloatingActionsMenuUpdateListener listener) {
+ mListener = listener;
}
- @Override
- public void onRestoreInstanceState(final Parcelable state) {
- if (state instanceof SavedState) {
- final SavedState savedState = (SavedState) state;
- mExpanded = savedState.mExpanded;
- mTouchDelegateGroup.setEnabled(mExpanded);
-
- if (mRotatingDrawable != null) {
- mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION);
- }
+ public void setScrollYTranslation(final float scrollYTranslation) {
+ this.scrollYTranslation = scrollYTranslation;
+ setTranslationY(behaviorYTranslation + scrollYTranslation);
+ }
- super.onRestoreInstanceState(savedState.getSuperState());
+ public void toggle() {
+ if (mExpanded) {
+ collapse();
} else {
- super.onRestoreInstanceState(state);
+ expand();
}
}
public interface OnFloatingActionsMenuUpdateListener {
- void onMenuExpanded();
-
void onMenuCollapsed();
+
+ void onMenuExpanded();
}
private static class RotatingDrawable extends LayerDrawable {
@@ -508,6 +505,14 @@ public class FloatingActionsMenu extends ViewGroup {
super(new Drawable[]{drawable});
}
+ @Override
+ public void draw(final Canvas canvas) {
+ canvas.save();
+ canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY());
+ super.draw(canvas);
+ canvas.restore();
+ }
+
@SuppressWarnings("UnusedDeclaration")
public float getRotation() {
return mRotation;
@@ -519,14 +524,6 @@ public class FloatingActionsMenu extends ViewGroup {
mRotation = rotation;
invalidateSelf();
}
-
- @Override
- public void draw(final Canvas canvas) {
- canvas.save();
- canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY());
- super.draw(canvas);
- canvas.restore();
- }
}
public static class SavedState extends BaseSavedState {
@@ -562,10 +559,10 @@ public class FloatingActionsMenu extends ViewGroup {
private class LayoutParams extends ViewGroup.LayoutParams {
- private final ObjectAnimator mExpandDir = new ObjectAnimator();
- private final ObjectAnimator mExpandAlpha = new ObjectAnimator();
- private final ObjectAnimator mCollapseDir = new ObjectAnimator();
private final ObjectAnimator mCollapseAlpha = new ObjectAnimator();
+ private final ObjectAnimator mCollapseDir = new ObjectAnimator();
+ private final ObjectAnimator mExpandAlpha = new ObjectAnimator();
+ private final ObjectAnimator mExpandDir = new ObjectAnimator();
private boolean animationsSetToPlay;
LayoutParams(final ViewGroup.LayoutParams source) {
@@ -596,6 +593,20 @@ public class FloatingActionsMenu extends ViewGroup {
}
}
+ private void addLayerTypeListener(final Animator animator, final View view) {
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(final Animator animation) {
+ view.setLayerType(LAYER_TYPE_NONE, null);
+ }
+
+ @Override
+ public void onAnimationStart(final Animator animation) {
+ view.setLayerType(LAYER_TYPE_HARDWARE, null);
+ }
+ });
+ }
+
public void setAnimationsTarget(final View view) {
mCollapseAlpha.setTarget(view);
mCollapseDir.setTarget(view);
@@ -614,19 +625,5 @@ public class FloatingActionsMenu extends ViewGroup {
animationsSetToPlay = true;
}
}
-
- private void addLayerTypeListener(final Animator animator, final View view) {
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(final Animator animation) {
- view.setLayerType(LAYER_TYPE_NONE, null);
- }
-
- @Override
- public void onAnimationStart(final Animator animation) {
- view.setLayerType(LAYER_TYPE_HARDWARE, null);
- }
- });
- }
}
}
diff --git a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java b/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java
index 4bb82f4c..ddb2899b 100644
--- a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java
+++ b/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java
@@ -29,13 +29,6 @@ public class TouchDelegateGroup extends TouchDelegate {
mTouchDelegates.add(touchDelegate);
}
- public void removeTouchDelegate(final TouchDelegate touchDelegate) {
- mTouchDelegates.remove(touchDelegate);
- if (mCurrentTouchDelegate == touchDelegate) {
- mCurrentTouchDelegate = null;
- }
- }
-
public void clearTouchDelegates() {
mTouchDelegates.clear();
mCurrentTouchDelegate = null;
@@ -72,6 +65,13 @@ public class TouchDelegateGroup extends TouchDelegate {
return delegate != null && delegate.onTouchEvent(event);
}
+ public void removeTouchDelegate(final TouchDelegate touchDelegate) {
+ mTouchDelegates.remove(touchDelegate);
+ if (mCurrentTouchDelegate == touchDelegate) {
+ mCurrentTouchDelegate = null;
+ }
+ }
+
public void setEnabled(final boolean enabled) {
mEnabled = enabled;
}
diff --git a/app/src/main/java/com/wireguard/config/Config.java b/app/src/main/java/com/wireguard/config/Config.java
index 31fe13cf..61e31838 100644
--- a/app/src/main/java/com/wireguard/config/Config.java
+++ b/app/src/main/java/com/wireguard/config/Config.java
@@ -105,9 +105,9 @@ public class Config {
return new Observable[size];
}
};
- @Nullable private String name;
private final Interface.Observable observableInterface;
private final ObservableList<Peer.Observable> observablePeers;
+ @Nullable private String name;
public Observable(@Nullable final Config parent, @Nullable final String name) {
this.name = name;
diff --git a/app/src/main/java/com/wireguard/config/Interface.java b/app/src/main/java/com/wireguard/config/Interface.java
index a1b9125a..aa1d986b 100644
--- a/app/src/main/java/com/wireguard/config/Interface.java
+++ b/app/src/main/java/com/wireguard/config/Interface.java
@@ -28,12 +28,12 @@ import java.util.List;
public class Interface {
private final List<InetNetwork> addressList;
+ private final Context context = Application.get();
private final List<InetAddress> dnsList;
private final List<String> excludedApplications;
@Nullable private Keypair keypair;
private int listenPort;
private int mtu;
- private final Context context = Application.get();
public Interface() {
addressList = new ArrayList<>();
@@ -94,6 +94,10 @@ public class Interface {
return dnsList.toArray(new InetAddress[dnsList.size()]);
}
+ public String[] getExcludedApplications() {
+ return excludedApplications.toArray(new String[excludedApplications.size()]);
+ }
+
@Nullable
private String getExcludedApplicationsString() {
if (excludedApplications.isEmpty())
@@ -101,10 +105,6 @@ public class Interface {
return Attribute.iterableToString(excludedApplications);
}
- public String[] getExcludedApplications() {
- return excludedApplications.toArray(new String[excludedApplications.size()]);
- }
-
public int getListenPort() {
return listenPort;
}
diff --git a/app/src/main/java/com/wireguard/config/Peer.java b/app/src/main/java/com/wireguard/config/Peer.java
index 914516ba..5cf0283c 100644
--- a/app/src/main/java/com/wireguard/config/Peer.java
+++ b/app/src/main/java/com/wireguard/config/Peer.java
@@ -37,11 +37,11 @@ import java9.lang.Iterables;
public class Peer {
private final List<InetNetwork> allowedIPsList;
+ private final Context context = Application.get();
@Nullable private InetEndpoint endpoint;
private int persistentKeepalive;
@Nullable private String preSharedKey;
@Nullable private String publicKey;
- private final Context context = Application.get();
public Peer() {
allowedIPsList = new ArrayList<>();
@@ -201,13 +201,15 @@ public class Peer {
return new Observable[size];
}
};
+ private static final List<String> DEFAULT_ROUTE_MOD_RFC1918_V4 = Arrays.asList("0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6", "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9", "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11", "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14", "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7", "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
+ private static final String DEFAULT_ROUTE_V4 = "0.0.0.0/0";
+ private final List<String> interfaceDNSRoutes = new ArrayList<>();
@Nullable private String allowedIPs;
@Nullable private String endpoint;
+ private int numSiblings;
@Nullable private String persistentKeepalive;
@Nullable private String preSharedKey;
@Nullable private String publicKey;
- private final List<String> interfaceDNSRoutes = new ArrayList<>();
- private int numSiblings;
public Observable(final Peer parent) {
loadData(parent);
@@ -244,22 +246,9 @@ public class Peer {
return 0;
}
- private static final String DEFAULT_ROUTE_V4 = "0.0.0.0/0";
- private static final List<String> DEFAULT_ROUTE_MOD_RFC1918_V4 = Arrays.asList("0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6", "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9", "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11", "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14", "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7", "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
-
- public void toggleExcludePrivateIPs() {
- final Collection<String> ips = new HashSet<>(Arrays.asList(Attribute.stringToList(allowedIPs)));
- final boolean hasDefaultRoute = ips.contains(DEFAULT_ROUTE_V4);
- final boolean hasDefaultRouteModRFC1918 = ips.containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
- if ((!hasDefaultRoute && !hasDefaultRouteModRFC1918) || numSiblings > 0)
- return;
- Iterables.removeIf(ips, ip -> !ip.contains(":"));
- if (hasDefaultRoute) {
- ips.addAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
- ips.addAll(interfaceDNSRoutes);
- } else if (hasDefaultRouteModRFC1918)
- ips.add(DEFAULT_ROUTE_V4);
- setAllowedIPs(Attribute.iterableToString(ips));
+ @Bindable @Nullable
+ public String getAllowedIPs() {
+ return allowedIPs;
}
@Bindable
@@ -268,21 +257,16 @@ public class Peer {
return numSiblings == 0 && (ips.contains(DEFAULT_ROUTE_V4) || ips.containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4));
}
- @Bindable
- public boolean getIsExcludePrivateIPsOn() {
- return numSiblings == 0 && Arrays.asList(Attribute.stringToList(allowedIPs)).containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
- }
-
- @Bindable @Nullable
- public String getAllowedIPs() {
- return allowedIPs;
- }
-
@Bindable @Nullable
public String getEndpoint() {
return endpoint;
}
+ @Bindable
+ public boolean getIsExcludePrivateIPsOn() {
+ return numSiblings == 0 && Arrays.asList(Attribute.stringToList(allowedIPs)).containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
+ }
+
@Bindable @Nullable
public String getPersistentKeepalive() {
return persistentKeepalive;
@@ -318,21 +302,6 @@ public class Peer {
notifyPropertyChanged(BR.endpoint);
}
- public void setPersistentKeepalive(final String persistentKeepalive) {
- this.persistentKeepalive = persistentKeepalive;
- notifyPropertyChanged(BR.persistentKeepalive);
- }
-
- public void setPreSharedKey(final String preSharedKey) {
- this.preSharedKey = preSharedKey;
- notifyPropertyChanged(BR.preSharedKey);
- }
-
- public void setPublicKey(final String publicKey) {
- this.publicKey = publicKey;
- notifyPropertyChanged(BR.publicKey);
- }
-
public void setInterfaceDNSRoutes(@Nullable final String dnsServers) {
final Collection<String> ips = new HashSet<>(Arrays.asList(Attribute.stringToList(allowedIPs)));
final boolean modifyAllowedIPs = ips.containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
@@ -354,6 +323,36 @@ public class Peer {
notifyPropertyChanged(BR.isExcludePrivateIPsOn);
}
+ public void setPersistentKeepalive(final String persistentKeepalive) {
+ this.persistentKeepalive = persistentKeepalive;
+ notifyPropertyChanged(BR.persistentKeepalive);
+ }
+
+ public void setPreSharedKey(final String preSharedKey) {
+ this.preSharedKey = preSharedKey;
+ notifyPropertyChanged(BR.preSharedKey);
+ }
+
+ public void setPublicKey(final String publicKey) {
+ this.publicKey = publicKey;
+ notifyPropertyChanged(BR.publicKey);
+ }
+
+ public void toggleExcludePrivateIPs() {
+ final Collection<String> ips = new HashSet<>(Arrays.asList(Attribute.stringToList(allowedIPs)));
+ final boolean hasDefaultRoute = ips.contains(DEFAULT_ROUTE_V4);
+ final boolean hasDefaultRouteModRFC1918 = ips.containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
+ if ((!hasDefaultRoute && !hasDefaultRouteModRFC1918) || numSiblings > 0)
+ return;
+ Iterables.removeIf(ips, ip -> !ip.contains(":"));
+ if (hasDefaultRoute) {
+ ips.addAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
+ ips.addAll(interfaceDNSRoutes);
+ } else if (hasDefaultRouteModRFC1918)
+ ips.add(DEFAULT_ROUTE_V4);
+ setAllowedIPs(Attribute.iterableToString(ips));
+ }
+
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeString(allowedIPs);
diff --git a/app/src/main/java/com/wireguard/util/NonNullForAll.java b/app/src/main/java/com/wireguard/util/NonNullForAll.java
index f2bd8255..4207cf85 100644
--- a/app/src/main/java/com/wireguard/util/NonNullForAll.java
+++ b/app/src/main/java/com/wireguard/util/NonNullForAll.java
@@ -22,4 +22,5 @@ import javax.annotation.meta.TypeQualifierDefault;
@Nonnull
@TypeQualifierDefault({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
-public @interface NonNullForAll { }
+public @interface NonNullForAll {
+}
diff --git a/app/src/main/res/drawable/ic_action_select_all.xml b/app/src/main/res/drawable/ic_action_select_all.xml
index 2ddfb85a..9c560297 100644
--- a/app/src/main/res/drawable/ic_action_select_all.xml
+++ b/app/src/main/res/drawable/ic_action_select_all.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="24"
- android:viewportHeight="24"
android:width="24dp"
- android:height="24dp">
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
<path
android:fillColor="?android:attr/colorForeground"
android:pathData="M3 5L5 5 5 3C3.9 3 3 3.9 3 5Zm0 8l2 0 0 -2 -2 0 0 2zm4 8l2 0 0 -2 -2 0 0 2zM3 9L5 9 5 7 3 7 3 9Zm10 -6l-2 0 0 2 2 0 0 -2zm6 0l0 2 2 0C21 3.9 20.1 3 19 3ZM5 21L5 19 3 19c0 1.1 0.9 2 2 2zm-2 -4l2 0 0 -2 -2 0 0 2zM9 3L7 3 7 5 9 5 9 3Zm2 18l2 0 0 -2 -2 0 0 2zm8 -8l2 0 0 -2 -2 0 0 2zm0 8c1.1 0 2 -0.9 2 -2l-2 0 0 2zm0 -12l2 0 0 -2 -2 0 0 2zm0 8l2 0 0 -2 -2 0 0 2zm-4 4l2 0 0 -2 -2 0 0 2zm0 -16l2 0 0 -2 -2 0 0 2zM7 17L17 17 17 7 7 7 7 17Zm2 -8l6 0 0 6 -6 0 0 -6z" />
-</vector> \ No newline at end of file
+</vector>
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
index e8571eb3..aabfce2a 100644
--- a/app/src/main/res/drawable/ic_settings.xml
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -5,5 +5,5 @@
android:viewportWidth="24">
<path
android:fillColor="?android:attr/colorForeground"
- android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
</vector>
diff --git a/app/src/main/res/drawable/list_item_background.xml b/app/src/main/res/drawable/list_item_background.xml
index 6a69bcda..f86d4df1 100644
--- a/app/src/main/res/drawable/list_item_background.xml
+++ b/app/src/main/res/drawable/list_item_background.xml
@@ -3,10 +3,14 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item>
<selector>
- <item app:state_multiselected="true" android:state_activated="true">
+ <item
+ android:state_activated="true"
+ app:state_multiselected="true">
<color android:color="?attr/colorControlActivated" />
</item>
- <item app:state_multiselected="false" android:state_activated="true">
+ <item
+ android:state_activated="true"
+ app:state_multiselected="false">
<color android:color="?attr/colorControlHighlight" />
</item>
</selector>
diff --git a/app/src/main/res/layout/app_list_dialog_fragment.xml b/app/src/main/res/layout/app_list_dialog_fragment.xml
index 25879b6b..c975778a 100644
--- a/app/src/main/res/layout/app_list_dialog_fragment.xml
+++ b/app/src/main/res/layout/app_list_dialog_fragment.xml
@@ -20,7 +20,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:minHeight="200dp" >
+ android:minHeight="200dp">
<ProgressBar
android:id="@+id/progress_bar"
@@ -28,7 +28,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
- android:visibility="@{appData.isEmpty() ? View.VISIBLE : View.GONE}"/>
+ android:visibility="@{appData.isEmpty() ? View.VISIBLE : View.GONE}" />
<android.support.v7.widget.RecyclerView
android:id="@+id/app_list"
diff --git a/app/src/main/res/layout/app_list_item.xml b/app/src/main/res/layout/app_list_item.xml
index 4519a3a4..825b828b 100644
--- a/app/src/main/res/layout/app_list_item.xml
+++ b/app/src/main/res/layout/app_list_item.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
@@ -23,10 +22,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_item_background"
- android:padding="16dp"
- android:orientation="horizontal"
android:gravity="center_vertical"
- android:onClick="@{(view) -> item.setExcludedFromTunnel(!item.excludedFromTunnel)}">
+ android:onClick="@{(view) -> item.setExcludedFromTunnel(!item.excludedFromTunnel)}"
+ android:orientation="horizontal"
+ android:padding="16dp">
<ImageView
android:id="@+id/app_icon"
diff --git a/app/src/main/res/layout/config_naming_dialog_fragment.xml b/app/src/main/res/layout/config_naming_dialog_fragment.xml
index 12871a85..bf8b4267 100644
--- a/app/src/main/res/layout/config_naming_dialog_fragment.xml
+++ b/app/src/main/res/layout/config_naming_dialog_fragment.xml
@@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
+
<import type="com.wireguard.android.widget.NameInputFilter" />
</data>
diff --git a/app/src/main/res/layout/tunnel_editor_fragment.xml b/app/src/main/res/layout/tunnel_editor_fragment.xml
index 1020e34c..f7976459 100644
--- a/app/src/main/res/layout/tunnel_editor_fragment.xml
+++ b/app/src/main/res/layout/tunnel_editor_fragment.xml
@@ -100,8 +100,8 @@
app:filter="@{KeyInputFilter.newInstance()}" />
<Button
- style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:id="@+id/generate_private_key_button"
+ style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/private_key_text"
@@ -217,12 +217,12 @@
android:textAlignment="center" />
<Button
- style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:id="@+id/set_excluded_applications"
+ style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="-8dp"
android:layout_below="@+id/dns_servers_text"
+ android:layout_marginLeft="-8dp"
android:onClick="@{fragment::onRequestSetExcludedApplications}"
android:text="@{@plurals/set_excluded_applications(config.interfaceSection.excludedApplicationsCount, config.interfaceSection.excludedApplicationsCount)}" />
</RelativeLayout>
diff --git a/app/src/main/res/layout/tunnel_editor_peer.xml b/app/src/main/res/layout/tunnel_editor_peer.xml
index 472b4cac..e270b71a 100644
--- a/app/src/main/res/layout/tunnel_editor_peer.xml
+++ b/app/src/main/res/layout/tunnel_editor_peer.xml
@@ -4,7 +4,8 @@
<data>
- <import type="android.view.View"/>
+ <import type="android.view.View" />
+
<import type="com.wireguard.android.widget.KeyInputFilter" />
<variable
diff --git a/app/src/main/res/layout/tunnel_list_fragment.xml b/app/src/main/res/layout/tunnel_list_fragment.xml
index a442c3be..ccc1c5ae 100644
--- a/app/src/main/res/layout/tunnel_list_fragment.xml
+++ b/app/src/main/res/layout/tunnel_list_fragment.xml
@@ -30,65 +30,67 @@
android:id="@+id/tunnel_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingBottom="@{@dimen/design_fab_size_normal * 1.1f}"
- android:clipToPadding="false"
android:choiceMode="multipleChoiceModal"
+ android:clipToPadding="false"
+ android:paddingBottom="@{@dimen/design_fab_size_normal * 1.1f}"
android:visibility="@{tunnels.size() > 0 ? android.view.View.VISIBLE : android.view.View.GONE}"
+ app:configurationHandler="@{rowConfigurationHandler}"
app:items="@{tunnels}"
- app:layout="@{@layout/tunnel_list_item}"
- app:configurationHandler="@{rowConfigurationHandler}" />
+ app:layout="@{@layout/tunnel_list_item}" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center"
android:orientation="vertical"
- android:visibility="@{tunnels.size() == 0 ? android.view.View.VISIBLE : android.view.View.GONE}"
- android:layout_gravity="center">
+ android:visibility="@{tunnels.size() == 0 ? android.view.View.VISIBLE : android.view.View.GONE}">
+
<android.support.v7.widget.AppCompatImageView
android:id="@+id/logo_placeholder"
android:layout_width="140dp"
android:layout_height="140dp"
android:layout_gravity="center"
- android:alpha="0.3333333"
- android:layout_marginTop="-70dp"
android:layout_marginBottom="20dp"
+ android:layout_marginTop="-70dp"
+ android:alpha="0.3333333"
android:src="@mipmap/ic_launcher" />
+
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:textSize="20sp"
- android:text="@string/tunnel_list_placeholder" />
+ android:text="@string/tunnel_list_placeholder"
+ android:textSize="20sp" />
</LinearLayout>
<com.wireguard.android.widget.fab.FloatingActionsMenu
android:id="@+id/create_menu"
- android:clipChildren="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
+ android:clipChildren="false"
app:fab_labelStyle="@style/fab_label"
app:fab_labelsPosition="@integer/label_position"
- app:layout_behavior="com.wireguard.android.widget.fab.FloatingActionButtonBehavior" >
+ app:layout_behavior="com.wireguard.android.widget.fab.FloatingActionButtonBehavior">
<com.wireguard.android.widget.fab.LabeledFloatingActionButton
android:id="@+id/create_from_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{fragment::onRequestImportConfig}"
- app:srcCompat="@drawable/ic_action_open_white"
app:fabSize="mini"
- app:fab_title="@string/create_from_file" />
+ app:fab_title="@string/create_from_file"
+ app:srcCompat="@drawable/ic_action_open_white" />
<com.wireguard.android.widget.fab.LabeledFloatingActionButton
android:id="@+id/scan_qr_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{fragment::onRequestScanQRCode}"
- app:srcCompat="@drawable/ic_action_scan_qr_code_white"
app:fabSize="mini"
- app:fab_title="@string/create_from_qrcode" />
+ app:fab_title="@string/create_from_qrcode"
+ app:srcCompat="@drawable/ic_action_scan_qr_code_white" />
<com.wireguard.android.widget.fab.LabeledFloatingActionButton
android:id="@+id/create_empty"
@@ -96,8 +98,8 @@
android:layout_height="wrap_content"
android:onClick="@{fragment::onRequestCreateConfig}"
app:fabSize="mini"
- app:srcCompat="@drawable/ic_action_edit_white"
- app:fab_title="@string/create_empty" />
+ app:fab_title="@string/create_empty"
+ app:srcCompat="@drawable/ic_action_edit_white" />
</com.wireguard.android.widget.fab.FloatingActionsMenu>
</android.support.design.widget.CoordinatorLayout>
diff --git a/app/src/main/res/menu/main_activity.xml b/app/src/main/res/menu/main_activity.xml
index 5fd11821..68bce52e 100644
--- a/app/src/main/res/menu/main_activity.xml
+++ b/app/src/main/res/menu/main_activity.xml
@@ -5,7 +5,7 @@
android:id="@+id/menu_settings"
android:alphabeticShortcut="s"
android:icon="@drawable/ic_settings"
+ android:orderInCategory="1000"
android:title="@string/settings"
- app:showAsAction="always"
- android:orderInCategory="1000" />
+ app:showAsAction="always" />
</menu>
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 85a987f9..86a86e63 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Multiselected">
- <attr name="state_multiselected" format="boolean"/>
+ <attr name="state_multiselected" format="boolean" />
</declare-styleable>
-</resources> \ No newline at end of file
+</resources>
diff --git a/app/src/main/res/values/fab.xml b/app/src/main/res/values/fab.xml
index e1d10df1..8fbdc724 100644
--- a/app/src/main/res/values/fab.xml
+++ b/app/src/main/res/values/fab.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <item name="fab_expand_menu_button" type="id"/>
- <item name="fab_label" type="id"/>
+ <item name="fab_expand_menu_button" type="id" />
+ <item name="fab_label" type="id" />
<dimen name="fab_shadow_offset">3dp</dimen>
<dimen name="fab_shadow_radius">9dp</dimen>
@@ -12,19 +12,19 @@
<dimen name="fab_labels_margin">8dp</dimen>
<declare-styleable name="LabeledFloatingActionButton">
- <attr name="fab_title" format="string"/>
+ <attr name="fab_title" format="string" />
</declare-styleable>
<declare-styleable name="FloatingActionsMenu">
- <attr name="fab_labelStyle" format="reference"/>
+ <attr name="fab_labelStyle" format="reference" />
<attr name="fab_labelsPosition" format="enum">
- <enum name="left" value="0"/>
- <enum name="right" value="1"/>
+ <enum name="left" value="0" />
+ <enum name="right" value="1" />
</attr>
<attr name="fab_expandDirection" format="enum">
- <enum name="up" value="0"/>
- <enum name="down" value="1"/>
- <enum name="left" value="2"/>
- <enum name="right" value="3"/>
+ <enum name="up" value="0" />
+ <enum name="down" value="1" />
+ <enum name="left" value="2" />
+ <enum name="right" value="3" />
</attr>
</declare-styleable>
<integer name="label_position">0</integer>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index c864ecfd..fce295ea 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -12,7 +12,7 @@
<CheckBoxPreference
android:defaultValue="false"
android:key="dark_theme"
- android:summaryOn="@string/dark_theme_summary_on"
android:summaryOff="@string/dark_theme_summary_off"
+ android:summaryOn="@string/dark_theme_summary_on"
android:title="@string/dark_theme_title" />
</PreferenceScreen>