mirror of
https://github.com/amnezia-vpn/amneziawg-android.git
synced 2026-07-03 14:05:13 +02:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d580200989 | |||
| c2cdde73d1 | |||
| bc74d4d7f8 | |||
| 535c611f2d | |||
| 6efbf65405 | |||
| abb121224d | |||
| 8ad4657d6f | |||
| 6d3f1e00a5 | |||
| c38f6c471d | |||
| 85462de254 | |||
| 61d4f17f5d | |||
| 09cf73cd3c | |||
| ffa3cefa67 | |||
| 8ec2cc8582 | |||
| 75dfa0643b | |||
| d5cde43158 | |||
| 6493a9a1f2 | |||
| f35e059194 | |||
| 3cb3e9d8b7 | |||
| 5dfc5659ad | |||
| c4102992ae | |||
| 219f4e8016 | |||
| 6558140a7c | |||
| db7b61ab80 | |||
| bce5d852e1 | |||
| b960b4a6cd | |||
| 1b10e75168 | |||
| 07359e392c | |||
| e5a5bad240 | |||
| ca92ac60b7 | |||
| e29c21f8df | |||
| 6ceeac93bf | |||
| 9f861096ac | |||
| 520df16885 |
+7
-7
@@ -11,14 +11,15 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
compileSdkVersion 27
|
||||
compileSdkVersion 28
|
||||
dataBinding.enabled true
|
||||
defaultConfig {
|
||||
applicationId 'com.wireguard.android'
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 27
|
||||
versionCode 437
|
||||
versionName '0.0.20180725'
|
||||
targetSdkVersion 28
|
||||
versionCode 439
|
||||
versionName '0.0.20180826'
|
||||
buildConfigField 'int', 'MIN_SDK_VERSION', "$minSdkVersion.apiLevel"
|
||||
}
|
||||
// If the keystore file exists
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
@@ -79,12 +80,11 @@ dependencies {
|
||||
implementation "com.android.support:design:$supportLibsVersion"
|
||||
implementation "com.android.support:preference-v14:$supportLibsVersion"
|
||||
implementation "com.android.support:support-annotations:$supportLibsVersion"
|
||||
implementation "net.sourceforge.streamsupport:android-retrofuture:$streamsupportVersion"
|
||||
implementation "net.sourceforge.streamsupport:android-retrostreams:$streamsupportVersion"
|
||||
implementation "com.google.code.findbugs:jsr305:$jsr305Version"
|
||||
implementation "com.journeyapps:zxing-android-embedded:$zxingEmbeddedVersion"
|
||||
implementation "net.sourceforge.streamsupport:android-retrofuture:$streamsupportVersion"
|
||||
implementation "net.sourceforge.streamsupport:android-retrostreams:$streamsupportVersion"
|
||||
implementation "ch.acra:acra-http:$acraVersion"
|
||||
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
package com.wireguard.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.preference.PreferenceManager;
|
||||
@@ -69,9 +71,11 @@ public class Application extends android.app.Application {
|
||||
* check the DN of the certs that signed the apk, without even bothering to try
|
||||
* validating that they're authentic. It's a good enough heuristic.
|
||||
*/
|
||||
private static boolean shouldEnableCrashReporting(final Context context) {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Nullable
|
||||
private static String getInstallSource(final Context context) {
|
||||
if (BuildConfig.DEBUG)
|
||||
return false;
|
||||
return null;
|
||||
try {
|
||||
final CertificateFactory cf = CertificateFactory.getInstance("X509");
|
||||
for (final Signature sig : context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures) {
|
||||
@@ -82,21 +86,35 @@ public class Application extends android.app.Application {
|
||||
continue;
|
||||
switch (parts[1]) {
|
||||
case "Google Inc.":
|
||||
return "Play Store";
|
||||
case "fdroid.org":
|
||||
return true;
|
||||
return "F-Droid";
|
||||
}
|
||||
}
|
||||
} catch (final Exception ignored) { }
|
||||
}
|
||||
} catch (final Exception ignored) { }
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(final Context context) {
|
||||
super.attachBaseContext(context);
|
||||
if (shouldEnableCrashReporting(context))
|
||||
|
||||
if (BuildConfig.MIN_SDK_VERSION > Build.VERSION.SDK_INT) {
|
||||
final Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||
intent.addCategory(Intent.CATEGORY_HOME);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
final String installSource = getInstallSource(context);
|
||||
if (installSource != null) {
|
||||
ACRA.init(this);
|
||||
ACRA.getErrorReporter().putCustomData("installSource", installSource);
|
||||
}
|
||||
}
|
||||
|
||||
public static Application get() {
|
||||
@@ -165,9 +183,11 @@ public class Application extends android.app.Application {
|
||||
|
||||
asyncWorker.supplyAsync(Application::getBackend).thenAccept(backend -> {
|
||||
futureBackend.complete(backend);
|
||||
ACRA.getErrorReporter().putCustomData("backend", backend.getClass().getSimpleName());
|
||||
asyncWorker.supplyAsync(backend::getVersion).thenAccept(version ->
|
||||
ACRA.getErrorReporter().putCustomData("backendVersion", version));
|
||||
if (ACRA.isInitialised()) {
|
||||
ACRA.getErrorReporter().putCustomData("backend", backend.getClass().getSimpleName());
|
||||
asyncWorker.supplyAsync(backend::getVersion).thenAccept(version ->
|
||||
ACRA.getErrorReporter().putCustomData("backendVersion", version));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.support.annotation.Nullable;
|
||||
@@ -44,10 +45,26 @@ public class QuickTileService extends TileService {
|
||||
@Nullable private Icon iconOn;
|
||||
@Nullable private Icon iconOff;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
/* This works around an annoying unsolved frameworks bug some people are hitting. */
|
||||
@Override
|
||||
@Nullable
|
||||
public IBinder onBind(final Intent intent) {
|
||||
IBinder ret = null;
|
||||
try {
|
||||
ret = super.onBind(intent);
|
||||
} catch (final Exception e) {
|
||||
Log.d(TAG, "Failed to bind to TileService", e);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
final SlashDrawable icon = new SlashDrawable(getResources().getDrawable(R.drawable.ic_tile));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
iconOff = iconOn = Icon.createWithResource(this, R.drawable.ic_tile);
|
||||
return;
|
||||
}
|
||||
final SlashDrawable icon = new SlashDrawable(getResources().getDrawable(R.drawable.ic_tile, Application.get().getTheme()));
|
||||
icon.setAnimationEnabled(false); /* Unfortunately we can't have animations, since Icons are marshaled. */
|
||||
icon.setSlashed(false);
|
||||
Bitmap b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
@@ -55,17 +72,12 @@ public class QuickTileService extends TileService {
|
||||
icon.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||
icon.draw(c);
|
||||
iconOn = Icon.createWithBitmap(b);
|
||||
/* TODO(msf): Change this to an explicit test for P when we start targetting SDK 28 */
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
|
||||
iconOff = iconOn;
|
||||
} else {
|
||||
icon.setSlashed(true);
|
||||
b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
c = new Canvas(b);
|
||||
icon.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||
icon.draw(c);
|
||||
iconOff = Icon.createWithBitmap(b);
|
||||
}
|
||||
icon.setSlashed(true);
|
||||
b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
c = new Canvas(b);
|
||||
icon.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||
icon.draw(c);
|
||||
iconOff = Icon.createWithBitmap(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,12 +10,13 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.Log;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.wireguard.android.R;
|
||||
import com.wireguard.android.fragment.TunnelDetailFragment;
|
||||
@@ -23,71 +24,46 @@ import com.wireguard.android.fragment.TunnelEditorFragment;
|
||||
import com.wireguard.android.fragment.TunnelListFragment;
|
||||
import com.wireguard.android.model.Tunnel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import java9.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* CRUD interface for WireGuard tunnels. This activity serves as the main entry point to the
|
||||
* WireGuard application, and contains several fragments for listing, viewing details of, and
|
||||
* editing the configuration and interface state of WireGuard tunnels.
|
||||
*/
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
private static final String KEY_STATE = "fragment_state";
|
||||
private static final String TAG = "WireGuard/" + MainActivity.class.getSimpleName();
|
||||
|
||||
private State state = State.EMPTY;
|
||||
|
||||
private boolean moveToState(final State nextState) {
|
||||
if (state == nextState)
|
||||
return false;
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
Log.i(TAG, "Moving from " + state.name() + " to " + nextState.name());
|
||||
if (nextState.layer > state.layer + 1) {
|
||||
moveToState(State.ofLayer(state.layer + 1));
|
||||
moveToState(nextState);
|
||||
return true;
|
||||
} else if (nextState.layer == state.layer + 1) {
|
||||
final Fragment fragment = Fragment.instantiate(this, nextState.fragment);
|
||||
final FragmentTransaction transaction = fragmentManager.beginTransaction()
|
||||
.replace(R.id.master_fragment, fragment)
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
|
||||
if (state.layer > 0)
|
||||
transaction.addToBackStack(null);
|
||||
transaction.commitAllowingStateLoss(); /* TODO: switch back to .commit() when this function is rewritten. */
|
||||
} else if (nextState.layer == state.layer - 1) {
|
||||
if (fragmentManager.getBackStackEntryCount() == 0)
|
||||
return false;
|
||||
fragmentManager.popBackStack();
|
||||
} else if (nextState.layer < state.layer - 1) {
|
||||
moveToState(State.ofLayer(state.layer - 1));
|
||||
moveToState(nextState);
|
||||
return true;
|
||||
}
|
||||
state = nextState;
|
||||
if (state.layer <= State.LIST.layer)
|
||||
setSelectedTunnel(null);
|
||||
updateActionBar();
|
||||
return true;
|
||||
}
|
||||
public class MainActivity extends BaseActivity
|
||||
implements FragmentManager.OnBackStackChangedListener {
|
||||
@Nullable private ActionBar actionBar;
|
||||
private boolean isTwoPaneLayout;
|
||||
@Nullable private TunnelListFragment listFragment;
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
final List<Fragment> fragments = getSupportFragmentManager().getFragments();
|
||||
|
||||
boolean handled = false;
|
||||
if (!fragments.isEmpty() && fragments.get(0) instanceof TunnelListFragment) {
|
||||
handled = ((TunnelListFragment) fragments.get(0)).collapseActionMenu();
|
||||
final int backStackEntries = getSupportFragmentManager().getBackStackEntryCount();
|
||||
// If the action menu is visible and expanded, collapse it instead of navigating back.
|
||||
if (isTwoPaneLayout || backStackEntries == 0) {
|
||||
if (listFragment != null && listFragment.collapseActionMenu())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
handled = moveToState(State.ofLayer(state.layer - 1));
|
||||
// If the two-pane layout does not have an editor open, going back should exit the app.
|
||||
if (isTwoPaneLayout && backStackEntries <= 1) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
super.onBackPressed();
|
||||
// Deselect the current tunnel on navigating back from the detail pane to the one-pane list.
|
||||
if (!isTwoPaneLayout && backStackEntries == 1) {
|
||||
setSelectedTunnel(null);
|
||||
return;
|
||||
}
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
@Override public void onBackStackChanged() {
|
||||
if (actionBar == null)
|
||||
return;
|
||||
// Do not show the home menu when the two-pane layout is at the detail view (see above).
|
||||
final int backStackEntries = getSupportFragmentManager().getBackStackEntryCount();
|
||||
final int minBackStackEntries = isTwoPaneLayout ? 2 : 1;
|
||||
actionBar.setDisplayHomeAsUpEnabled(backStackEntries >= minBackStackEntries);
|
||||
}
|
||||
|
||||
// We use onTouchListener here to avoid the UI click sound, hence
|
||||
@@ -97,25 +73,14 @@ public class MainActivity extends BaseActivity {
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main_activity);
|
||||
if (savedInstanceState != null && savedInstanceState.getString(KEY_STATE) != null)
|
||||
state = State.valueOf(savedInstanceState.getString(KEY_STATE));
|
||||
if (state == State.EMPTY) {
|
||||
State initialState = getSelectedTunnel() != null ? State.DETAIL : State.LIST;
|
||||
if (getIntent() != null && getIntent().getStringExtra(KEY_STATE) != null)
|
||||
initialState = State.valueOf(getIntent().getStringExtra(KEY_STATE));
|
||||
moveToState(initialState);
|
||||
}
|
||||
updateActionBar();
|
||||
final int actionBarId = getResources().getIdentifier("action_bar", "id", getPackageName());
|
||||
if (actionBarId != 0 && findViewById(actionBarId) != null) {
|
||||
findViewById(actionBarId).setOnTouchListener((v, e) -> {
|
||||
final List<Fragment> fragments = getSupportFragmentManager().getFragments();
|
||||
if (!fragments.isEmpty() && fragments.get(0) instanceof TunnelListFragment) {
|
||||
((TunnelListFragment) fragments.get(0)).collapseActionMenu();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
actionBar = getSupportActionBar();
|
||||
isTwoPaneLayout = findViewById(R.id.master_detail_wrapper) instanceof LinearLayout;
|
||||
listFragment = (TunnelListFragment) getSupportFragmentManager().findFragmentByTag("LIST");
|
||||
getSupportFragmentManager().addOnBackStackChangedListener(this);
|
||||
onBackStackChanged();
|
||||
final View actionBarView = findViewById(R.id.action_bar);
|
||||
if (actionBarView != null)
|
||||
actionBarView.setOnTouchListener((v, e) -> listFragment != null && listFragment.collapseActionMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,11 +94,14 @@ public class MainActivity extends BaseActivity {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// The back arrow in the action bar should act the same as the back button.
|
||||
moveToState(State.ofLayer(state.layer - 1));
|
||||
onBackPressed();
|
||||
return true;
|
||||
case R.id.menu_action_edit:
|
||||
if (getSelectedTunnel() != null)
|
||||
moveToState(State.EDITOR);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.detail_container, new TunnelEditorFragment())
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
return true;
|
||||
case R.id.menu_action_save:
|
||||
// This menu item is handled by the editor fragment.
|
||||
@@ -147,37 +115,26 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(final Bundle outState) {
|
||||
outState.putString(KEY_STATE, state.name());
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
|
||||
moveToState(newTunnel != null ? State.DETAIL : State.LIST);
|
||||
}
|
||||
|
||||
private void updateActionBar() {
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(state.layer > State.LIST.layer);
|
||||
}
|
||||
|
||||
private enum State {
|
||||
EMPTY(null, 0),
|
||||
LIST(TunnelListFragment.class, 1),
|
||||
DETAIL(TunnelDetailFragment.class, 2),
|
||||
EDITOR(TunnelEditorFragment.class, 3);
|
||||
|
||||
@Nullable private final String fragment;
|
||||
private final int layer;
|
||||
|
||||
State(@Nullable final Class<? extends Fragment> fragment, final int layer) {
|
||||
this.fragment = fragment != null ? fragment.getName() : null;
|
||||
this.layer = layer;
|
||||
protected void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel,
|
||||
@Nullable final Tunnel newTunnel) {
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
final int backStackEntries = fragmentManager.getBackStackEntryCount();
|
||||
if (newTunnel == null) {
|
||||
// Clear everything off the back stack (all editors and detail fragments).
|
||||
fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
return;
|
||||
}
|
||||
|
||||
private static State ofLayer(final int layer) {
|
||||
return Stream.of(State.values()).filter(s -> s.layer == layer).findFirst().get();
|
||||
if (backStackEntries == 2) {
|
||||
// Pop the editor off the back stack to reveal the detail fragment. Use the immediate
|
||||
// method to avoid the editor picking up the new tunnel while it is still visible.
|
||||
fragmentManager.popBackStackImmediate();
|
||||
} else if (backStackEntries == 0) {
|
||||
// Create and show a new detail fragment.
|
||||
fragmentManager.beginTransaction()
|
||||
.add(R.id.detail_container, new TunnelDetailFragment())
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,7 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
|
||||
}
|
||||
// Tell the activity to finish itself or go back to the detail view.
|
||||
getActivity().runOnUiThread(() -> {
|
||||
// TODO(smaeul): Remove this hack when fixing the Config ViewModel
|
||||
// The selected tunnel has to actually change, but we have to remember this one.
|
||||
final Tunnel savedTunnel = tunnel;
|
||||
if (savedTunnel == getSelectedTunnel())
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -38,6 +39,8 @@ 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;
|
||||
|
||||
@@ -85,7 +88,7 @@ public class TunnelListFragment extends BaseFragment {
|
||||
final FragmentManager fragmentManager = getFragmentManager();
|
||||
if (fragmentManager != null)
|
||||
ConfigNamingDialogFragment.newInstance(configText).show(fragmentManager, null);
|
||||
} catch (final IllegalArgumentException|IOException exception) {
|
||||
} catch (final Exception exception) {
|
||||
onTunnelImportFinished(Collections.emptyList(), Collections.singletonList(exception));
|
||||
}
|
||||
}
|
||||
@@ -260,9 +263,20 @@ public class TunnelListFragment extends BaseFragment {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private MultiselectableRelativeLayout viewForTunnel(final Tunnel tunnel, final List tunnels) {
|
||||
return (MultiselectableRelativeLayout)binding.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(tunnel)).itemView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
|
||||
// Do nothing.
|
||||
if (binding == null)
|
||||
return;
|
||||
Application.getTunnelManager().getTunnels().thenAccept(tunnels -> {
|
||||
if (newTunnel != null)
|
||||
viewForTunnel(newTunnel, tunnels).setSingleSelected(true);
|
||||
if (oldTunnel != null)
|
||||
viewForTunnel(oldTunnel, tunnels).setSingleSelected(false);
|
||||
});
|
||||
}
|
||||
|
||||
private void onTunnelDeletionFinished(final Integer count, @Nullable final Throwable throwable) {
|
||||
@@ -304,6 +318,26 @@ public class TunnelListFragment extends BaseFragment {
|
||||
Snackbar.make(binding.mainContainer, message, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@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);
|
||||
@@ -328,7 +362,10 @@ public class TunnelListFragment extends BaseFragment {
|
||||
return true;
|
||||
});
|
||||
|
||||
binding.getRoot().setActivated(actionModeListener.checkedItems.contains(position));
|
||||
if (actionMode != null)
|
||||
((MultiselectableRelativeLayout)binding.getRoot()).setMultiSelected(actionModeListener.checkedItems.contains(position));
|
||||
else
|
||||
((MultiselectableRelativeLayout)binding.getRoot()).setSingleSelected(getSelectedTunnel() == tunnel);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -377,6 +414,7 @@ public class TunnelListFragment extends BaseFragment {
|
||||
resources = getActivity().getResources();
|
||||
}
|
||||
mode.getMenuInflater().inflate(R.menu.tunnel_list_action_mode, menu);
|
||||
binding.tunnelList.getAdapter().notifyDataSetChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -384,7 +422,6 @@ public class TunnelListFragment extends BaseFragment {
|
||||
public void onDestroyActionMode(final ActionMode mode) {
|
||||
actionMode = null;
|
||||
resources = null;
|
||||
|
||||
checkedItems.clear();
|
||||
binding.tunnelList.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
@@ -393,6 +430,10 @@ public class TunnelListFragment extends BaseFragment {
|
||||
setItemChecked(position, !checkedItems.contains(position));
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getCheckedItems() {
|
||||
return new ArrayList<>(checkedItems);
|
||||
}
|
||||
|
||||
void setItemChecked(final int position, final boolean checked) {
|
||||
if (checked) {
|
||||
checkedItems.add(position);
|
||||
@@ -400,15 +441,16 @@ public class TunnelListFragment extends BaseFragment {
|
||||
checkedItems.remove(position);
|
||||
}
|
||||
|
||||
final RecyclerView.Adapter adapter = binding == null ? null : binding.tunnelList.getAdapter();
|
||||
|
||||
if (actionMode == null && !checkedItems.isEmpty() && getActivity() != null) {
|
||||
((AppCompatActivity) getActivity()).startSupportActionMode(this);
|
||||
} else if (actionMode != null && checkedItems.isEmpty()) {
|
||||
actionMode.finish();
|
||||
}
|
||||
|
||||
if (binding != null) {
|
||||
binding.tunnelList.getAdapter().notifyItemChanged(position);
|
||||
}
|
||||
if (adapter != null)
|
||||
adapter.notifyItemChanged(position);
|
||||
|
||||
updateTitle(actionMode);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.support.annotation.Nullable;
|
||||
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.BR;
|
||||
import com.wireguard.android.R;
|
||||
import com.wireguard.android.configStore.ConfigStore;
|
||||
import com.wireguard.android.model.Tunnel.State;
|
||||
import com.wireguard.android.model.Tunnel.Statistics;
|
||||
@@ -46,6 +47,7 @@ public final class TunnelManager extends BaseObservable {
|
||||
private static final String KEY_RUNNING_TUNNELS = "enabled_configs";
|
||||
|
||||
private final ConfigStore configStore;
|
||||
private final Context context = Application.get();
|
||||
private final CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> completableTunnels = new CompletableFuture<>();
|
||||
private final ObservableSortedKeyedList<String, Tunnel> tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR);
|
||||
@Nullable private Tunnel lastUsedTunnel;
|
||||
@@ -64,9 +66,9 @@ public final class TunnelManager extends BaseObservable {
|
||||
|
||||
public CompletionStage<Tunnel> create(final String name, @Nullable final Config config) {
|
||||
if (Tunnel.isNameInvalid(name))
|
||||
return CompletableFuture.failedFuture(new IllegalArgumentException("Invalid name"));
|
||||
return CompletableFuture.failedFuture(new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name)));
|
||||
if (tunnels.containsKey(name)) {
|
||||
final String message = "Tunnel " + name + " already exists";
|
||||
final String message = context.getString(R.string.tunnel_error_already_exists, name);
|
||||
return CompletableFuture.failedFuture(new IllegalArgumentException(message));
|
||||
}
|
||||
return Application.getAsyncWorker().supplyAsync(() -> configStore.create(name, config))
|
||||
@@ -212,9 +214,9 @@ public final class TunnelManager extends BaseObservable {
|
||||
|
||||
CompletionStage<String> setTunnelName(final Tunnel tunnel, final String name) {
|
||||
if (Tunnel.isNameInvalid(name))
|
||||
return CompletableFuture.failedFuture(new IllegalArgumentException("Invalid name"));
|
||||
return CompletableFuture.failedFuture(new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name)));
|
||||
if (tunnels.containsKey(name)) {
|
||||
final String message = "Tunnel " + name + " already exists";
|
||||
final String message = context.getString(R.string.tunnel_error_already_exists, name);
|
||||
return CompletableFuture.failedFuture(new IllegalArgumentException(message));
|
||||
}
|
||||
final State originalState = tunnel.getState();
|
||||
|
||||
@@ -11,7 +11,11 @@ import android.view.ContextThemeWrapper;
|
||||
|
||||
import com.wireguard.android.activity.SettingsActivity;
|
||||
|
||||
public class FragmentUtils {
|
||||
public final class FragmentUtils {
|
||||
|
||||
private FragmentUtils() {
|
||||
// Prevent instantiation
|
||||
}
|
||||
|
||||
public static SettingsActivity getPrefActivity(final Preference preference) {
|
||||
final Context context = preference.getContext();
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.wireguard.android.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.wireguard.android.R;
|
||||
|
||||
public class MultiselectableRelativeLayout extends RelativeLayout {
|
||||
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) {
|
||||
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
|
||||
mergeDrawableStates(drawableState, STATE_MULTISELECTED);
|
||||
return drawableState;
|
||||
}
|
||||
return super.onCreateDrawableState(extraSpace);
|
||||
}
|
||||
|
||||
public void setMultiSelected(final boolean on) {
|
||||
if (!multiselected) {
|
||||
multiselected = true;
|
||||
refreshDrawableState();
|
||||
}
|
||||
setActivated(on);
|
||||
}
|
||||
|
||||
public void setSingleSelected(final boolean on) {
|
||||
if (multiselected) {
|
||||
multiselected = false;
|
||||
refreshDrawableState();
|
||||
}
|
||||
setActivated(on);
|
||||
}
|
||||
}
|
||||
+36
-1
@@ -6,13 +6,19 @@
|
||||
|
||||
package com.wireguard.android.widget.fab;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.support.design.widget.CoordinatorLayout;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionsMenu> {
|
||||
|
||||
public FloatingActionButtonBehavior(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
@@ -23,10 +29,39 @@ public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<Flo
|
||||
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) {
|
||||
child.setBehaviorYTranslation(destination);
|
||||
return;
|
||||
}
|
||||
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.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(final Animator a) {
|
||||
child.setBehaviorYTranslation(destination);
|
||||
}
|
||||
});
|
||||
animator.addUpdateListener(a -> child.setBehaviorYTranslation((float)a.getAnimatedValue()));
|
||||
animator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDependentViewChanged(final CoordinatorLayout parent, final FloatingActionsMenu child,
|
||||
final View dependency) {
|
||||
child.setBehaviorYTranslation(Math.min(0, dependency.getTranslationY() - dependency.getMeasuredHeight()));
|
||||
animateChange(child, Math.min(0, dependency.getTranslationY() - dependency.getMeasuredHeight()), dependency.getMeasuredHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDependentViewRemoved(final CoordinatorLayout parent, final FloatingActionsMenu child,
|
||||
final View dependency) {
|
||||
animateChange(child, 0, dependency.getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Keep;
|
||||
@@ -392,8 +393,10 @@ public class FloatingActionsMenu extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean BROKEN_LABEL_STYLE = Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.BRAND.equals("ASUS");
|
||||
|
||||
private void createLabels() {
|
||||
final Context context = new ContextThemeWrapper(getContext(), mLabelsStyle);
|
||||
final Context context = BROKEN_LABEL_STYLE ? getContext() : new ContextThemeWrapper(getContext(), mLabelsStyle);
|
||||
|
||||
for (int i = 0; i < mButtonsCount; i++) {
|
||||
final FloatingActionButton button = (FloatingActionButton) getChildAt(i);
|
||||
@@ -402,7 +405,8 @@ public class FloatingActionsMenu extends ViewGroup {
|
||||
final String title = ((LabeledFloatingActionButton) button).getTitle();
|
||||
|
||||
final AppCompatTextView label = new AppCompatTextView(context);
|
||||
label.setTextAppearance(context, mLabelsStyle);
|
||||
if (!BROKEN_LABEL_STYLE)
|
||||
label.setTextAppearance(context, mLabelsStyle);
|
||||
label.setText(title);
|
||||
addView(label);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package com.wireguard.config;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@@ -55,6 +56,7 @@ public enum Attribute {
|
||||
return TextUtils.join(", ", iterable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Attribute match(final CharSequence line) {
|
||||
return KEY_MAP.get(SEPARATOR_PATTERN.split(line)[0].toLowerCase());
|
||||
}
|
||||
@@ -65,10 +67,12 @@ public enum Attribute {
|
||||
return LIST_SEPARATOR_PATTERN.split(string.trim());
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public String composeWith(@Nullable final Object value) {
|
||||
return String.format("%s = %s%n", token, value);
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public String composeWith(final int value) {
|
||||
return String.format("%s = %d%n", token, value);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package com.wireguard.config;
|
||||
|
||||
import android.content.Context;
|
||||
import android.databinding.BaseObservable;
|
||||
import android.databinding.Bindable;
|
||||
import android.databinding.ObservableArrayList;
|
||||
@@ -15,6 +16,8 @@ import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.android.databinding.library.baseAdapters.BR;
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
@@ -43,6 +46,7 @@ public class Config {
|
||||
|
||||
public static Config from(final BufferedReader reader) throws IOException {
|
||||
final Config config = new Config();
|
||||
final Context context = Application.get();
|
||||
Peer currentPeer = null;
|
||||
String line;
|
||||
boolean inInterfaceSection = false;
|
||||
@@ -65,11 +69,11 @@ public class Config {
|
||||
} else if (currentPeer != null) {
|
||||
currentPeer.parse(line);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid configuration line: " + line);
|
||||
throw new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_config_line, line));
|
||||
}
|
||||
}
|
||||
if (!inInterfaceSection && currentPeer == null) {
|
||||
throw new IllegalArgumentException("Could not find any config information");
|
||||
throw new IllegalArgumentException(context.getString(R.string.tunnel_error_no_config_information));
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ package com.wireguard.config;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.R;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
@@ -30,7 +33,7 @@ public final class InetAddresses {
|
||||
|
||||
public static InetAddress parse(@Nullable final String address) {
|
||||
if (address == null || address.isEmpty())
|
||||
throw new IllegalArgumentException("Empty address");
|
||||
throw new IllegalArgumentException(Application.get().getString(R.string.tunnel_error_empty_inetaddress));
|
||||
try {
|
||||
return (InetAddress) PARSER_METHOD.invoke(null, address);
|
||||
} catch (final IllegalAccessException | InvocationTargetException e) {
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
|
||||
package com.wireguard.config;
|
||||
|
||||
import android.content.Context;
|
||||
import android.databinding.BaseObservable;
|
||||
import android.databinding.Bindable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.BR;
|
||||
import com.wireguard.android.R;
|
||||
import com.wireguard.crypto.Keypair;
|
||||
|
||||
import java.net.InetAddress;
|
||||
@@ -31,6 +34,7 @@ public class Interface {
|
||||
@Nullable private Keypair keypair;
|
||||
private int listenPort;
|
||||
private int mtu;
|
||||
private final Context context = Application.get();
|
||||
|
||||
public Interface() {
|
||||
addressList = new ArrayList<>();
|
||||
@@ -42,7 +46,7 @@ public class Interface {
|
||||
if (addresses != null && addresses.length > 0) {
|
||||
for (final String addr : addresses) {
|
||||
if (addr.isEmpty())
|
||||
throw new IllegalArgumentException("Address is empty");
|
||||
throw new IllegalArgumentException(context.getString(R.string.tunnel_error_empty_interface_address));
|
||||
addressList.add(new InetNetwork(addr));
|
||||
}
|
||||
}
|
||||
@@ -140,6 +144,8 @@ public class Interface {
|
||||
|
||||
public void parse(final String line) {
|
||||
final Attribute key = Attribute.match(line);
|
||||
if (key == null)
|
||||
throw new IllegalArgumentException(String.format(context.getString(R.string.tunnel_error_interface_parse_failed), line));
|
||||
switch (key) {
|
||||
case ADDRESS:
|
||||
addAddresses(key.parseList(line));
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
package com.wireguard.config;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.databinding.BaseObservable;
|
||||
import android.databinding.Bindable;
|
||||
import android.os.Parcel;
|
||||
@@ -13,6 +15,8 @@ import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.android.databinding.library.baseAdapters.BR;
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.R;
|
||||
import com.wireguard.crypto.KeyEncoding;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
@@ -38,6 +42,7 @@ public class Peer {
|
||||
private int persistentKeepalive;
|
||||
@Nullable private String preSharedKey;
|
||||
@Nullable private String publicKey;
|
||||
private final Context context = Application.get();
|
||||
|
||||
public Peer() {
|
||||
allowedIPsList = new ArrayList<>();
|
||||
@@ -67,11 +72,15 @@ public class Peer {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Nullable
|
||||
private String getEndpointString() {
|
||||
if (endpoint == null)
|
||||
return null;
|
||||
return String.format("%s:%d", endpoint.getHostString(), endpoint.getPort());
|
||||
if (endpoint.getHostString().contains(":") && !endpoint.getHostString().contains("["))
|
||||
return String.format("[%s]:%d", endpoint.getHostString(), endpoint.getPort());
|
||||
else
|
||||
return String.format("%s:%d", endpoint.getHostString(), endpoint.getPort());
|
||||
}
|
||||
|
||||
public int getPersistentKeepalive() {
|
||||
@@ -95,6 +104,7 @@ public class Peer {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public String getResolvedEndpointString() throws UnknownHostException {
|
||||
if (endpoint == null)
|
||||
throw new UnknownHostException("{empty}");
|
||||
@@ -113,6 +123,8 @@ public class Peer {
|
||||
|
||||
public void parse(final String line) {
|
||||
final Attribute key = Attribute.match(line);
|
||||
if (key == null)
|
||||
throw new IllegalArgumentException(context.getString(R.string.tunnel_error_interface_parse_failed, line));
|
||||
switch (key) {
|
||||
case ALLOWED_IPS:
|
||||
addAllowedIPs(key.parseList(line));
|
||||
@@ -147,7 +159,7 @@ public class Peer {
|
||||
if (endpoint != null && !endpoint.isEmpty()) {
|
||||
final InetSocketAddress constructedEndpoint;
|
||||
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1)
|
||||
throw new IllegalArgumentException("Forbidden characters in endpoint");
|
||||
throw new IllegalArgumentException(context.getString(R.string.tunnel_error_forbidden_endpoint_chars));
|
||||
final URI uri;
|
||||
try {
|
||||
uri = new URI("wg://" + endpoint);
|
||||
@@ -248,7 +260,7 @@ public class Peer {
|
||||
parent.setPreSharedKey(preSharedKey);
|
||||
parent.setPublicKey(publicKey);
|
||||
if (parent.getPublicKey() == null)
|
||||
throw new IllegalArgumentException("Peer public key may not be empty");
|
||||
throw new IllegalArgumentException(Application.get().getString(R.string.tunnel_error_empty_peer_public_key));
|
||||
loadData(parent);
|
||||
notifyChange();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
package com.wireguard.crypto;
|
||||
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.R;
|
||||
|
||||
/**
|
||||
* This is a specialized constant-time base64 and hex implementation that resists side-channel attacks.
|
||||
*/
|
||||
@@ -15,11 +18,11 @@ public final class KeyEncoding {
|
||||
public static final int KEY_LENGTH_BASE64 = 44;
|
||||
public static final int KEY_LENGTH_HEX = 64;
|
||||
private static final String KEY_LENGTH_BASE64_EXCEPTION_MESSAGE =
|
||||
"WireGuard base64 keys must be 44 characters encoding 32 bytes";
|
||||
Application.get().getString(R.string.key_length_base64_exception_message);
|
||||
private static final String KEY_LENGTH_EXCEPTION_MESSAGE =
|
||||
"WireGuard keys must be 32 bytes";
|
||||
Application.get().getString(R.string.key_length_exception_message);
|
||||
private static final String KEY_LENGTH_HEX_EXCEPTION_MESSAGE =
|
||||
"WireGuard hex keys must be 64 characters encoding 32 bytes";
|
||||
Application.get().getString(R.string.key_length_hex_exception_message);
|
||||
|
||||
private KeyEncoding() {
|
||||
// Prevent instantiation.
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/list_item_activated" android:state_activated="true" /> <!-- TODO(msf): themeify this -->
|
||||
<item android:drawable="@android:color/transparent" /> <!-- TODO(msf): themeify this -->
|
||||
</selector>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item>
|
||||
<selector>
|
||||
<item app:state_multiselected="true" android:state_activated="true">
|
||||
<color android:color="?attr/colorControlActivated" />
|
||||
</item>
|
||||
<item app:state_multiselected="false" android:state_activated="true">
|
||||
<color android:color="?attr/colorControlHighlight" />
|
||||
</item>
|
||||
</selector>
|
||||
</item>
|
||||
<item android:drawable="?attr/selectableItemBackground" />
|
||||
</layer-list>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/list_item_ripple"> <!-- TODO(msf): themeify this -->
|
||||
<item android:drawable="@drawable/list_item_background" />
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/white" />
|
||||
</ripple>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/master_detail_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:baselineAligned="false"
|
||||
android:divider="?attr/dividerHorizontal"
|
||||
android:orientation="horizontal"
|
||||
android:showDividers="middle"
|
||||
tools:context=".activity.MainActivity">
|
||||
|
||||
<fragment
|
||||
android:name="com.wireguard.android.fragment.TunnelListFragment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="2"
|
||||
android:tag="LIST" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/detail_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="3" />
|
||||
</LinearLayout>
|
||||
@@ -22,7 +22,7 @@
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/list_item_background_anim"
|
||||
android:background="@drawable/list_item_background"
|
||||
android:padding="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data>
|
||||
<import type="com.wireguard.android.widget.NameInputFilter" />
|
||||
</data>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -15,7 +20,9 @@
|
||||
android:id="@+id/tunnel_name_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/tunnel_name" />
|
||||
android:hint="@string/tunnel_name"
|
||||
android:inputType="textNoSuggestions|textVisiblePassword"
|
||||
app:filter="@{NameInputFilter.newInstance()}" />
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/master_fragment"
|
||||
android:id="@+id/master_detail_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:ignore="MergeRootFrame" />
|
||||
tools:context=".activity.MainActivity">
|
||||
|
||||
<fragment
|
||||
android:name="com.wireguard.android.fragment.TunnelListFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:tag="LIST" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/public_key_text"
|
||||
style="?android:attr/editTextStyle"
|
||||
style="?attr/editTextStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/public_key_label"
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="140dp"
|
||||
android:layout_gravity="center"
|
||||
android:tint="@color/transparent_background_placeholder"
|
||||
android:alpha="0.3333333"
|
||||
android:layout_marginTop="-70dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
type="com.wireguard.android.fragment.TunnelListFragment" />
|
||||
</data>
|
||||
|
||||
<RelativeLayout
|
||||
<com.wireguard.android.widget.MultiselectableRelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/list_item_background_anim"
|
||||
android:background="@drawable/list_item_background"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:padding="16dp">
|
||||
|
||||
@@ -51,5 +51,5 @@
|
||||
android:layout_alignParentEnd="true"
|
||||
app:checked="@{item.state == State.UP}"
|
||||
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
|
||||
</RelativeLayout>
|
||||
</com.wireguard.android.widget.MultiselectableRelativeLayout>
|
||||
</layout>
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- TODO(msf): remove these 4 hard-coded colors and replace with theme colors -->
|
||||
<color name="list_item_activated">#64cfd8dc</color>
|
||||
<color name="list_item_ripple">#a0808e95</color>
|
||||
<!-- TODO(msf): remove these 2 hard-coded colors and replace with theme colors -->
|
||||
<color name="fab_label_text_color">#000000</color>
|
||||
<color name="fab_label_background_color">#bbbbbb</color>
|
||||
|
||||
<color name="accent">#5e97f6</color>
|
||||
|
||||
<!-- TODO(msf): replace with ?android:attr/colorBackground with some alpha -->
|
||||
<color name="transparent_background_placeholder">#aa2e2e2e</color>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="Multiselected">
|
||||
<attr name="state_multiselected" format="boolean"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@@ -1,13 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- TODO(msf): remove these 4 hard-coded colors and replace with theme colors -->
|
||||
<color name="list_item_activated">#cfd8dc</color> <!-- Blue Grey 200 -->
|
||||
<color name="list_item_ripple">#808e95</color> <!-- Blue Grey 200 dark -->
|
||||
<!-- TODO(msf): remove these 2 hard-coded colors and replace with theme colors -->
|
||||
<color name="fab_label_text_color">#ffffff</color>
|
||||
<color name="fab_label_background_color">#444444</color>
|
||||
|
||||
<color name="accent">#2196F3</color>
|
||||
|
||||
<!-- TODO(msf): replace with ?android:attr/colorBackground with some alpha -->
|
||||
<color name="transparent_background_placeholder">#aafafafa</color>
|
||||
</resources>
|
||||
|
||||
@@ -97,6 +97,18 @@
|
||||
<string name="tunnel_name">Tunnel Name</string>
|
||||
<string name="tunnel_rename_error">Unable to rename tunnel: %s</string>
|
||||
<string name="tunnel_rename_success">Successfully renamed tunnel to “%s”</string>
|
||||
<string name="tunnel_error_invalid_name">Invalid name</string>
|
||||
<string name="tunnel_error_already_exists">Tunnel %s already exists</string>
|
||||
<string name="tunnel_error_empty_inetaddress">Empty address</string>
|
||||
<string name="tunnel_error_empty_interface_address">Address is empty</string>
|
||||
<string name="tunnel_error_interface_parse_failed">Unable to parse line: “%s”</string>
|
||||
<string name="tunnel_error_forbidden_endpoint_chars">Forbidden characters in endpoint</string>
|
||||
<string name="tunnel_error_empty_peer_public_key">Peer public key may not be empty</string>
|
||||
<string name="tunnel_error_invalid_config_line">Invalid configuration line: %s</string>
|
||||
<string name="tunnel_error_no_config_information">Could not find any config information</string>
|
||||
<string name="key_length_base64_exception_message">WireGuard base64 keys must be 44 characters encoding 32 bytes</string>
|
||||
<string name="key_length_exception_message">WireGuard keys must be 32 bytes</string>
|
||||
<string name="key_length_hex_exception_message">WireGuard hex keys must be 64 characters encoding 32 bytes</string>
|
||||
<string name="version_title">WireGuard for Android v%s"</string>
|
||||
<string name="version_summary">%s backend v%s</string>
|
||||
<string name="version_summary_checking">Checking %s backend version</string>
|
||||
|
||||
@@ -23,7 +23,7 @@ default: $(DESTDIR)/libwg-go.so
|
||||
|
||||
GOBUILDARCH := $(NDK_GO_ARCH_MAP_$(shell uname -m))
|
||||
GOBUILDOS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
|
||||
GOBUILDVERSION := 1.10.2
|
||||
GOBUILDVERSION := 1.11
|
||||
GOBUILDTARBALL := https://dl.google.com/go/go$(GOBUILDVERSION).$(GOBUILDOS)-$(GOBUILDARCH).tar.gz
|
||||
GOBUILDVERSION_NEEDED := go version go$(GOBUILDVERSION) $(GOBUILDOS)/$(GOBUILDARCH)
|
||||
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
diff -ru b/src/runtime/sys_linux_386.s a/src/runtime/sys_linux_386.s
|
||||
--- b/src/runtime/sys_linux_386.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_386.s 2018-05-09 17:09:42.319531743 +0200
|
||||
@@ -287,13 +287,13 @@
|
||||
From 6f345a38d9533db388009d91d29981673dcf95b4 Mon Sep 17 00:00:00 2001
|
||||
From: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Date: Fri, 04 May 2018 03:48:23 +0200
|
||||
Subject: [PATCH] runtime: use CLOCK_BOOTTIME in nanotime on Linux
|
||||
|
||||
This makes timers account for having expired while a computer was
|
||||
asleep, which is quite common on mobile devices. Note that BOOTTIME is
|
||||
identical to MONOTONIC, except that it takes into account time spent
|
||||
in suspend. In Linux 4.17, the kernel will actually make MONOTONIC act
|
||||
like BOOTTIME anyway, so this switch will additionally unify the
|
||||
timer behavior across kernels.
|
||||
|
||||
BOOTTIME was introduced into Linux 2.6.39-rc1 with 70a08cca1227d in
|
||||
2011.
|
||||
|
||||
Fixes #24595
|
||||
|
||||
Change-Id: I7b2a6ca0c5bc5fce57ec0eeafe7b68270b429321
|
||||
---
|
||||
|
||||
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
|
||||
index 8d5a4ff..bfad064 100644
|
||||
--- a/src/runtime/sys_linux_386.s
|
||||
+++ b/src/runtime/sys_linux_386.s
|
||||
@@ -285,13 +285,13 @@
|
||||
|
||||
LEAL 8(SP), BX // &ts (struct timespec)
|
||||
MOVL BX, 4(SP)
|
||||
@@ -17,11 +38,12 @@ diff -ru b/src/runtime/sys_linux_386.s a/src/runtime/sys_linux_386.s
|
||||
LEAL 8(SP), CX
|
||||
INVOKE_SYSCALL
|
||||
|
||||
diff -ru b/src/runtime/sys_linux_amd64.s a/src/runtime/sys_linux_amd64.s
|
||||
--- b/src/runtime/sys_linux_amd64.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_amd64.s 2018-05-09 17:09:42.319531743 +0200
|
||||
@@ -258,7 +258,7 @@
|
||||
MOVQ runtime·__vdso_clock_gettime_sym(SB), AX
|
||||
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
|
||||
index 62d8024..8510be4 100644
|
||||
--- a/src/runtime/sys_linux_amd64.s
|
||||
+++ b/src/runtime/sys_linux_amd64.s
|
||||
@@ -257,7 +257,7 @@
|
||||
MOVQ runtime·vdsoClockgettimeSym(SB), AX
|
||||
CMPQ AX, $0
|
||||
JEQ fallback
|
||||
- MOVL $1, DI // CLOCK_MONOTONIC
|
||||
@@ -29,34 +51,55 @@ diff -ru b/src/runtime/sys_linux_amd64.s a/src/runtime/sys_linux_amd64.s
|
||||
LEAQ 0(SP), SI
|
||||
CALL AX
|
||||
MOVQ 0(SP), AX // sec
|
||||
diff -ru b/src/runtime/sys_linux_arm64.s a/src/runtime/sys_linux_arm64.s
|
||||
--- b/src/runtime/sys_linux_arm64.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_arm64.s 2018-05-09 17:12:47.844591628 +0200
|
||||
@@ -201,7 +201,7 @@
|
||||
RET
|
||||
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
|
||||
index aa39732..d29cb88 100644
|
||||
--- a/src/runtime/sys_linux_arm.s
|
||||
+++ b/src/runtime/sys_linux_arm.s
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT runtime·nanotime(SB),NOSPLIT,$24-8
|
||||
- MOVW $1, R0 // CLOCK_MONOTONIC
|
||||
+ MOVW $7, R0 // CLOCK_BOOTTIME
|
||||
MOVD RSP, R1
|
||||
MOVD $SYS_clock_gettime, R8
|
||||
SVC
|
||||
diff -ru b/src/runtime/sys_linux_arm.s a/src/runtime/sys_linux_arm.s
|
||||
--- b/src/runtime/sys_linux_arm.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_arm.s 2018-05-09 17:13:18.983281049 +0200
|
||||
@@ -235,7 +235,7 @@
|
||||
#define CLOCK_REALTIME 0
|
||||
-#define CLOCK_MONOTONIC 1
|
||||
+#define CLOCK_BOOTTIME 7
|
||||
|
||||
// int64 nanotime(void)
|
||||
TEXT runtime·nanotime(SB),NOSPLIT,$32
|
||||
- MOVW $1, R0 // CLOCK_MONOTONIC
|
||||
+ MOVW $7, R0 // CLOCK_BOOTTIME
|
||||
MOVW $8(R13), R1 // timespec
|
||||
MOVW $SYS_clock_gettime, R7
|
||||
SWI $0
|
||||
diff -ru b/src/runtime/sys_linux_mips64x.s a/src/runtime/sys_linux_mips64x.s
|
||||
--- b/src/runtime/sys_linux_mips64x.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_mips64x.s 2018-05-09 17:09:42.321531721 +0200
|
||||
@@ -197,7 +197,7 @@
|
||||
// for EABI, as we don't support OABI
|
||||
#define SYS_BASE 0x0
|
||||
@@ -287,7 +287,7 @@
|
||||
SUB $24, R13 // Space for results
|
||||
BIC $0x7, R13 // Align for C code
|
||||
|
||||
- MOVW $CLOCK_MONOTONIC, R0
|
||||
+ MOVW $CLOCK_BOOTTIME, R0
|
||||
MOVW $8(R13), R1 // timespec
|
||||
MOVW runtime·vdsoClockgettimeSym(SB), R11
|
||||
CMP $0, R11
|
||||
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
|
||||
index c6afd76..24294e8 100644
|
||||
--- a/src/runtime/sys_linux_arm64.s
|
||||
+++ b/src/runtime/sys_linux_arm64.s
|
||||
@@ -13,7 +13,7 @@
|
||||
#define AT_FDCWD -100
|
||||
|
||||
#define CLOCK_REALTIME 0
|
||||
-#define CLOCK_MONOTONIC 1
|
||||
+#define CLOCK_BOOTTIME 7
|
||||
|
||||
#define SYS_exit 93
|
||||
#define SYS_read 63
|
||||
@@ -243,7 +243,7 @@
|
||||
BIC $15, R1
|
||||
MOVD R1, RSP
|
||||
|
||||
- MOVW $CLOCK_MONOTONIC, R0
|
||||
+ MOVW $CLOCK_BOOTTIME, R0
|
||||
MOVD runtime·vdsoClockgettimeSym(SB), R2
|
||||
CBZ R2, fallback
|
||||
BL (R2)
|
||||
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
|
||||
index 8e64f1c..521062f 100644
|
||||
--- a/src/runtime/sys_linux_mips64x.s
|
||||
+++ b/src/runtime/sys_linux_mips64x.s
|
||||
@@ -185,7 +185,7 @@
|
||||
RET
|
||||
|
||||
TEXT runtime·nanotime(SB),NOSPLIT,$16
|
||||
@@ -65,10 +108,11 @@ diff -ru b/src/runtime/sys_linux_mips64x.s a/src/runtime/sys_linux_mips64x.s
|
||||
MOVV $0(R29), R5
|
||||
MOVV $SYS_clock_gettime, R2
|
||||
SYSCALL
|
||||
diff -ru b/src/runtime/sys_linux_mipsx.s a/src/runtime/sys_linux_mipsx.s
|
||||
--- b/src/runtime/sys_linux_mipsx.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_mipsx.s 2018-05-09 17:09:42.321531721 +0200
|
||||
@@ -202,7 +202,7 @@
|
||||
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
|
||||
index a6bca3b..920ed9a 100644
|
||||
--- a/src/runtime/sys_linux_mipsx.s
|
||||
+++ b/src/runtime/sys_linux_mipsx.s
|
||||
@@ -189,7 +189,7 @@
|
||||
RET
|
||||
|
||||
TEXT runtime·nanotime(SB),NOSPLIT,$8-8
|
||||
@@ -77,10 +121,11 @@ diff -ru b/src/runtime/sys_linux_mipsx.s a/src/runtime/sys_linux_mipsx.s
|
||||
MOVW $4(R29), R5
|
||||
MOVW $SYS_clock_gettime, R2
|
||||
SYSCALL
|
||||
diff -ru b/src/runtime/sys_linux_ppc64x.s a/src/runtime/sys_linux_ppc64x.s
|
||||
--- b/src/runtime/sys_linux_ppc64x.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_ppc64x.s 2018-05-09 17:09:42.322531710 +0200
|
||||
@@ -176,7 +176,7 @@
|
||||
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
|
||||
index 483cb8e..11f3c49 100644
|
||||
--- a/src/runtime/sys_linux_ppc64x.s
|
||||
+++ b/src/runtime/sys_linux_ppc64x.s
|
||||
@@ -164,7 +164,7 @@
|
||||
RET
|
||||
|
||||
TEXT runtime·nanotime(SB),NOSPLIT,$16
|
||||
@@ -89,10 +134,11 @@ diff -ru b/src/runtime/sys_linux_ppc64x.s a/src/runtime/sys_linux_ppc64x.s
|
||||
MOVD $0(R1), R4
|
||||
SYSCALL $SYS_clock_gettime
|
||||
MOVD 0(R1), R3 // sec
|
||||
diff -ru b/src/runtime/sys_linux_s390x.s a/src/runtime/sys_linux_s390x.s
|
||||
--- b/src/runtime/sys_linux_s390x.s 2018-04-30 22:26:39.000000000 +0200
|
||||
+++ a/src/runtime/sys_linux_s390x.s 2018-05-09 17:09:42.322531710 +0200
|
||||
@@ -188,7 +188,7 @@
|
||||
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
|
||||
index 1ff110c..e9049e0 100644
|
||||
--- a/src/runtime/sys_linux_s390x.s
|
||||
+++ b/src/runtime/sys_linux_s390x.s
|
||||
@@ -176,7 +176,7 @@
|
||||
RET
|
||||
|
||||
TEXT runtime·nanotime(SB),NOSPLIT,$16
|
||||
|
||||
@@ -91,28 +91,28 @@ func wgTurnOn(ifnameRef string, tun_fd int32, settings string) int32 {
|
||||
return -1
|
||||
}
|
||||
|
||||
var uapi net.Listener;
|
||||
|
||||
uapiFile, err := UAPIOpen(name)
|
||||
if err != nil {
|
||||
unix.Close(int(tun_fd))
|
||||
logger.Error.Println(err)
|
||||
return -1
|
||||
}
|
||||
uapi, err := UAPIListen(name, uapiFile)
|
||||
if err != nil {
|
||||
uapiFile.Close()
|
||||
unix.Close(int(tun_fd))
|
||||
logger.Error.Println(err)
|
||||
return -1
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
conn, err := uapi.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go ipcHandle(device, conn)
|
||||
} else {
|
||||
uapi, err = UAPIListen(name, uapiFile)
|
||||
if err != nil {
|
||||
uapiFile.Close()
|
||||
logger.Error.Println(err)
|
||||
} else {
|
||||
go func() {
|
||||
for {
|
||||
conn, err := uapi.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go ipcHandle(device, conn)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
device.Up()
|
||||
logger.Info.Println("Device started")
|
||||
@@ -138,7 +138,9 @@ func wgTurnOff(tunnelHandle int32) {
|
||||
return
|
||||
}
|
||||
delete(tunnelHandles, tunnelHandle)
|
||||
handle.uapi.Close()
|
||||
if handle.uapi != nil {
|
||||
handle.uapi.Close()
|
||||
}
|
||||
handle.device.Close()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule app/tools/wireguard updated: 8f49f7b30f...393d8f2fcb
+1
-1
Submodule app/tools/wireguard-go updated: 3ad3e83c7a...15da869b31
+1
-1
@@ -7,7 +7,7 @@ allprojects {
|
||||
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
|
||||
Reference in New Issue
Block a user