global: Add nullity annotations

Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
This commit is contained in:
Eric Kuck
2018-07-13 03:46:23 +02:00
committed by Jason A. Donenfeld
parent fbaa4d9ab1
commit 67ea8b2936
48 changed files with 480 additions and 309 deletions
+1
View File
@@ -15,3 +15,4 @@ build/
*.iml *.iml
*.jks *.jks
keystore.properties keystore.properties
package-info.java
+2
View File
@@ -94,6 +94,8 @@
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML> </XML>
<codeStyleSettings language="JAVA"> <codeStyleSettings language="JAVA">
<option name="METHOD_ANNOTATION_WRAP" value="0" />
<option name="FIELD_ANNOTATION_WRAP" value="0" />
<arrangement> <arrangement>
<groups /> <groups />
<rules> <rules>
+3
View File
@@ -1,4 +1,5 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply from: 'nonnull.gradle'
// Create a variable called keystorePropertiesFile, and initialize it to your // Create a variable called keystorePropertiesFile, and initialize it to your
// keystore.properties file, in the rootProject folder. // keystore.properties file, in the rootProject folder.
@@ -56,6 +57,7 @@ ext {
databindingVersion = '3.1.3' databindingVersion = '3.1.3'
supportLibsVersion = '27.1.1' supportLibsVersion = '27.1.1'
streamsupportVersion = '1.6.0' streamsupportVersion = '1.6.0'
jsr305Version = '3.0.2'
} }
dependencies { dependencies {
@@ -67,6 +69,7 @@ dependencies {
implementation "com.android.support:support-annotations:$supportLibsVersion" implementation "com.android.support:support-annotations:$supportLibsVersion"
implementation "net.sourceforge.streamsupport:android-retrofuture:$streamsupportVersion" implementation "net.sourceforge.streamsupport:android-retrofuture:$streamsupportVersion"
implementation "net.sourceforge.streamsupport:android-retrostreams:$streamsupportVersion" implementation "net.sourceforge.streamsupport:android-retrostreams:$streamsupportVersion"
implementation "com.google.code.findbugs:jsr305:$jsr305Version"
} }
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright © 2018 Eric Kuck <eric@bluelinelabs.com>.
* SPDX-License-Identifier: Apache-2.0
*/
task generateNonNullJavaFiles(dependsOn: "assembleDebug", type: Copy) {
group = "Copying"
description = "Generate package-info.java classes"
def basePackage = "com" + File.separatorChar + "wireguard"
def mainSrcPhrase = "src" + File.separatorChar + "main" + File.separatorChar +
"java" + File.separatorChar
def mainTestSrcPhrase = "src" + File.separatorChar + "test" + File.separatorChar +
"java" + File.separatorChar
def mainAndroidTestSrcPhrase = "src" + File.separatorChar + "androidTest" + File.separatorChar +
"java" + File.separatorChar
def sourceDir = file( "${projectDir}" + File.separatorChar + "src" + File.separatorChar +
"main" + File.separatorChar + "java" + File.separatorChar +
basePackage )
def testSourceDir = file( "${projectDir}" + File.separatorChar + "src" + File.separatorChar +
"test" + File.separatorChar + "java" + File.separatorChar +
basePackage)
def androidTestSourceDir = file( "${projectDir}" + File.separatorChar + "src" + File
.separatorChar +
"androidTest" + File.separatorChar + "java" + File.separatorChar +
basePackage )
generateInfoFiles(sourceDir, mainSrcPhrase);
sourceDir.eachDirRecurse { dir ->
generateInfoFiles(dir, mainSrcPhrase)
}
if (file(testSourceDir).exists()) {
generateInfoFiles(testSourceDir, mainTestSrcPhrase);
testSourceDir.eachDirRecurse { dir ->
generateInfoFiles(dir, mainTestSrcPhrase)
}
}
if (file(androidTestSourceDir).exists()) {
generateInfoFiles(androidTestSourceDir, mainAndroidTestSrcPhrase);
androidTestSourceDir.eachDirRecurse { dir ->
generateInfoFiles(dir, mainAndroidTestSrcPhrase)
}
}
println "[SUCCESS] NonNull generator: package-info.java files checked"
}
private void generateInfoFiles(File dir, String mainSrcPhrase) {
def infoFileContentHeader = getFileContentHeader();
def infoFileContentFooter = getFileContentFooter();
def infoFilePath = dir.getAbsolutePath() + File.separatorChar + "package-info.java"
//file(infoFilePath).delete(); //do not use in production code
if (!file(infoFilePath).exists()) {
def infoFileContentPackage = getFileContentPackage(dir.getAbsolutePath(), mainSrcPhrase);
new File(infoFilePath).write(infoFileContentHeader +
infoFileContentPackage + infoFileContentFooter)
println "[dir] " + infoFilePath + " created";
}
}
def getFileContentPackage(String path, String mainSrcPhrase) {
def mainSrcPhraseIndex = path.indexOf(mainSrcPhrase)
def output = path.substring(mainSrcPhraseIndex)
// Win hotfix
if (System.properties['os.name'].toLowerCase().contains('windows')) {
output = output.replace("\\", "/")
mainSrcPhrase = mainSrcPhrase.replace("\\", "/")
}
return "package " + output.replaceAll(mainSrcPhrase, "").replaceAll(
"/", ".") + ";\n"
}
def getFileContentHeader() {
return "/**\n" +
" * Make all method parameters @NonNull by default.\n" +
" */\n" +
"@NonNullForAll\n"
}
def getFileContentFooter() {
return "\n" +
"import com.wireguard.util.NonNullForAll;\n"
}
@@ -10,6 +10,7 @@ import android.os.AsyncTask;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatDelegate; import android.support.v7.app.AppCompatDelegate;
import com.wireguard.android.backend.Backend; import com.wireguard.android.backend.Backend;
@@ -26,18 +27,19 @@ import java.io.File;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
public class Application extends android.app.Application { public class Application extends android.app.Application {
private static WeakReference<Application> weakSelf; @SuppressWarnings("NullableProblems") private static WeakReference<Application> weakSelf;
private AsyncWorker asyncWorker; @SuppressWarnings("NullableProblems") private AsyncWorker asyncWorker;
private Backend backend; @SuppressWarnings("NullableProblems") private RootShell rootShell;
private RootShell rootShell; @SuppressWarnings("NullableProblems") private SharedPreferences sharedPreferences;
private SharedPreferences sharedPreferences; @SuppressWarnings("NullableProblems") private ToolsInstaller toolsInstaller;
private ToolsInstaller toolsInstaller; @SuppressWarnings("NullableProblems") private TunnelManager tunnelManager;
private TunnelManager tunnelManager; @SuppressWarnings("NullableProblems") private Handler handler;
private Handler handler; @Nullable private Backend backend;
private Collection<BackendCallback> haveBackendCallbacks = new ArrayList<>(); @Nullable private Collection<BackendCallback> haveBackendCallbacks = new ArrayList<>();
private final Object haveBackendCallbacksLock = new Object(); private final Object haveBackendCallbacksLock = new Object();
public Application() { public Application() {
@@ -65,9 +67,11 @@ public class Application extends android.app.Application {
if (app.backend == null) if (app.backend == null)
app.backend = new GoBackend(app.getApplicationContext()); app.backend = new GoBackend(app.getApplicationContext());
synchronized (app.haveBackendCallbacksLock) { synchronized (app.haveBackendCallbacksLock) {
for (final BackendCallback callback : app.haveBackendCallbacks) if (app.haveBackendCallbacks != null) {
app.handler.post(() -> callback.callback(app.backend)); for (final BackendCallback callback : app.haveBackendCallbacks)
app.haveBackendCallbacks = null; app.handler.post(() -> callback.callback(app.backend));
app.haveBackendCallbacks = null;
}
} }
} }
return app.backend; return app.backend;
@@ -82,10 +86,12 @@ public class Application extends android.app.Application {
public static void onHaveBackend(final BackendCallback callback) { public static void onHaveBackend(final BackendCallback callback) {
final Application app = get(); final Application app = get();
synchronized (app.haveBackendCallbacksLock) { synchronized (app.haveBackendCallbacksLock) {
if (app.haveBackendCallbacks == null) if (app.haveBackendCallbacks == null) {
Objects.requireNonNull(app.backend, "Backend still null in onHaveBackend call");
callback.callback(app.backend); callback.callback(app.backend);
else } else {
app.haveBackendCallbacks.add(callback); app.haveBackendCallbacks.add(callback);
}
} }
} }
@@ -12,12 +12,11 @@ import android.databinding.Observable;
import android.databinding.Observable.OnPropertyChangedCallback; import android.databinding.Observable.OnPropertyChangedCallback;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon; import android.graphics.drawable.Icon;
import android.os.Build; import android.os.Build;
import android.service.quicksettings.Tile; import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService; import android.service.quicksettings.TileService;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@@ -41,9 +40,9 @@ public class QuickTileService extends TileService {
private final OnStateChangedCallback onStateChangedCallback = new OnStateChangedCallback(); private final OnStateChangedCallback onStateChangedCallback = new OnStateChangedCallback();
private final OnTunnelChangedCallback onTunnelChangedCallback = new OnTunnelChangedCallback(); private final OnTunnelChangedCallback onTunnelChangedCallback = new OnTunnelChangedCallback();
private Tunnel tunnel; @Nullable private Tunnel tunnel;
private Icon iconOn; @Nullable private Icon iconOn;
private Icon iconOff; @Nullable private Icon iconOff;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Override @Override
@@ -91,7 +90,7 @@ public class QuickTileService extends TileService {
} }
private void onToggleFinished(@SuppressWarnings("unused") final State state, private void onToggleFinished(@SuppressWarnings("unused") final State state,
final Throwable throwable) { @Nullable final Throwable throwable) {
if (throwable == null) if (throwable == null)
return; return;
final String error = ExceptionLoggers.unwrapMessage(throwable); final String error = ExceptionLoggers.unwrapMessage(throwable);
@@ -9,6 +9,7 @@ package com.wireguard.android.activity;
import android.databinding.CallbackRegistry; import android.databinding.CallbackRegistry;
import android.databinding.CallbackRegistry.NotifierCallback; import android.databinding.CallbackRegistry.NotifierCallback;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import com.wireguard.android.Application; import com.wireguard.android.Application;
import com.wireguard.android.model.Tunnel; import com.wireguard.android.model.Tunnel;
@@ -24,19 +25,19 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity {
private static final String KEY_SELECTED_TUNNEL = "selected_tunnel"; private static final String KEY_SELECTED_TUNNEL = "selected_tunnel";
private final SelectionChangeRegistry selectionChangeRegistry = new SelectionChangeRegistry(); private final SelectionChangeRegistry selectionChangeRegistry = new SelectionChangeRegistry();
private Tunnel selectedTunnel; @Nullable private Tunnel selectedTunnel;
public void addOnSelectedTunnelChangedListener( public void addOnSelectedTunnelChangedListener(final OnSelectedTunnelChangedListener listener) {
final OnSelectedTunnelChangedListener listener) {
selectionChangeRegistry.add(listener); selectionChangeRegistry.add(listener);
} }
@Nullable
public Tunnel getSelectedTunnel() { public Tunnel getSelectedTunnel() {
return selectedTunnel; return selectedTunnel;
} }
@Override @Override
protected void onCreate(final Bundle savedInstanceState) { protected void onCreate(@Nullable final Bundle savedInstanceState) {
// Restore the saved tunnel if there is one; otherwise grab it from the arguments. // Restore the saved tunnel if there is one; otherwise grab it from the arguments.
String savedTunnelName = null; String savedTunnelName = null;
if (savedInstanceState != null) if (savedInstanceState != null)
@@ -59,14 +60,14 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
protected abstract void onSelectedTunnelChanged(Tunnel oldTunnel, Tunnel newTunnel); protected abstract void onSelectedTunnelChanged(@Nullable Tunnel oldTunnel, @Nullable Tunnel newTunnel);
public void removeOnSelectedTunnelChangedListener( public void removeOnSelectedTunnelChangedListener(
final OnSelectedTunnelChangedListener listener) { final OnSelectedTunnelChangedListener listener) {
selectionChangeRegistry.remove(listener); selectionChangeRegistry.remove(listener);
} }
public void setSelectedTunnel(final Tunnel tunnel) { public void setSelectedTunnel(@Nullable final Tunnel tunnel) {
final Tunnel oldTunnel = selectedTunnel; final Tunnel oldTunnel = selectedTunnel;
if (Objects.equals(oldTunnel, tunnel)) if (Objects.equals(oldTunnel, tunnel))
return; return;
@@ -76,7 +77,7 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity {
} }
public interface OnSelectedTunnelChangedListener { public interface OnSelectedTunnelChangedListener {
void onSelectedTunnelChanged(Tunnel oldTunnel, Tunnel newTunnel); void onSelectedTunnelChanged(@Nullable Tunnel oldTunnel, @Nullable Tunnel newTunnel);
} }
private static final class SelectionChangeNotifier private static final class SelectionChangeNotifier
@@ -9,6 +9,7 @@ package com.wireguard.android.activity;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
@@ -22,6 +23,8 @@ import com.wireguard.android.fragment.TunnelEditorFragment;
import com.wireguard.android.fragment.TunnelListFragment; import com.wireguard.android.fragment.TunnelListFragment;
import com.wireguard.android.model.Tunnel; import com.wireguard.android.model.Tunnel;
import java.util.List;
import java9.util.stream.Stream; import java9.util.stream.Stream;
/** /**
@@ -33,6 +36,7 @@ import java9.util.stream.Stream;
public class MainActivity extends BaseActivity { public class MainActivity extends BaseActivity {
private static final String KEY_STATE = "fragment_state"; private static final String KEY_STATE = "fragment_state";
private static final String TAG = "WireGuard/" + MainActivity.class.getSimpleName(); private static final String TAG = "WireGuard/" + MainActivity.class.getSimpleName();
private State state = State.EMPTY; private State state = State.EMPTY;
private boolean moveToState(final State nextState) { private boolean moveToState(final State nextState) {
@@ -70,13 +74,19 @@ public class MainActivity extends BaseActivity {
@Override @Override
public void onBackPressed() { public void onBackPressed() {
TunnelListFragment fragment = null; final List<Fragment> fragments = getSupportFragmentManager().getFragments();
try {
fragment = ((TunnelListFragment) getSupportFragmentManager().getFragments().get(0)); boolean handled = false;
} catch (final ClassCastException ignored) { } if (!fragments.isEmpty() && fragments.get(0) instanceof TunnelListFragment) {
if (fragment == null || !fragment.collapseActionMenu()) { handled = ((TunnelListFragment) fragments.get(0)).collapseActionMenu();
if (!moveToState(State.ofLayer(state.layer - 1))) }
super.onBackPressed();
if (!handled) {
handled = moveToState(State.ofLayer(state.layer - 1));
}
if (!handled) {
super.onBackPressed();
} }
} }
@@ -84,7 +94,7 @@ public class MainActivity extends BaseActivity {
// calling View#performClick defeats the purpose of it. // calling View#performClick defeats the purpose of it.
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
protected void onCreate(final Bundle savedInstanceState) { protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity); setContentView(R.layout.main_activity);
if (savedInstanceState != null && savedInstanceState.getString(KEY_STATE) != null) if (savedInstanceState != null && savedInstanceState.getString(KEY_STATE) != null)
@@ -99,9 +109,10 @@ public class MainActivity extends BaseActivity {
final int actionBarId = getResources().getIdentifier("action_bar", "id", getPackageName()); final int actionBarId = getResources().getIdentifier("action_bar", "id", getPackageName());
if (actionBarId != 0 && findViewById(actionBarId) != null) { if (actionBarId != 0 && findViewById(actionBarId) != null) {
findViewById(actionBarId).setOnTouchListener((v, e) -> { findViewById(actionBarId).setOnTouchListener((v, e) -> {
try { final List<Fragment> fragments = getSupportFragmentManager().getFragments();
((TunnelListFragment) getSupportFragmentManager().getFragments().get(0)).collapseActionMenu(); if (!fragments.isEmpty() && fragments.get(0) instanceof TunnelListFragment) {
} catch (final ClassCastException ignored) { } ((TunnelListFragment) fragments.get(0)).collapseActionMenu();
}
return false; return false;
}); });
} }
@@ -142,7 +153,7 @@ public class MainActivity extends BaseActivity {
} }
@Override @Override
protected void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) { protected void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
moveToState(newTunnel != null ? State.DETAIL : State.LIST); moveToState(newTunnel != null ? State.DETAIL : State.LIST);
} }
@@ -157,10 +168,10 @@ public class MainActivity extends BaseActivity {
DETAIL(TunnelDetailFragment.class, 2), DETAIL(TunnelDetailFragment.class, 2),
EDITOR(TunnelEditorFragment.class, 3); EDITOR(TunnelEditorFragment.class, 3);
private final String fragment; @Nullable private final String fragment;
private final int layer; private final int layer;
State(final Class<? extends Fragment> fragment, final int layer) { State(@Nullable final Class<? extends Fragment> fragment, final int layer) {
this.fragment = fragment != null ? fragment.getName() : null; this.fragment = fragment != null ? fragment.getName() : null;
this.layer = layer; this.layer = layer;
} }
@@ -8,12 +8,13 @@ package com.wireguard.android.activity;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat; import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.util.SparseArray;
import android.view.MenuItem; import android.view.MenuItem;
import com.wireguard.android.Application; import com.wireguard.android.Application;
@@ -22,16 +23,14 @@ import com.wireguard.android.backend.WgQuickBackend;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Interface for changing application-global persistent settings. * Interface for changing application-global persistent settings.
*/ */
public class SettingsActivity extends ThemeChangeAwareActivity { public class SettingsActivity extends ThemeChangeAwareActivity {
private final Map<Integer, PermissionRequestCallback> permissionRequestCallbacks = new HashMap<>(); private final SparseArray<PermissionRequestCallback> permissionRequestCallbacks = new SparseArray<>();
private int permissionRequestCounter; private int permissionRequestCounter;
public void ensurePermissions(final String[] permissions, final PermissionRequestCallback cb) { public void ensurePermissions(final String[] permissions, final PermissionRequestCallback cb) {
@@ -54,7 +53,7 @@ public class SettingsActivity extends ThemeChangeAwareActivity {
} }
@Override @Override
protected void onCreate(final Bundle savedInstanceState) { protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) { if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
@@ -76,8 +75,8 @@ public class SettingsActivity extends ThemeChangeAwareActivity {
@Override @Override
public void onRequestPermissionsResult(final int requestCode, public void onRequestPermissionsResult(final int requestCode,
@NonNull final String[] permissions, final String[] permissions,
@NonNull final int[] grantResults) { final int[] grantResults) {
final PermissionRequestCallback f = permissionRequestCallbacks.get(requestCode); final PermissionRequestCallback f = permissionRequestCallbacks.get(requestCode);
if (f != null) { if (f != null) {
permissionRequestCallbacks.remove(requestCode); permissionRequestCallbacks.remove(requestCode);
@@ -8,6 +8,7 @@ package com.wireguard.android.activity;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate; import android.support.v7.app.AppCompatDelegate;
import android.util.Log; import android.util.Log;
@@ -19,7 +20,7 @@ import java.lang.reflect.Field;
public abstract class ThemeChangeAwareActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { public abstract class ThemeChangeAwareActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "WireGuard/" + ThemeChangeAwareActivity.class.getSimpleName(); private static final String TAG = "WireGuard/" + ThemeChangeAwareActivity.class.getSimpleName();
private static Resources lastResources; @Nullable private static Resources lastResources;
private static boolean lastDarkMode; private static boolean lastDarkMode;
private static synchronized void invalidateDrawableCache(final Resources resources, final boolean darkMode) { private static synchronized void invalidateDrawableCache(final Resources resources, final boolean darkMode) {
if (resources == lastResources && darkMode == lastDarkMode) if (resources == lastResources && darkMode == lastDarkMode)
@@ -51,7 +52,7 @@ public abstract class ThemeChangeAwareActivity extends AppCompatActivity impleme
@Override @Override
protected void onCreate(final Bundle savedInstanceState) { protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this); Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
} }
@@ -7,6 +7,7 @@
package com.wireguard.android.activity; package com.wireguard.android.activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import com.wireguard.android.fragment.TunnelEditorFragment; import com.wireguard.android.fragment.TunnelEditorFragment;
import com.wireguard.android.model.Tunnel; import com.wireguard.android.model.Tunnel;
@@ -18,7 +19,7 @@ import com.wireguard.android.model.Tunnel;
public class TunnelCreatorActivity extends BaseActivity { public class TunnelCreatorActivity extends BaseActivity {
@Override @Override
@SuppressWarnings("UnnecessaryFullyQualifiedName") @SuppressWarnings("UnnecessaryFullyQualifiedName")
protected void onCreate(final Bundle savedInstanceState) { protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) { if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
@@ -28,7 +29,7 @@ public class TunnelCreatorActivity extends BaseActivity {
} }
@Override @Override
protected void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) { protected void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
finish(); finish();
} }
} }
@@ -10,6 +10,7 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.support.annotation.Nullable;
import android.support.v4.util.ArraySet; import android.support.v4.util.ArraySet;
import android.util.Log; import android.util.Log;
@@ -29,6 +30,7 @@ import com.wireguard.crypto.KeyEncoding;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Collections; import java.util.Collections;
import java.util.Formatter; import java.util.Formatter;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@@ -40,7 +42,7 @@ public final class GoBackend implements Backend {
private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>(); private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>();
private final Context context; private final Context context;
private Tunnel currentTunnel; @Nullable private Tunnel currentTunnel;
private int currentTunnelHandle = -1; private int currentTunnelHandle = -1;
public GoBackend(final Context context) { public GoBackend(final Context context) {
@@ -114,12 +116,14 @@ public final class GoBackend implements Backend {
return getState(tunnel); return getState(tunnel);
} }
private void setStateInternal(final Tunnel tunnel, final Config config, final State state) private void setStateInternal(final Tunnel tunnel, @Nullable final Config config, final State state)
throws Exception { throws Exception {
if (state == State.UP) { if (state == State.UP) {
Log.i(TAG, "Bringing tunnel up"); Log.i(TAG, "Bringing tunnel up");
Objects.requireNonNull(config, "Trying to bring up a tunnel with no config");
if (VpnService.prepare(context) != null) if (VpnService.prepare(context) != null)
throw new Exception("VPN service not authorized by user"); throw new Exception("VPN service not authorized by user");
@@ -245,7 +249,7 @@ public final class GoBackend implements Backend {
} }
@Override @Override
public int onStartCommand(final Intent intent, final int flags, final int startId) { public int onStartCommand(@Nullable final Intent intent, final int flags, final int startId) {
vpnService.complete(this); vpnService.complete(this);
if (intent == null || intent.getComponent() == null || !intent.getComponent().getPackageName().equals(getPackageName())) { if (intent == null || intent.getComponent() == null || !intent.getComponent().getPackageName().equals(getPackageName())) {
Log.d(TAG, "Service started by Always-on VPN feature"); Log.d(TAG, "Service started by Always-on VPN feature");
@@ -7,6 +7,7 @@
package com.wireguard.android.backend; package com.wireguard.android.backend;
import android.content.Context; import android.content.Context;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import com.wireguard.android.Application; import com.wireguard.android.Application;
@@ -21,6 +22,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java9.util.stream.Collectors; import java9.util.stream.Collectors;
@@ -106,8 +108,9 @@ public final class WgQuickBackend implements Backend {
return getState(tunnel); return getState(tunnel);
} }
private void setStateInternal(final Tunnel tunnel, final Config config, final State state) private void setStateInternal(final Tunnel tunnel, @Nullable final Config config, final State state) throws Exception {
throws Exception { Objects.requireNonNull(config, "Trying to set state with a null config");
final File tempFile = new File(localTemporaryDir, tunnel.getName() + ".conf"); final File tempFile = new File(localTemporaryDir, tunnel.getName() + ".conf");
try (final FileOutputStream stream = new FileOutputStream(tempFile, false)) { try (final FileOutputStream stream = new FileOutputStream(tempFile, false)) {
stream.write(config.toString().getBytes(StandardCharsets.UTF_8)); stream.write(config.toString().getBytes(StandardCharsets.UTF_8));
@@ -9,6 +9,7 @@ package com.wireguard.android.databinding;
import android.databinding.DataBindingUtil; import android.databinding.DataBindingUtil;
import android.databinding.ObservableList; import android.databinding.ObservableList;
import android.databinding.ViewDataBinding; import android.databinding.ViewDataBinding;
import android.support.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -16,6 +17,7 @@ import android.view.ViewGroup;
import com.wireguard.android.BR; import com.wireguard.android.BR;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects;
/** /**
* Helper class for binding an ObservableList to the children of a ViewGroup. * Helper class for binding an ObservableList to the children of a ViewGroup.
@@ -26,7 +28,7 @@ class ItemChangeListener<T> {
private final ViewGroup container; private final ViewGroup container;
private final int layoutId; private final int layoutId;
private final LayoutInflater layoutInflater; private final LayoutInflater layoutInflater;
private ObservableList<T> list; @Nullable private ObservableList<T> list;
ItemChangeListener(final ViewGroup container, final int layoutId) { ItemChangeListener(final ViewGroup container, final int layoutId) {
this.container = container; this.container = container;
@@ -34,17 +36,21 @@ class ItemChangeListener<T> {
layoutInflater = LayoutInflater.from(container.getContext()); layoutInflater = LayoutInflater.from(container.getContext());
} }
private View getView(final int position, final View convertView) { private View getView(final int position, @Nullable final View convertView) {
ViewDataBinding binding = DataBindingUtil.getBinding(convertView); ViewDataBinding binding = convertView != null ? DataBindingUtil.getBinding(convertView) : null;
if (binding == null) if (binding == null) {
binding = DataBindingUtil.inflate(layoutInflater, layoutId, container, false); binding = DataBindingUtil.inflate(layoutInflater, layoutId, container, false);
}
Objects.requireNonNull(list, "Trying to get a view while list is still null");
binding.setVariable(BR.collection, list); binding.setVariable(BR.collection, list);
binding.setVariable(BR.item, list.get(position)); binding.setVariable(BR.item, list.get(position));
binding.executePendingBindings(); binding.executePendingBindings();
return binding.getRoot(); return binding.getRoot();
} }
void setList(final ObservableList<T> newList) { void setList(@Nullable final ObservableList<T> newList) {
if (list != null) if (list != null)
list.removeOnListChangedCallback(callback); list.removeOnListChangedCallback(callback);
list = newList; list = newList;
@@ -10,7 +10,7 @@ import android.content.Context;
import android.databinding.DataBindingUtil; import android.databinding.DataBindingUtil;
import android.databinding.ObservableList; import android.databinding.ObservableList;
import android.databinding.ViewDataBinding; import android.databinding.ViewDataBinding;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter; import android.support.v7.widget.RecyclerView.Adapter;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -31,8 +31,8 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
private final OnListChangedCallback<E> callback = new OnListChangedCallback<>(this); private final OnListChangedCallback<E> callback = new OnListChangedCallback<>(this);
private final int layoutId; private final int layoutId;
private final LayoutInflater layoutInflater; private final LayoutInflater layoutInflater;
private ObservableKeyedList<K, E> list; @Nullable private ObservableKeyedList<K, E> list;
private RowConfigurationHandler rowConfigurationHandler; @Nullable private RowConfigurationHandler rowConfigurationHandler;
ObservableKeyedRecyclerViewAdapter(final Context context, final int layoutId, ObservableKeyedRecyclerViewAdapter(final Context context, final int layoutId,
final ObservableKeyedList<K, E> list) { final ObservableKeyedList<K, E> list) {
@@ -46,6 +46,7 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
return list != null ? list.size() : 0; return list != null ? list.size() : 0;
} }
@Nullable
private E getItem(final int position) { private E getItem(final int position) {
if (list == null || position < 0 || position >= list.size()) if (list == null || position < 0 || position >= list.size())
return null; return null;
@@ -58,30 +59,34 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
return key != null ? key.hashCode() : -1; return key != null ? key.hashCode() : -1;
} }
@Nullable
private K getKey(final int position) { private K getKey(final int position) {
final E item = getItem(position); final E item = getItem(position);
return item != null ? item.getKey() : null; return item != null ? item.getKey() : null;
} }
@NonNull @Override @Override
public ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
return new ViewHolder(DataBindingUtil.inflate(layoutInflater, layoutId, parent, false)); return new ViewHolder(DataBindingUtil.inflate(layoutInflater, layoutId, parent, false));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) { public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.binding.setVariable(BR.collection, list); holder.binding.setVariable(BR.collection, list);
holder.binding.setVariable(BR.key, getKey(position)); holder.binding.setVariable(BR.key, getKey(position));
holder.binding.setVariable(BR.item, getItem(position)); holder.binding.setVariable(BR.item, getItem(position));
holder.binding.executePendingBindings(); holder.binding.executePendingBindings();
if (rowConfigurationHandler != null) { if (rowConfigurationHandler != null) {
rowConfigurationHandler.onConfigureRow(holder.binding, getItem(position), position); E item = getItem(position);
if (item != null) {
rowConfigurationHandler.onConfigureRow(holder.binding, item, position);
}
} }
} }
void setList(final ObservableKeyedList<K, E> newList) { void setList(@Nullable final ObservableKeyedList<K, E> newList) {
if (list != null) if (list != null)
list.removeOnListChangedCallback(callback); list.removeOnListChangedCallback(callback);
list = newList; list = newList;
@@ -39,7 +39,7 @@ public class AppListDialogFragment extends DialogFragment {
private static final String KEY_EXCLUDED_APPS = "excludedApps"; private static final String KEY_EXCLUDED_APPS = "excludedApps";
private List<String> currentlyExcludedApps; private final List<String> currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
private final ObservableKeyedList<String, ApplicationData> appData = new ObservableKeyedArrayList<>(); private final ObservableKeyedList<String, ApplicationData> appData = new ObservableKeyedArrayList<>();
public static <T extends Fragment & AppExclusionListener> AppListDialogFragment newInstance(final String[] excludedApps, final T target) { public static <T extends Fragment & AppExclusionListener> AppListDialogFragment newInstance(final String[] excludedApps, final T target) {
@@ -51,24 +51,12 @@ public class AppListDialogFragment extends DialogFragment {
return fragment; return fragment;
} }
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
}
@Override
public void onAttach(final Context context) {
super.onAttach(context);
}
@Override @Override
public Dialog onCreateDialog(final Bundle savedInstanceState) { public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity()); final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setTitle(R.string.excluded_applications); alertDialogBuilder.setTitle(R.string.excluded_applications);
AppListDialogFragmentBinding binding = AppListDialogFragmentBinding.inflate(getActivity().getLayoutInflater(), null, false); final AppListDialogFragmentBinding binding = AppListDialogFragmentBinding.inflate(getActivity().getLayoutInflater(), null, false);
binding.executePendingBindings(); binding.executePendingBindings();
alertDialogBuilder.setView(binding.getRoot()); alertDialogBuilder.setView(binding.getRoot());
@@ -10,7 +10,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.databinding.DataBindingUtil; import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding; import android.databinding.ViewDataBinding;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.Log; import android.util.Log;
@@ -37,10 +37,11 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
private static final String TAG = "WireGuard/" + BaseFragment.class.getSimpleName(); private static final String TAG = "WireGuard/" + BaseFragment.class.getSimpleName();
private static final int REQUEST_CODE_VPN_PERMISSION = 23491; private static final int REQUEST_CODE_VPN_PERMISSION = 23491;
private BaseActivity activity; @Nullable private BaseActivity activity;
private Tunnel pendingTunnel; @Nullable private Tunnel pendingTunnel;
private Boolean pendingTunnelUp; @Nullable private Boolean pendingTunnelUp;
@Nullable
protected Tunnel getSelectedTunnel() { protected Tunnel getSelectedTunnel() {
return activity != null ? activity.getSelectedTunnel() : null; return activity != null ? activity.getSelectedTunnel() : null;
} }
@@ -65,7 +66,7 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
} }
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_VPN_PERMISSION) { if (requestCode == REQUEST_CODE_VPN_PERMISSION) {
@@ -76,7 +77,7 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
} }
} }
protected void setSelectedTunnel(final Tunnel tunnel) { protected void setSelectedTunnel(@Nullable final Tunnel tunnel) {
if (activity != null) if (activity != null)
activity.setSelectedTunnel(tunnel); activity.setSelectedTunnel(tunnel);
} }
@@ -106,7 +107,7 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
}); });
} }
private void setTunnelStateWithPermissionsResult(@NonNull final Tunnel tunnel, final boolean checked) { private void setTunnelStateWithPermissionsResult(final Tunnel tunnel, final boolean checked) {
tunnel.setState(State.of(checked)).whenComplete((state, throwable) -> { tunnel.setState(State.of(checked)).whenComplete((state, throwable) -> {
if (throwable == null) if (throwable == null)
return; return;
@@ -7,7 +7,7 @@
package com.wireguard.android.fragment; package com.wireguard.android.fragment;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -24,14 +24,16 @@ import com.wireguard.config.Config;
*/ */
public class TunnelDetailFragment extends BaseFragment { public class TunnelDetailFragment extends BaseFragment {
private TunnelDetailFragmentBinding binding; @Nullable private TunnelDetailFragmentBinding binding;
private void onConfigLoaded(final String name, final Config config) { private void onConfigLoaded(final String name, final Config config) {
binding.setConfig(new Config.Observable(config, name)); if (binding != null) {
binding.setConfig(new Config.Observable(config, name));
}
} }
@Override @Override
public void onCreate(final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@@ -42,8 +44,8 @@ public class TunnelDetailFragment extends BaseFragment {
} }
@Override @Override
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
final Bundle savedInstanceState) { @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState); super.onCreateView(inflater, container, savedInstanceState);
binding = TunnelDetailFragmentBinding.inflate(inflater, container, false); binding = TunnelDetailFragmentBinding.inflate(inflater, container, false);
binding.executePendingBindings(); binding.executePendingBindings();
@@ -57,7 +59,7 @@ public class TunnelDetailFragment extends BaseFragment {
} }
@Override @Override
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) { public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
if (binding == null) if (binding == null)
return; return;
binding.setTunnel(newTunnel); binding.setTunnel(newTunnel);
@@ -68,7 +70,11 @@ public class TunnelDetailFragment extends BaseFragment {
} }
@Override @Override
public void onViewStateRestored(final Bundle savedInstanceState) { public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
if (binding == null) {
return;
}
binding.setFragment(this); binding.setFragment(this);
onSelectedTunnelChanged(null, getSelectedTunnel()); onSelectedTunnelChanged(null, getSelectedTunnel());
super.onViewStateRestored(savedInstanceState); super.onViewStateRestored(savedInstanceState);
@@ -11,7 +11,7 @@ import android.content.Context;
import android.databinding.Observable; import android.databinding.Observable;
import android.databinding.ObservableList; import android.databinding.ObservableList;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.util.Log; import android.util.Log;
@@ -37,6 +37,7 @@ import com.wireguard.config.Config;
import com.wireguard.config.Peer; import com.wireguard.config.Peer;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Fragment for editing a WireGuard configuration. * Fragment for editing a WireGuard configuration.
@@ -47,15 +48,17 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
private static final String KEY_ORIGINAL_NAME = "original_name"; private static final String KEY_ORIGINAL_NAME = "original_name";
private static final String TAG = "WireGuard/" + TunnelEditorFragment.class.getSimpleName(); private static final String TAG = "WireGuard/" + TunnelEditorFragment.class.getSimpleName();
private TunnelEditorFragmentBinding binding; @Nullable private TunnelEditorFragmentBinding binding;
private Tunnel tunnel; @Nullable private Tunnel tunnel;
private void onConfigLoaded(final String name, final Config config) { private void onConfigLoaded(final String name, final Config config) {
binding.setConfig(new Config.Observable(config, name)); if (binding != null) {
binding.setConfig(new Config.Observable(config, name));
}
} }
private void onConfigSaved(final Tunnel savedTunnel, private void onConfigSaved(final Tunnel savedTunnel,
final Throwable throwable) { @Nullable final Throwable throwable) {
final String message; final String message;
if (throwable == null) { if (throwable == null) {
message = getString(R.string.config_save_success, savedTunnel.getName()); message = getString(R.string.config_save_success, savedTunnel.getName());
@@ -73,7 +76,7 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
} }
@Override @Override
public void onCreate(final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@@ -124,8 +127,8 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
}; };
@Override @Override
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
final Bundle savedInstanceState) { @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState); super.onCreateView(inflater, container, savedInstanceState);
binding = TunnelEditorFragmentBinding.inflate(inflater, container, false); binding = TunnelEditorFragmentBinding.inflate(inflater, container, false);
binding.addOnPropertyChangedCallback(breakObjectOrientedLayeringHandler); binding.addOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
@@ -197,14 +200,14 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
} }
@Override @Override
public void onSaveInstanceState(@NonNull final Bundle outState) { public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(KEY_LOCAL_CONFIG, binding.getConfig()); outState.putParcelable(KEY_LOCAL_CONFIG, binding.getConfig());
outState.putString(KEY_ORIGINAL_NAME, tunnel == null ? null : tunnel.getName()); outState.putString(KEY_ORIGINAL_NAME, tunnel == null ? null : tunnel.getName());
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
@Override @Override
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) { public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
tunnel = newTunnel; tunnel = newTunnel;
if (binding == null) if (binding == null)
return; return;
@@ -213,7 +216,7 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
tunnel.getConfigAsync().thenAccept(a -> onConfigLoaded(tunnel.getName(), a)); tunnel.getConfigAsync().thenAccept(a -> onConfigLoaded(tunnel.getName(), a));
} }
private void onTunnelCreated(final Tunnel newTunnel, final Throwable throwable) { private void onTunnelCreated(final Tunnel newTunnel, @Nullable final Throwable throwable) {
final String message; final String message;
if (throwable == null) { if (throwable == null) {
tunnel = newTunnel; tunnel = newTunnel;
@@ -232,7 +235,7 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
} }
private void onTunnelRenamed(final Tunnel renamedTunnel, final Config newConfig, private void onTunnelRenamed(final Tunnel renamedTunnel, final Config newConfig,
final Throwable throwable) { @Nullable final Throwable throwable) {
final String message; final String message;
if (throwable == null) { if (throwable == null) {
message = getString(R.string.tunnel_rename_success, renamedTunnel.getName()); message = getString(R.string.tunnel_rename_success, renamedTunnel.getName());
@@ -251,7 +254,11 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
} }
@Override @Override
public void onViewStateRestored(final Bundle savedInstanceState) { public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
if (binding == null) {
return;
}
binding.setFragment(this); binding.setFragment(this);
if (savedInstanceState == null) { if (savedInstanceState == null) {
@@ -271,15 +278,16 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
public void onRequestSetExcludedApplications(@SuppressWarnings("unused") final View view) { public void onRequestSetExcludedApplications(@SuppressWarnings("unused") final View view) {
final FragmentManager fragmentManager = getFragmentManager(); final FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) { if (fragmentManager != null && binding != null) {
final String[] excludedApps = Attribute.stringToList(binding.getConfig().getInterfaceSection().getExcludedApplications()); final String[] excludedApps = Attribute.stringToList(binding.getConfig().getInterfaceSection().getExcludedApplications());
final AppListDialogFragment fragment = AppListDialogFragment.newInstance(excludedApps, this); final AppListDialogFragment fragment = AppListDialogFragment.newInstance(excludedApps, this);
fragment.show(getFragmentManager(), null); fragment.show(fragmentManager, null);
} }
} }
@Override @Override
public void onExcludedAppsSelected(final List<String> excludedApps) { 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)); binding.getConfig().getInterfaceSection().setExcludedApplications(Attribute.iterableToString(excludedApps));
} }
@@ -15,7 +15,6 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
@@ -60,20 +59,20 @@ public class TunnelListFragment extends BaseFragment {
private static final String TAG = "WireGuard/" + TunnelListFragment.class.getSimpleName(); private static final String TAG = "WireGuard/" + TunnelListFragment.class.getSimpleName();
private final ActionModeListener actionModeListener = new ActionModeListener(); private final ActionModeListener actionModeListener = new ActionModeListener();
private ActionMode actionMode; @Nullable private ActionMode actionMode;
private TunnelListFragmentBinding binding; @Nullable private TunnelListFragmentBinding binding;
public boolean collapseActionMenu() { public boolean collapseActionMenu() {
if (binding.createMenu.isExpanded()) { if (binding != null && binding.createMenu.isExpanded()) {
binding.createMenu.collapse(); binding.createMenu.collapse();
return true; return true;
} }
return false; return false;
} }
private void importTunnel(final Uri uri) { private void importTunnel(@Nullable final Uri uri) {
final Activity activity = getActivity(); final Activity activity = getActivity();
if (activity == null) if (activity == null || uri == null)
return; return;
final ContentResolver contentResolver = activity.getContentResolver(); final ContentResolver contentResolver = activity.getContentResolver();
@@ -165,10 +164,10 @@ public class TunnelListFragment extends BaseFragment {
} }
@Override @Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
switch (requestCode) { switch (requestCode) {
case REQUEST_IMPORT: case REQUEST_IMPORT:
if (resultCode == Activity.RESULT_OK) if (resultCode == Activity.RESULT_OK && data != null)
importTunnel(data.getData()); importTunnel(data.getData());
return; return;
default: default:
@@ -178,8 +177,8 @@ public class TunnelListFragment extends BaseFragment {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
final Bundle savedInstanceState) { @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState); super.onCreateView(inflater, container, savedInstanceState);
binding = TunnelListFragmentBinding.inflate(inflater, container, false); binding = TunnelListFragmentBinding.inflate(inflater, container, false);
@@ -216,16 +215,18 @@ public class TunnelListFragment extends BaseFragment {
@Override @Override
public void onPause() { public void onPause() {
binding.createMenu.collapse(); if (binding != null) {
binding.createMenu.collapse();
}
super.onPause(); super.onPause();
} }
@Override @Override
public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) { public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
// Do nothing. // Do nothing.
} }
private void onTunnelDeletionFinished(final Integer count, final Throwable throwable) { private void onTunnelDeletionFinished(final Integer count, @Nullable final Throwable throwable) {
final String message; final String message;
if (throwable == null) { if (throwable == null) {
message = getResources().getQuantityString(R.plurals.delete_success, count, count); message = getResources().getQuantityString(R.plurals.delete_success, count, count);
@@ -265,8 +266,13 @@ public class TunnelListFragment extends BaseFragment {
} }
@Override @Override
public void onViewStateRestored(final Bundle savedInstanceState) { public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState); super.onViewStateRestored(savedInstanceState);
if (binding == null) {
return;
}
binding.setFragment(this); binding.setFragment(this);
binding.setTunnels(Application.getTunnelManager().getTunnels()); binding.setTunnels(Application.getTunnelManager().getTunnels());
binding.setRowConfigurationHandler((ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<TunnelListItemBinding, Tunnel>) (binding, tunnel, position) -> { binding.setRowConfigurationHandler((ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<TunnelListItemBinding, Tunnel>) (binding, tunnel, position) -> {
@@ -290,7 +296,7 @@ public class TunnelListFragment extends BaseFragment {
private final class ActionModeListener implements ActionMode.Callback { private final class ActionModeListener implements ActionMode.Callback {
private final Collection<Integer> checkedItems = new HashSet<>(); private final Collection<Integer> checkedItems = new HashSet<>();
private Resources resources; @Nullable private Resources resources;
@Override @Override
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
@@ -357,7 +363,9 @@ public class TunnelListFragment extends BaseFragment {
actionMode.finish(); actionMode.finish();
} }
binding.tunnelList.getAdapter().notifyItemChanged(position); if (binding != null) {
binding.tunnelList.getAdapter().notifyItemChanged(position);
}
updateTitle(actionMode); updateTitle(actionMode);
} }
@@ -9,36 +9,32 @@ package com.wireguard.android.model;
import android.databinding.BaseObservable; import android.databinding.BaseObservable;
import android.databinding.Bindable; import android.databinding.Bindable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import com.wireguard.android.BR; import com.wireguard.android.BR;
import com.wireguard.util.Keyed; import com.wireguard.util.Keyed;
public class ApplicationData extends BaseObservable implements Keyed<String> { public class ApplicationData extends BaseObservable implements Keyed<String> {
@NonNull private final Drawable icon; private final Drawable icon;
@NonNull private final String name; private final String name;
@NonNull private final String packageName; private final String packageName;
private boolean excludedFromTunnel; private boolean excludedFromTunnel;
public ApplicationData(@NonNull final Drawable icon, @NonNull final String name, @NonNull final String packageName, final boolean excludedFromTunnel) { public ApplicationData(final Drawable icon, final String name, final String packageName, final boolean excludedFromTunnel) {
this.icon = icon; this.icon = icon;
this.name = name; this.name = name;
this.packageName = packageName; this.packageName = packageName;
this.excludedFromTunnel = excludedFromTunnel; this.excludedFromTunnel = excludedFromTunnel;
} }
@NonNull
public Drawable getIcon() { public Drawable getIcon() {
return icon; return icon;
} }
@NonNull
public String getName() { public String getName() {
return name; return name;
} }
@NonNull
public String getPackageName() { public String getPackageName() {
return packageName; return packageName;
} }
@@ -8,13 +8,12 @@ package com.wireguard.android.model;
import android.databinding.BaseObservable; import android.databinding.BaseObservable;
import android.databinding.Bindable; import android.databinding.Bindable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.wireguard.android.BR; import com.wireguard.android.BR;
import com.wireguard.android.util.ExceptionLoggers; import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.util.Keyed;
import com.wireguard.config.Config; import com.wireguard.config.Config;
import com.wireguard.util.Keyed;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -30,20 +29,20 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,15}"); private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,15}");
private final TunnelManager manager; private final TunnelManager manager;
private Config config; @Nullable private Config config;
private String name; private String name;
private State state; private State state;
private Statistics statistics; @Nullable private Statistics statistics;
Tunnel(@NonNull final TunnelManager manager, @NonNull final String name, Tunnel(final TunnelManager manager, final String name,
@Nullable final Config config, @NonNull final State state) { @Nullable final Config config, final State state) {
this.manager = manager; this.manager = manager;
this.name = name; this.name = name;
this.config = config; this.config = config;
this.state = state; this.state = state;
} }
public static boolean isNameInvalid(@NonNull final CharSequence name) { public static boolean isNameInvalid(final CharSequence name) {
return !NAME_PATTERN.matcher(name).matches(); return !NAME_PATTERN.matcher(name).matches();
} }
@@ -51,7 +50,7 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
return manager.delete(this); return manager.delete(this);
} }
@Bindable @Bindable @Nullable
public Config getConfig() { public Config getConfig() {
if (config == null) if (config == null)
manager.getTunnelConfig(this).whenComplete(ExceptionLoggers.E); manager.getTunnelConfig(this).whenComplete(ExceptionLoggers.E);
@@ -83,7 +82,7 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
return TunnelManager.getTunnelState(this); return TunnelManager.getTunnelState(this);
} }
@Bindable @Bindable @Nullable
public Statistics getStatistics() { public Statistics getStatistics() {
// FIXME: Check age of statistics. // FIXME: Check age of statistics.
if (statistics == null) if (statistics == null)
@@ -118,25 +117,26 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
return state; return state;
} }
Statistics onStatisticsChanged(final Statistics statistics) { @Nullable
Statistics onStatisticsChanged(@Nullable final Statistics statistics) {
this.statistics = statistics; this.statistics = statistics;
notifyPropertyChanged(BR.statistics); notifyPropertyChanged(BR.statistics);
return statistics; return statistics;
} }
public CompletionStage<Config> setConfig(@NonNull final Config config) { public CompletionStage<Config> setConfig(final Config config) {
if (!config.equals(this.config)) if (!config.equals(this.config))
return manager.setTunnelConfig(this, config); return manager.setTunnelConfig(this, config);
return CompletableFuture.completedFuture(this.config); return CompletableFuture.completedFuture(this.config);
} }
public CompletionStage<String> setName(@NonNull final String name) { public CompletionStage<String> setName(final String name) {
if (!name.equals(this.name)) if (!name.equals(this.name))
return manager.setTunnelName(this, name); return manager.setTunnelName(this, name);
return CompletableFuture.completedFuture(this.name); return CompletableFuture.completedFuture(this.name);
} }
public CompletionStage<State> setState(@NonNull final State state) { public CompletionStage<State> setState(final State state) {
if (state != this.state) if (state != this.state)
return manager.setTunnelState(this, state); return manager.setTunnelState(this, state);
return CompletableFuture.completedFuture(this.state); return CompletableFuture.completedFuture(this.state);
@@ -152,6 +152,5 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
} }
} }
public static class Statistics extends BaseObservable { public static class Statistics extends BaseObservable { }
}
} }
@@ -11,7 +11,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.databinding.BaseObservable; import android.databinding.BaseObservable;
import android.databinding.Bindable; import android.databinding.Bindable;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import com.wireguard.android.Application; import com.wireguard.android.Application;
import com.wireguard.android.BR; import com.wireguard.android.BR;
@@ -47,9 +47,8 @@ public final class TunnelManager extends BaseObservable {
private static final String KEY_RUNNING_TUNNELS = "enabled_configs"; private static final String KEY_RUNNING_TUNNELS = "enabled_configs";
private final ConfigStore configStore; private final ConfigStore configStore;
private final ObservableSortedKeyedList<String, Tunnel> tunnels = private final ObservableSortedKeyedList<String, Tunnel> tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR);
new ObservableSortedKeyedArrayList<>(COMPARATOR); @Nullable private Tunnel lastUsedTunnel;
private Tunnel lastUsedTunnel;
private boolean haveLoaded; private boolean haveLoaded;
private final ArrayList<CompletableFuture<Void>> delayedLoadRestoreTunnels = new ArrayList<>(); private final ArrayList<CompletableFuture<Void>> delayedLoadRestoreTunnels = new ArrayList<>();
@@ -57,13 +56,13 @@ public final class TunnelManager extends BaseObservable {
this.configStore = configStore; this.configStore = configStore;
} }
private Tunnel addToList(final String name, final Config config, final State state) { private Tunnel addToList(final String name, @Nullable final Config config, final State state) {
final Tunnel tunnel = new Tunnel(this, name, config, state); final Tunnel tunnel = new Tunnel(this, name, config, state);
tunnels.add(tunnel); tunnels.add(tunnel);
return tunnel; return tunnel;
} }
public CompletionStage<Tunnel> create(@NonNull final String name, final Config config) { public CompletionStage<Tunnel> create(final String name, @Nullable final Config config) {
if (Tunnel.isNameInvalid(name)) if (Tunnel.isNameInvalid(name))
return CompletableFuture.failedFuture(new IllegalArgumentException("Invalid name")); return CompletableFuture.failedFuture(new IllegalArgumentException("Invalid name"));
if (tunnels.containsKey(name)) { if (tunnels.containsKey(name)) {
@@ -102,7 +101,7 @@ public final class TunnelManager extends BaseObservable {
}); });
} }
@Bindable @Bindable @Nullable
public Tunnel getLastUsedTunnel() { public Tunnel getLastUsedTunnel() {
return lastUsedTunnel; return lastUsedTunnel;
} }
@@ -191,7 +190,7 @@ public final class TunnelManager extends BaseObservable {
Application.getSharedPreferences().edit().putStringSet(KEY_RUNNING_TUNNELS, runningTunnels).apply(); Application.getSharedPreferences().edit().putStringSet(KEY_RUNNING_TUNNELS, runningTunnels).apply();
} }
private void setLastUsedTunnel(final Tunnel tunnel) { private void setLastUsedTunnel(@Nullable final Tunnel tunnel) {
if (tunnel == lastUsedTunnel) if (tunnel == lastUsedTunnel)
return; return;
lastUsedTunnel = tunnel; lastUsedTunnel = tunnel;
@@ -256,7 +255,7 @@ public final class TunnelManager extends BaseObservable {
public static final class IntentReceiver extends BroadcastReceiver { public static final class IntentReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(final Context context, final Intent intent) { public void onReceive(final Context context, @Nullable final Intent intent) {
final TunnelManager manager = Application.getTunnelManager(); final TunnelManager manager = Application.getTunnelManager();
if (intent == null) if (intent == null)
return; return;
@@ -10,6 +10,7 @@ import android.Manifest;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Environment; import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -33,7 +34,7 @@ import java.io.InputStreamReader;
public class LogExporterPreference extends Preference { public class LogExporterPreference extends Preference {
private static final String TAG = "WireGuard/" + LogExporterPreference.class.getSimpleName(); private static final String TAG = "WireGuard/" + LogExporterPreference.class.getSimpleName();
private String exportedFilePath; @Nullable private String exportedFilePath;
public LogExporterPreference(final Context context, final AttributeSet attrs) { public LogExporterPreference(final Context context, final AttributeSet attrs) {
super(context, attrs); super(context, attrs);
@@ -73,7 +74,7 @@ public class LogExporterPreference extends Preference {
}).whenComplete(this::exportLogComplete); }).whenComplete(this::exportLogComplete);
} }
private void exportLogComplete(final String filePath, final Throwable throwable) { private void exportLogComplete(final String filePath, @Nullable final Throwable throwable) {
if (throwable != null) { if (throwable != null) {
final String error = ExceptionLoggers.unwrapMessage(throwable); final String error = ExceptionLoggers.unwrapMessage(throwable);
final String message = getContext().getString(R.string.log_export_error, error); final String message = getContext().getString(R.string.log_export_error, error);
@@ -7,7 +7,7 @@
package com.wireguard.android.preference; package com.wireguard.android.preference;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -43,7 +43,7 @@ public class ToolsInstallerPreference extends Preference {
Application.getAsyncWorker().supplyAsync(Application.getToolsInstaller()::areInstalled).whenComplete(this::onCheckResult); Application.getAsyncWorker().supplyAsync(Application.getToolsInstaller()::areInstalled).whenComplete(this::onCheckResult);
} }
private void onCheckResult(final int state, final Throwable throwable) { private void onCheckResult(final int state, @Nullable final Throwable throwable) {
if (throwable != null || state == ToolsInstaller.ERROR) if (throwable != null || state == ToolsInstaller.ERROR)
setState(State.INITIAL); setState(State.INITIAL);
else if ((state & ToolsInstaller.YES) == ToolsInstaller.YES) else if ((state & ToolsInstaller.YES) == ToolsInstaller.YES)
@@ -62,7 +62,7 @@ public class ToolsInstallerPreference extends Preference {
Application.getAsyncWorker().supplyAsync(Application.getToolsInstaller()::install).whenComplete(this::onInstallResult); Application.getAsyncWorker().supplyAsync(Application.getToolsInstaller()::install).whenComplete(this::onInstallResult);
} }
private void onInstallResult(final Integer result, final Throwable throwable) { private void onInstallResult(final Integer result, @Nullable final Throwable throwable) {
if (throwable != null) if (throwable != null)
setState(State.FAILURE); setState(State.FAILURE);
else if ((result & (ToolsInstaller.YES | ToolsInstaller.MAGISK)) == (ToolsInstaller.YES | ToolsInstaller.MAGISK)) else if ((result & (ToolsInstaller.YES | ToolsInstaller.MAGISK)) == (ToolsInstaller.YES | ToolsInstaller.MAGISK))
@@ -73,7 +73,7 @@ public class ToolsInstallerPreference extends Preference {
setState(State.FAILURE); setState(State.FAILURE);
} }
private void setState(@NonNull final State state) { private void setState(final State state) {
if (this.state == state) if (this.state == state)
return; return;
this.state = state; this.state = state;
@@ -9,6 +9,7 @@ import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -17,7 +18,7 @@ import com.wireguard.android.BuildConfig;
import com.wireguard.android.R; import com.wireguard.android.R;
public class VersionPreference extends Preference { public class VersionPreference extends Preference {
private String versionSummary; @Nullable private String versionSummary;
public VersionPreference(final Context context, final AttributeSet attrs) { public VersionPreference(final Context context, final AttributeSet attrs) {
super(context, attrs); super(context, attrs);
@@ -33,7 +34,7 @@ public class VersionPreference extends Preference {
}); });
} }
@Override @Override @Nullable
public CharSequence getSummary() { public CharSequence getSummary() {
return versionSummary; return versionSummary;
} }
@@ -10,6 +10,7 @@ import android.Manifest;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Environment; import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -40,7 +41,7 @@ import java9.util.concurrent.CompletableFuture;
public class ZipExporterPreference extends Preference { public class ZipExporterPreference extends Preference {
private static final String TAG = "WireGuard/" + ZipExporterPreference.class.getSimpleName(); private static final String TAG = "WireGuard/" + ZipExporterPreference.class.getSimpleName();
private String exportedFilePath; @Nullable private String exportedFilePath;
public ZipExporterPreference(final Context context, final AttributeSet attrs) { public ZipExporterPreference(final Context context, final AttributeSet attrs) {
super(context, attrs); super(context, attrs);
@@ -79,7 +80,7 @@ public class ZipExporterPreference extends Preference {
}).whenComplete(this::exportZipComplete)); }).whenComplete(this::exportZipComplete));
} }
private void exportZipComplete(final String filePath, final Throwable throwable) { private void exportZipComplete(@Nullable final String filePath, @Nullable final Throwable throwable) {
if (throwable != null) { if (throwable != null) {
final String error = ExceptionLoggers.unwrapMessage(throwable); final String error = ExceptionLoggers.unwrapMessage(throwable);
final String message = getContext().getString(R.string.zip_export_error, error); final String message = getContext().getString(R.string.zip_export_error, error);
@@ -6,8 +6,9 @@
package com.wireguard.android.util; package com.wireguard.android.util;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import java9.util.concurrent.CompletionException; import java9.util.concurrent.CompletionException;
import java9.util.function.BiConsumer; import java9.util.function.BiConsumer;
@@ -34,7 +35,6 @@ public enum ExceptionLoggers implements BiConsumer<Object, Throwable> {
return throwable; return throwable;
} }
@NonNull
public static String unwrapMessage(Throwable throwable) { public static String unwrapMessage(Throwable throwable) {
throwable = unwrap(throwable); throwable = unwrap(throwable);
final String message = throwable.getMessage(); final String message = throwable.getMessage();
@@ -44,7 +44,7 @@ public enum ExceptionLoggers implements BiConsumer<Object, Throwable> {
} }
@Override @Override
public void accept(final Object result, final Throwable throwable) { public void accept(final Object result, @Nullable final Throwable throwable) {
if (throwable != null) if (throwable != null)
Log.println(Log.ERROR, TAG, Log.getStackTraceString(throwable)); Log.println(Log.ERROR, TAG, Log.getStackTraceString(throwable));
else if (priority <= Log.DEBUG) else if (priority <= Log.DEBUG)
@@ -7,7 +7,7 @@
package com.wireguard.android.util; package com.wireguard.android.util;
import android.databinding.ObservableArrayList; import android.databinding.ObservableArrayList;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import com.wireguard.util.Keyed; import com.wireguard.util.Keyed;
@@ -25,28 +25,28 @@ import java.util.Objects;
public class ObservableKeyedArrayList<K, E extends Keyed<? extends K>> public class ObservableKeyedArrayList<K, E extends Keyed<? extends K>>
extends ObservableArrayList<E> implements ObservableKeyedList<K, E> { extends ObservableArrayList<E> implements ObservableKeyedList<K, E> {
@Override @Override
public boolean add(final E e) { public boolean add(@Nullable final E e) {
if (e == null) if (e == null)
throw new NullPointerException("Trying to add a null element"); throw new NullPointerException("Trying to add a null element");
return super.add(e); return super.add(e);
} }
@Override @Override
public void add(final int index, final E e) { public void add(final int index, @Nullable final E e) {
if (e == null) if (e == null)
throw new NullPointerException("Trying to add a null element"); throw new NullPointerException("Trying to add a null element");
super.add(index, e); super.add(index, e);
} }
@Override @Override
public boolean addAll(@NonNull final Collection<? extends E> c) { public boolean addAll(final Collection<? extends E> c) {
if (c.contains(null)) if (c.contains(null))
throw new NullPointerException("Trying to add a collection with null element(s)"); throw new NullPointerException("Trying to add a collection with null element(s)");
return super.addAll(c); return super.addAll(c);
} }
@Override @Override
public boolean addAll(final int index, @NonNull final Collection<? extends E> c) { public boolean addAll(final int index, final Collection<? extends E> c) {
if (c.contains(null)) if (c.contains(null))
throw new NullPointerException("Trying to add a collection with null element(s)"); throw new NullPointerException("Trying to add a collection with null element(s)");
return super.addAll(index, c); return super.addAll(index, c);
@@ -65,13 +65,13 @@ public class ObservableKeyedArrayList<K, E extends Keyed<? extends K>>
return indexOfKey(key) >= 0; return indexOfKey(key) >= 0;
} }
@Override @Override @Nullable
public E get(final K key) { public E get(final K key) {
final int index = indexOfKey(key); final int index = indexOfKey(key);
return index >= 0 ? get(index) : null; return index >= 0 ? get(index) : null;
} }
@Override @Override @Nullable
public E getLast(final K key) { public E getLast(final K key) {
final int index = lastIndexOfKey(key); final int index = lastIndexOfKey(key);
return index >= 0 ? get(index) : null; return index >= 0 ? get(index) : null;
@@ -100,7 +100,7 @@ public class ObservableKeyedArrayList<K, E extends Keyed<? extends K>>
} }
@Override @Override
public E set(final int index, final E e) { public E set(final int index, @Nullable final E e) {
if (e == null) if (e == null)
throw new NullPointerException("Trying to set a null key"); throw new NullPointerException("Trying to set a null key");
return super.set(index, e); return super.set(index, e);
@@ -6,7 +6,7 @@
package com.wireguard.android.util; package com.wireguard.android.util;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import com.wireguard.util.Keyed; import com.wireguard.util.Keyed;
import com.wireguard.util.SortedKeyedList; import com.wireguard.util.SortedKeyedList;
@@ -29,6 +29,7 @@ import java.util.Spliterator;
public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>> public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>>
extends ObservableKeyedArrayList<K, E> implements ObservableSortedKeyedList<K, E> { extends ObservableKeyedArrayList<K, E> implements ObservableSortedKeyedList<K, E> {
@Nullable
private final Comparator<? super K> comparator; private final Comparator<? super K> comparator;
private final transient KeyList<K, E> keyList = new KeyList<>(this); private final transient KeyList<K, E> keyList = new KeyList<>(this);
@@ -75,7 +76,7 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>>
} }
@Override @Override
public boolean addAll(@NonNull final Collection<? extends E> c) { public boolean addAll(final Collection<? extends E> c) {
boolean didChange = false; boolean didChange = false;
for (final E e : c) for (final E e : c)
if (add(e)) if (add(e))
@@ -84,12 +85,13 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>>
} }
@Override @Override
public boolean addAll(int index, @NonNull final Collection<? extends E> c) { public boolean addAll(int index, final Collection<? extends E> c) {
for (final E e : c) for (final E e : c)
add(index++, e); add(index++, e);
return true; return true;
} }
@Nullable
@Override @Override
public Comparator<? super K> comparator() { public Comparator<? super K> comparator() {
return comparator; return comparator;
@@ -128,7 +130,6 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>>
} }
@Override @Override
@NonNull
public Set<K> keySet() { public Set<K> keySet() {
return keyList; return keyList;
} }
@@ -168,7 +169,6 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>>
} }
@Override @Override
@NonNull
public Collection<E> values() { public Collection<E> values() {
return this; return this;
} }
@@ -7,6 +7,7 @@
package com.wireguard.android.util; package com.wireguard.android.util;
import android.content.Context; import android.content.Context;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import com.wireguard.android.R; import com.wireguard.android.R;
@@ -34,10 +35,10 @@ public class RootShell {
private final File localTemporaryDir; private final File localTemporaryDir;
private final Object lock = new Object(); private final Object lock = new Object();
private final String preamble; private final String preamble;
private Process process; @Nullable private Process process;
private BufferedReader stderr; @Nullable private BufferedReader stderr;
private OutputStreamWriter stdin; @Nullable private OutputStreamWriter stdin;
private BufferedReader stdout; @Nullable private BufferedReader stdout;
public RootShell(final Context context) { public RootShell(final Context context) {
deviceNotRootedMessage = context.getString(R.string.error_root); deviceNotRootedMessage = context.getString(R.string.error_root);
@@ -80,7 +81,7 @@ public class RootShell {
* @param command Command to run as root. * @param command Command to run as root.
* @return The exit value of the command. * @return The exit value of the command.
*/ */
public int run(final Collection<String> output, final String command) public int run(@Nullable final Collection<String> output, final String command)
throws IOException, NoRootException { throws IOException, NoRootException {
synchronized (lock) { synchronized (lock) {
/* Start inside synchronized block to prevent a concurrent call to stop(). */ /* Start inside synchronized block to prevent a concurrent call to stop(). */
@@ -19,8 +19,7 @@ import java.util.zip.ZipFile;
public final class SharedLibraryLoader { public final class SharedLibraryLoader {
private static final String TAG = "WireGuard/" + SharedLibraryLoader.class.getSimpleName(); private static final String TAG = "WireGuard/" + SharedLibraryLoader.class.getSimpleName();
private SharedLibraryLoader() { private SharedLibraryLoader() { }
}
public static void loadSharedLibrary(final Context context, final String libName) { public static void loadSharedLibrary(final Context context, final String libName) {
Throwable noAbiException; Throwable noAbiException;
@@ -7,6 +7,7 @@
package com.wireguard.android.util; package com.wireguard.android.util;
import android.content.Context; import android.content.Context;
import android.support.annotation.Nullable;
import android.system.OsConstants; import android.system.OsConstants;
import android.util.Log; import android.util.Log;
@@ -39,20 +40,21 @@ public final class ToolsInstaller {
new File("/system/xbin"), new File("/system/xbin"),
new File("/system/bin"), new File("/system/bin"),
}; };
private static final File INSTALL_DIR = getInstallDir(); @Nullable private static final File INSTALL_DIR = getInstallDir();
private static final String TAG = "WireGuard/" + ToolsInstaller.class.getSimpleName(); private static final String TAG = "WireGuard/" + ToolsInstaller.class.getSimpleName();
private final File localBinaryDir; private final File localBinaryDir;
private final Object lock = new Object(); private final Object lock = new Object();
private final File nativeLibraryDir; private final File nativeLibraryDir;
private Boolean areToolsAvailable; @Nullable private Boolean areToolsAvailable;
private Boolean installAsMagiskModule; @Nullable private Boolean installAsMagiskModule;
public ToolsInstaller(final Context context) { public ToolsInstaller(final Context context) {
localBinaryDir = new File(context.getCacheDir(), "bin"); localBinaryDir = new File(context.getCacheDir(), "bin");
nativeLibraryDir = new File(context.getApplicationInfo().nativeLibraryDir); nativeLibraryDir = new File(context.getApplicationInfo().nativeLibraryDir);
} }
@Nullable
private static File getInstallDir() { private static File getInstallDir() {
final String path = System.getenv("PATH"); final String path = System.getenv("PATH");
if (path == null) if (path == null)
@@ -6,6 +6,7 @@
package com.wireguard.android.widget; package com.wireguard.android.widget;
import android.support.annotation.Nullable;
import android.text.InputFilter; import android.text.InputFilter;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
@@ -25,7 +26,7 @@ public class KeyInputFilter implements InputFilter {
return new KeyInputFilter(); return new KeyInputFilter();
} }
@Override @Override @Nullable
public CharSequence filter(final CharSequence source, public CharSequence filter(final CharSequence source,
final int sStart, final int sEnd, final int sStart, final int sEnd,
final Spanned dest, final Spanned dest,
@@ -6,6 +6,7 @@
package com.wireguard.android.widget; package com.wireguard.android.widget;
import android.support.annotation.Nullable;
import android.text.InputFilter; import android.text.InputFilter;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
@@ -25,7 +26,7 @@ public class NameInputFilter implements InputFilter {
return new NameInputFilter(); return new NameInputFilter();
} }
@Override @Override @Nullable
public CharSequence filter(final CharSequence source, public CharSequence filter(final CharSequence source,
final int sStart, final int sEnd, final int sStart, final int sEnd,
final Spanned dest, final Spanned dest,
@@ -25,11 +25,9 @@ import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.support.annotation.ColorInt; import android.support.annotation.ColorInt;
import android.support.annotation.IntRange; import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.FloatProperty; import android.util.FloatProperty;
@TargetApi(Build.VERSION_CODES.N) @TargetApi(Build.VERSION_CODES.N)
public class SlashDrawable extends Drawable { public class SlashDrawable extends Drawable {
@@ -53,26 +51,24 @@ public class SlashDrawable extends Drawable {
// Draw the slash washington-monument style; rotate to no-u-turn style // Draw the slash washington-monument style; rotate to no-u-turn style
private static final float DEFAULT_ROTATION = -45f; private static final float DEFAULT_ROTATION = -45f;
private Drawable mDrawable; private final Drawable mDrawable;
private final RectF mSlashRect = new RectF(0, 0, 0, 0); private final RectF mSlashRect = new RectF(0, 0, 0, 0);
private float mRotation; private float mRotation;
private boolean mSlashed; private boolean mSlashed;
private Mode mTintMode;
private ColorStateList mTintList;
private boolean mAnimationEnabled = true; private boolean mAnimationEnabled = true;
public SlashDrawable(final Drawable d) { public SlashDrawable(final Drawable d) {
setDrawable(d); mDrawable = d;
} }
@Override @Override
public int getIntrinsicHeight() { public int getIntrinsicHeight() {
return mDrawable != null ? mDrawable.getIntrinsicHeight(): 0; return mDrawable.getIntrinsicHeight();
} }
@Override @Override
public int getIntrinsicWidth() { public int getIntrinsicWidth() {
return mDrawable != null ? mDrawable.getIntrinsicWidth(): 0; return mDrawable.getIntrinsicWidth();
} }
@Override @Override
@@ -81,17 +77,6 @@ public class SlashDrawable extends Drawable {
mDrawable.setBounds(bounds); mDrawable.setBounds(bounds);
} }
public void setDrawable(final Drawable d) {
mDrawable = d;
mDrawable.setCallback(getCallback());
mDrawable.setBounds(getBounds());
if (mTintMode != null)
mDrawable.setTintMode(mTintMode);
if (mTintList != null)
mDrawable.setTintList(mTintList);
invalidateSelf();
}
public void setRotation(final float rotation) { public void setRotation(final float rotation) {
if (mRotation == rotation) if (mRotation == rotation)
return; return;
@@ -139,7 +124,7 @@ public class SlashDrawable extends Drawable {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Override @Override
public void draw(@NonNull final Canvas canvas) { public void draw(final Canvas canvas) {
canvas.save(); canvas.save();
final Matrix m = new Matrix(); final Matrix m = new Matrix();
final int width = getBounds().width(); final int width = getBounds().width();
@@ -201,7 +186,6 @@ public class SlashDrawable extends Drawable {
@Override @Override
public void setTintList(@Nullable final ColorStateList tint) { public void setTintList(@Nullable final ColorStateList tint) {
mTintList = tint;
super.setTintList(tint); super.setTintList(tint);
setDrawableTintList(tint); setDrawableTintList(tint);
mPaint.setColor(tint == null ? 0 : tint.getDefaultColor()); mPaint.setColor(tint == null ? 0 : tint.getDefaultColor());
@@ -213,8 +197,7 @@ public class SlashDrawable extends Drawable {
} }
@Override @Override
public void setTintMode(@NonNull final Mode tintMode) { public void setTintMode(final Mode tintMode) {
mTintMode = tintMode;
super.setTintMode(tintMode); super.setTintMode(tintMode);
mDrawable.setTintMode(tintMode); mDrawable.setTintMode(tintMode);
} }
@@ -7,22 +7,23 @@ package com.wireguard.android.widget;
import android.content.Context; import android.content.Context;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.Switch; import android.widget.Switch;
public class ToggleSwitch extends Switch { public class ToggleSwitch extends Switch {
private boolean isRestoringState; private boolean isRestoringState;
private OnBeforeCheckedChangeListener listener; @Nullable private OnBeforeCheckedChangeListener listener;
@SuppressWarnings({"SameParameterValue", "WeakerAccess"})
public ToggleSwitch(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public ToggleSwitch(final Context context) { public ToggleSwitch(final Context context) {
this(context, null); this(context, null);
} }
@SuppressWarnings({"SameParameterValue", "WeakerAccess"})
public ToggleSwitch(final Context context, @Nullable final AttributeSet attrs) {
super(context, attrs);
}
@Override @Override
public void onRestoreInstanceState(final Parcelable state) { public void onRestoreInstanceState(final Parcelable state) {
isRestoringState = true; isRestoringState = true;
@@ -20,7 +20,7 @@ import android.graphics.drawable.LayerDrawable;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Keep; import android.support.annotation.Keep;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.res.ResourcesCompat; import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.AppCompatTextView; import android.support.v7.widget.AppCompatTextView;
@@ -57,32 +57,32 @@ public class FloatingActionsMenu extends ViewGroup {
private boolean mExpanded; private boolean mExpanded;
private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
private FloatingActionButton mAddButton; @Nullable private FloatingActionButton mAddButton;
private RotatingDrawable mRotatingDrawable; @Nullable private RotatingDrawable mRotatingDrawable;
private int mMaxButtonWidth; private int mMaxButtonWidth;
private int mMaxButtonHeight; private int mMaxButtonHeight;
private int mLabelsStyle; private int mLabelsStyle;
private int mLabelsPosition; private int mLabelsPosition;
private int mButtonsCount; private int mButtonsCount;
private TouchDelegateGroup mTouchDelegateGroup; @Nullable private TouchDelegateGroup mTouchDelegateGroup;
private OnFloatingActionsMenuUpdateListener mListener; @Nullable private OnFloatingActionsMenuUpdateListener mListener;
private final Rect touchArea = new Rect(0, 0, 0, 0); private final Rect touchArea = new Rect(0, 0, 0, 0);
public FloatingActionsMenu(final Context context) { public FloatingActionsMenu(final Context context) {
this(context, null); this(context, null);
} }
public FloatingActionsMenu(final Context context, final AttributeSet attrs) { public FloatingActionsMenu(final Context context, @Nullable final AttributeSet attrs) {
super(context, attrs); super(context, attrs);
init(context, attrs); init(context, attrs);
} }
public FloatingActionsMenu(final Context context, final AttributeSet attrs, final int defStyle) { public FloatingActionsMenu(final Context context, @Nullable final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
init(context, attrs); init(context, attrs);
} }
private void init(final Context context, final AttributeSet attributeSet) { private void init(final Context context, @Nullable final AttributeSet attributeSet) {
mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing)); mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing));
mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin); mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin);
mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset); mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);
@@ -530,7 +530,7 @@ public class FloatingActionsMenu extends ViewGroup {
} }
@Override @Override
public void writeToParcel(@NonNull final Parcel out, final int flags) { public void writeToParcel(final Parcel out, final int flags) {
super.writeToParcel(out, flags); super.writeToParcel(out, flags);
out.writeInt(mExpanded ? 1 : 0); out.writeInt(mExpanded ? 1 : 0);
} }
@@ -8,6 +8,7 @@ package com.wireguard.android.widget.fab;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.TextView; import android.widget.TextView;
@@ -16,17 +17,17 @@ import com.wireguard.android.R;
public class LabeledFloatingActionButton extends FloatingActionButton { public class LabeledFloatingActionButton extends FloatingActionButton {
private final String title; @Nullable private final String title;
public LabeledFloatingActionButton(final Context context) { public LabeledFloatingActionButton(final Context context) {
this(context, null); this(context, null);
} }
public LabeledFloatingActionButton(final Context context, final AttributeSet attrs) { public LabeledFloatingActionButton(final Context context, @Nullable final AttributeSet attrs) {
this(context, attrs, 0); this(context, attrs, 0);
} }
public LabeledFloatingActionButton(final Context context, final AttributeSet attrs, final int defStyle) { public LabeledFloatingActionButton(final Context context, @Nullable final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
final TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.LabeledFloatingActionButton, 0, 0); final TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.LabeledFloatingActionButton, 0, 0);
@@ -34,10 +35,12 @@ public class LabeledFloatingActionButton extends FloatingActionButton {
attr.recycle(); attr.recycle();
} }
@Nullable
TextView getLabelView() { TextView getLabelView() {
return (TextView) getTag(R.id.fab_label); return (TextView) getTag(R.id.fab_label);
} }
@Nullable
public String getTitle() { public String getTitle() {
return title; return title;
} }
@@ -7,7 +7,7 @@
package com.wireguard.android.widget.fab; package com.wireguard.android.widget.fab;
import android.graphics.Rect; import android.graphics.Rect;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.TouchDelegate; import android.view.TouchDelegate;
import android.view.View; import android.view.View;
@@ -18,14 +18,14 @@ import java.util.Collection;
public class TouchDelegateGroup extends TouchDelegate { public class TouchDelegateGroup extends TouchDelegate {
private static final Rect USELESS_HACKY_RECT = new Rect(); private static final Rect USELESS_HACKY_RECT = new Rect();
private final Collection<TouchDelegate> mTouchDelegates = new ArrayList<>(); private final Collection<TouchDelegate> mTouchDelegates = new ArrayList<>();
private TouchDelegate mCurrentTouchDelegate; @Nullable private TouchDelegate mCurrentTouchDelegate;
private boolean mEnabled; private boolean mEnabled;
public TouchDelegateGroup(final View uselessHackyView) { public TouchDelegateGroup(final View uselessHackyView) {
super(USELESS_HACKY_RECT, uselessHackyView); super(USELESS_HACKY_RECT, uselessHackyView);
} }
public void addTouchDelegate(@NonNull final TouchDelegate touchDelegate) { public void addTouchDelegate(final TouchDelegate touchDelegate) {
mTouchDelegates.add(touchDelegate); mTouchDelegates.add(touchDelegate);
} }
@@ -42,7 +42,7 @@ public class TouchDelegateGroup extends TouchDelegate {
} }
@Override @Override
public boolean onTouchEvent(@NonNull final MotionEvent event) { public boolean onTouchEvent(final MotionEvent event) {
if (!mEnabled) if (!mEnabled)
return false; return false;
@@ -6,6 +6,7 @@
package com.wireguard.config; package com.wireguard.config;
import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import java.util.HashMap; import java.util.HashMap;
@@ -59,13 +60,13 @@ public enum Attribute {
return KEY_MAP.get(SEPARATOR_PATTERN.split(line)[0].toLowerCase()); return KEY_MAP.get(SEPARATOR_PATTERN.split(line)[0].toLowerCase());
} }
public static String[] stringToList(final String string) { public static String[] stringToList(@Nullable final String string) {
if (TextUtils.isEmpty(string)) if (TextUtils.isEmpty(string))
return EMPTY_LIST; return EMPTY_LIST;
return LIST_SEPARATOR_PATTERN.split(string.trim()); return LIST_SEPARATOR_PATTERN.split(string.trim());
} }
public String composeWith(final Object value) { public String composeWith(@Nullable final Object value) {
return String.format("%s = %s%n", token, value); return String.format("%s = %s%n", token, value);
} }
@@ -77,11 +78,13 @@ public enum Attribute {
return String.format("%s = %s%n", token, iterableToString(value)); return String.format("%s = %s%n", token, iterableToString(value));
} }
@Nullable
public String parse(final CharSequence line) { public String parse(final CharSequence line) {
final Matcher matcher = pattern.matcher(line); final Matcher matcher = pattern.matcher(line);
return matcher.matches() ? matcher.group(1) : null; return matcher.matches() ? matcher.group(1) : null;
} }
@Nullable
public String[] parseList(final CharSequence line) { public String[] parseList(final CharSequence line) {
final Matcher matcher = pattern.matcher(line); final Matcher matcher = pattern.matcher(line);
return matcher.matches() ? stringToList(matcher.group(1)) : null; return matcher.matches() ? stringToList(matcher.group(1)) : null;
@@ -12,6 +12,7 @@ import android.databinding.ObservableArrayList;
import android.databinding.ObservableList; import android.databinding.ObservableList;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Nullable;
import com.android.databinding.library.baseAdapters.BR; import com.android.databinding.library.baseAdapters.BR;
@@ -96,13 +97,19 @@ public class Config {
return new Observable[size]; return new Observable[size];
} }
}; };
private String name; @Nullable private String name;
private Interface.Observable observableInterface; private final Interface.Observable observableInterface;
private ObservableList<Peer.Observable> observablePeers; private final ObservableList<Peer.Observable> observablePeers;
public Observable(final Config parent, final String name) { public Observable(@Nullable final Config parent, @Nullable final String name) {
this.name = name; this.name = name;
loadData(parent);
observableInterface = new Interface.Observable(parent == null ? null : parent.interfaceSection);
observablePeers = new ObservableArrayList<>();
if (parent != null) {
for (final Peer peer : parent.getPeers())
observablePeers.add(new Peer.Observable(peer));
}
} }
private Observable(final Parcel in) { private Observable(final Parcel in) {
@@ -144,15 +151,6 @@ public class Config {
return observablePeers; return observablePeers;
} }
protected void loadData(final Config parent) {
observableInterface = new Interface.Observable(parent == null ? null : parent.interfaceSection);
observablePeers = new ObservableArrayList<>();
if (parent != null) {
for (final Peer peer : parent.getPeers())
observablePeers.add(new Peer.Observable(peer));
}
}
public void setName(final String name) { public void setName(final String name) {
this.name = name; this.name = name;
notifyPropertyChanged(BR.name); notifyPropertyChanged(BR.name);
@@ -6,7 +6,6 @@
package com.wireguard.config; package com.wireguard.config;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@@ -29,7 +28,6 @@ public final class InetAddresses {
// Prevent instantiation. // Prevent instantiation.
} }
@NonNull
public static InetAddress parse(@Nullable final String address) { public static InetAddress parse(@Nullable final String address) {
if (address == null || address.isEmpty()) if (address == null || address.isEmpty())
throw new IllegalArgumentException("Empty address"); throw new IllegalArgumentException("Empty address");
@@ -6,8 +6,6 @@
package com.wireguard.config; package com.wireguard.config;
import android.support.annotation.NonNull;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Objects; import java.util.Objects;
@@ -16,7 +14,7 @@ public class InetNetwork {
private final InetAddress address; private final InetAddress address;
private final int mask; private final int mask;
public InetNetwork(@NonNull final String input) { public InetNetwork(final String input) {
final int slash = input.lastIndexOf('/'); final int slash = input.lastIndexOf('/');
final int rawMask; final int rawMask;
final String rawAddress; final String rawAddress;
@@ -40,7 +38,6 @@ public class InetNetwork {
return Objects.equals(address, other.address) && mask == other.mask; return Objects.equals(address, other.address) && mask == other.mask;
} }
@NonNull
public InetAddress getAddress() { public InetAddress getAddress() {
return address; return address;
} }
@@ -10,6 +10,7 @@ import android.databinding.BaseObservable;
import android.databinding.Bindable; import android.databinding.Bindable;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Nullable;
import com.wireguard.android.BR; import com.wireguard.android.BR;
import com.wireguard.crypto.Keypair; import com.wireguard.crypto.Keypair;
@@ -27,7 +28,7 @@ public class Interface {
private final List<InetNetwork> addressList; private final List<InetNetwork> addressList;
private final List<InetAddress> dnsList; private final List<InetAddress> dnsList;
private final List<String> excludedApplications; private final List<String> excludedApplications;
private Keypair keypair; @Nullable private Keypair keypair;
private int listenPort; private int listenPort;
private int mtu; private int mtu;
@@ -37,7 +38,7 @@ public class Interface {
excludedApplications = new ArrayList<>(); excludedApplications = new ArrayList<>();
} }
private void addAddresses(final String[] addresses) { private void addAddresses(@Nullable final String[] addresses) {
if (addresses != null && addresses.length > 0) { if (addresses != null && addresses.length > 0) {
for (final String addr : addresses) { for (final String addr : addresses) {
if (addr.isEmpty()) if (addr.isEmpty())
@@ -47,7 +48,7 @@ public class Interface {
} }
} }
private void addDnses(final String[] dnses) { private void addDnses(@Nullable final String[] dnses) {
if (dnses != null && dnses.length > 0) { if (dnses != null && dnses.length > 0) {
for (final String dns : dnses) { for (final String dns : dnses) {
dnsList.add(InetAddresses.parse(dns)); dnsList.add(InetAddresses.parse(dns));
@@ -55,12 +56,13 @@ public class Interface {
} }
} }
private void addExcludedApplications(final String[] applications) { private void addExcludedApplications(@Nullable final String[] applications) {
if (applications != null && applications.length > 0) { if (applications != null && applications.length > 0) {
excludedApplications.addAll(Arrays.asList(applications)); excludedApplications.addAll(Arrays.asList(applications));
} }
} }
@Nullable
private String getAddressString() { private String getAddressString() {
if (addressList.isEmpty()) if (addressList.isEmpty())
return null; return null;
@@ -71,6 +73,7 @@ public class Interface {
return addressList.toArray(new InetNetwork[addressList.size()]); return addressList.toArray(new InetNetwork[addressList.size()]);
} }
@Nullable
private String getDnsString() { private String getDnsString() {
if (dnsList.isEmpty()) if (dnsList.isEmpty())
return null; return null;
@@ -88,6 +91,7 @@ public class Interface {
return dnsList.toArray(new InetAddress[dnsList.size()]); return dnsList.toArray(new InetAddress[dnsList.size()]);
} }
@Nullable
private String getExcludedApplicationsString() { private String getExcludedApplicationsString() {
if (excludedApplications.isEmpty()) if (excludedApplications.isEmpty())
return null; return null;
@@ -102,6 +106,7 @@ public class Interface {
return listenPort; return listenPort;
} }
@Nullable
private String getListenPortString() { private String getListenPortString() {
if (listenPort == 0) if (listenPort == 0)
return null; return null;
@@ -112,18 +117,21 @@ public class Interface {
return mtu; return mtu;
} }
@Nullable
private String getMtuString() { private String getMtuString() {
if (mtu == 0) if (mtu == 0)
return null; return null;
return Integer.toString(mtu); return Integer.toString(mtu);
} }
@Nullable
public String getPrivateKey() { public String getPrivateKey() {
if (keypair == null) if (keypair == null)
return null; return null;
return keypair.getPrivateKey(); return keypair.getPrivateKey();
} }
@Nullable
public String getPublicKey() { public String getPublicKey() {
if (keypair == null) if (keypair == null)
return null; return null;
@@ -156,17 +164,17 @@ public class Interface {
} }
} }
private void setAddressString(final String addressString) { private void setAddressString(@Nullable final String addressString) {
addressList.clear(); addressList.clear();
addAddresses(Attribute.stringToList(addressString)); addAddresses(Attribute.stringToList(addressString));
} }
private void setDnsString(final String dnsString) { private void setDnsString(@Nullable final String dnsString) {
dnsList.clear(); dnsList.clear();
addDnses(Attribute.stringToList(dnsString)); addDnses(Attribute.stringToList(dnsString));
} }
private void setExcludedApplicationsString(final String applicationsString) { private void setExcludedApplicationsString(@Nullable final String applicationsString) {
excludedApplications.clear(); excludedApplications.clear();
addExcludedApplications(Attribute.stringToList(applicationsString)); addExcludedApplications(Attribute.stringToList(applicationsString));
} }
@@ -175,7 +183,7 @@ public class Interface {
this.listenPort = listenPort; this.listenPort = listenPort;
} }
private void setListenPortString(final String port) { private void setListenPortString(@Nullable final String port) {
if (port != null && !port.isEmpty()) if (port != null && !port.isEmpty())
setListenPort(Integer.parseInt(port, 10)); setListenPort(Integer.parseInt(port, 10));
else else
@@ -186,14 +194,14 @@ public class Interface {
this.mtu = mtu; this.mtu = mtu;
} }
private void setMtuString(final String mtu) { private void setMtuString(@Nullable final String mtu) {
if (mtu != null && !mtu.isEmpty()) if (mtu != null && !mtu.isEmpty())
setMtu(Integer.parseInt(mtu, 10)); setMtu(Integer.parseInt(mtu, 10));
else else
setMtu(0); setMtu(0);
} }
private void setPrivateKey(String privateKey) { private void setPrivateKey(@Nullable String privateKey) {
if (privateKey != null && privateKey.isEmpty()) if (privateKey != null && privateKey.isEmpty())
privateKey = null; privateKey = null;
keypair = privateKey == null ? null : new Keypair(privateKey); keypair = privateKey == null ? null : new Keypair(privateKey);
@@ -229,15 +237,15 @@ public class Interface {
return new Observable[size]; return new Observable[size];
} }
}; };
private String addresses; @Nullable private String addresses;
private String dnses; @Nullable private String dnses;
private String excludedApplications; @Nullable private String excludedApplications;
private String listenPort; @Nullable private String listenPort;
private String mtu; @Nullable private String mtu;
private String privateKey; @Nullable private String privateKey;
private String publicKey; @Nullable private String publicKey;
public Observable(final Interface parent) { public Observable(@Nullable final Interface parent) {
if (parent != null) if (parent != null)
loadData(parent); loadData(parent);
} }
@@ -276,16 +284,19 @@ public class Interface {
notifyPropertyChanged(BR.publicKey); notifyPropertyChanged(BR.publicKey);
} }
@Nullable
@Bindable @Bindable
public String getAddresses() { public String getAddresses() {
return addresses; return addresses;
} }
@Nullable
@Bindable @Bindable
public String getDnses() { public String getDnses() {
return dnses; return dnses;
} }
@Nullable
@Bindable @Bindable
public String getExcludedApplications() { public String getExcludedApplications() {
return excludedApplications; return excludedApplications;
@@ -296,21 +307,25 @@ public class Interface {
return Attribute.stringToList(excludedApplications).length; return Attribute.stringToList(excludedApplications).length;
} }
@Nullable
@Bindable @Bindable
public String getListenPort() { public String getListenPort() {
return listenPort; return listenPort;
} }
@Nullable
@Bindable @Bindable
public String getMtu() { public String getMtu() {
return mtu; return mtu;
} }
@Nullable
@Bindable @Bindable
public String getPrivateKey() { public String getPrivateKey() {
return privateKey; return privateKey;
} }
@Nullable
@Bindable @Bindable
public String getPublicKey() { public String getPublicKey() {
return publicKey; return publicKey;
@@ -10,6 +10,7 @@ import android.databinding.BaseObservable;
import android.databinding.Bindable; import android.databinding.Bindable;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.Nullable;
import com.android.databinding.library.baseAdapters.BR; import com.android.databinding.library.baseAdapters.BR;
import com.wireguard.crypto.KeyEncoding; import com.wireguard.crypto.KeyEncoding;
@@ -34,16 +35,16 @@ import java9.lang.Iterables;
public class Peer { public class Peer {
private final List<InetNetwork> allowedIPsList; private final List<InetNetwork> allowedIPsList;
private InetSocketAddress endpoint; @Nullable private InetSocketAddress endpoint;
private int persistentKeepalive; private int persistentKeepalive;
private String preSharedKey; @Nullable private String preSharedKey;
private String publicKey; @Nullable private String publicKey;
public Peer() { public Peer() {
allowedIPsList = new ArrayList<>(); allowedIPsList = new ArrayList<>();
} }
private void addAllowedIPs(final String[] allowedIPs) { private void addAllowedIPs(@Nullable final String[] allowedIPs) {
if (allowedIPs != null && allowedIPs.length > 0) { if (allowedIPs != null && allowedIPs.length > 0) {
for (final String allowedIP : allowedIPs) { for (final String allowedIP : allowedIPs) {
allowedIPsList.add(new InetNetwork(allowedIP)); allowedIPsList.add(new InetNetwork(allowedIP));
@@ -55,16 +56,19 @@ public class Peer {
return allowedIPsList.toArray(new InetNetwork[allowedIPsList.size()]); return allowedIPsList.toArray(new InetNetwork[allowedIPsList.size()]);
} }
@Nullable
private String getAllowedIPsString() { private String getAllowedIPsString() {
if (allowedIPsList.isEmpty()) if (allowedIPsList.isEmpty())
return null; return null;
return Attribute.iterableToString(allowedIPsList); return Attribute.iterableToString(allowedIPsList);
} }
@Nullable
public InetSocketAddress getEndpoint() { public InetSocketAddress getEndpoint() {
return endpoint; return endpoint;
} }
@Nullable
private String getEndpointString() { private String getEndpointString() {
if (endpoint == null) if (endpoint == null)
return null; return null;
@@ -75,16 +79,19 @@ public class Peer {
return persistentKeepalive; return persistentKeepalive;
} }
@Nullable
private String getPersistentKeepaliveString() { private String getPersistentKeepaliveString() {
if (persistentKeepalive == 0) if (persistentKeepalive == 0)
return null; return null;
return Integer.valueOf(persistentKeepalive).toString(); return Integer.valueOf(persistentKeepalive).toString();
} }
@Nullable
public String getPreSharedKey() { public String getPreSharedKey() {
return preSharedKey; return preSharedKey;
} }
@Nullable
public String getPublicKey() { public String getPublicKey() {
return publicKey; return publicKey;
} }
@@ -130,16 +137,16 @@ public class Peer {
} }
} }
private void setAllowedIPsString(final String allowedIPsString) { private void setAllowedIPsString(@Nullable final String allowedIPsString) {
allowedIPsList.clear(); allowedIPsList.clear();
addAllowedIPs(Attribute.stringToList(allowedIPsString)); addAllowedIPs(Attribute.stringToList(allowedIPsString));
} }
private void setEndpoint(final InetSocketAddress endpoint) { private void setEndpoint(@Nullable final InetSocketAddress endpoint) {
this.endpoint = endpoint; this.endpoint = endpoint;
} }
private void setEndpointString(final String endpoint) { private void setEndpointString(@Nullable final String endpoint) {
if (endpoint != null && !endpoint.isEmpty()) { if (endpoint != null && !endpoint.isEmpty()) {
final InetSocketAddress constructedEndpoint; final InetSocketAddress constructedEndpoint;
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1) if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1)
@@ -160,14 +167,14 @@ public class Peer {
this.persistentKeepalive = persistentKeepalive; this.persistentKeepalive = persistentKeepalive;
} }
private void setPersistentKeepaliveString(final String persistentKeepalive) { private void setPersistentKeepaliveString(@Nullable final String persistentKeepalive) {
if (persistentKeepalive != null && !persistentKeepalive.isEmpty()) if (persistentKeepalive != null && !persistentKeepalive.isEmpty())
setPersistentKeepalive(Integer.parseInt(persistentKeepalive, 10)); setPersistentKeepalive(Integer.parseInt(persistentKeepalive, 10));
else else
setPersistentKeepalive(0); setPersistentKeepalive(0);
} }
private void setPreSharedKey(String preSharedKey) { private void setPreSharedKey(@Nullable String preSharedKey) {
if (preSharedKey != null && preSharedKey.isEmpty()) if (preSharedKey != null && preSharedKey.isEmpty())
preSharedKey = null; preSharedKey = null;
if (preSharedKey != null) if (preSharedKey != null)
@@ -175,7 +182,7 @@ public class Peer {
this.preSharedKey = preSharedKey; this.preSharedKey = preSharedKey;
} }
private void setPublicKey(String publicKey) { private void setPublicKey(@Nullable String publicKey) {
if (publicKey != null && publicKey.isEmpty()) if (publicKey != null && publicKey.isEmpty())
publicKey = null; publicKey = null;
if (publicKey != null) if (publicKey != null)
@@ -211,12 +218,12 @@ public class Peer {
return new Observable[size]; return new Observable[size];
} }
}; };
private String allowedIPs; @Nullable private String allowedIPs;
private String endpoint; @Nullable private String endpoint;
private String persistentKeepalive; @Nullable private String persistentKeepalive;
private String preSharedKey; @Nullable private String preSharedKey;
private String publicKey; @Nullable private String publicKey;
private List<String> interfaceDNSRoutes; private final List<String> interfaceDNSRoutes = new ArrayList<>();
private int numSiblings; private int numSiblings;
public Observable(final Peer parent) { public Observable(final Peer parent) {
@@ -230,7 +237,6 @@ public class Peer {
preSharedKey = in.readString(); preSharedKey = in.readString();
publicKey = in.readString(); publicKey = in.readString();
numSiblings = in.readInt(); numSiblings = in.readInt();
interfaceDNSRoutes = new ArrayList<>();
in.readStringList(interfaceDNSRoutes); in.readStringList(interfaceDNSRoutes);
} }
@@ -284,27 +290,27 @@ public class Peer {
return numSiblings == 0 && Arrays.asList(Attribute.stringToList(allowedIPs)).containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4); return numSiblings == 0 && Arrays.asList(Attribute.stringToList(allowedIPs)).containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4);
} }
@Bindable @Bindable @Nullable
public String getAllowedIPs() { public String getAllowedIPs() {
return allowedIPs; return allowedIPs;
} }
@Bindable @Bindable @Nullable
public String getEndpoint() { public String getEndpoint() {
return endpoint; return endpoint;
} }
@Bindable @Bindable @Nullable
public String getPersistentKeepalive() { public String getPersistentKeepalive() {
return persistentKeepalive; return persistentKeepalive;
} }
@Bindable @Bindable @Nullable
public String getPreSharedKey() { public String getPreSharedKey() {
return preSharedKey; return preSharedKey;
} }
@Bindable @Bindable @Nullable
public String getPublicKey() { public String getPublicKey() {
return publicKey; return publicKey;
} }
@@ -315,7 +321,6 @@ public class Peer {
persistentKeepalive = parent.getPersistentKeepaliveString(); persistentKeepalive = parent.getPersistentKeepaliveString();
preSharedKey = parent.getPreSharedKey(); preSharedKey = parent.getPreSharedKey();
publicKey = parent.getPublicKey(); publicKey = parent.getPublicKey();
interfaceDNSRoutes = new ArrayList<>();
} }
public void setAllowedIPs(final String allowedIPs) { public void setAllowedIPs(final String allowedIPs) {
@@ -5,6 +5,8 @@
package com.wireguard.crypto; package com.wireguard.crypto;
import android.support.annotation.Nullable;
import java.util.Arrays; import java.util.Arrays;
/** /**
@@ -93,7 +95,7 @@ public final class Curve25519 {
* if the base point of the curve should be used. * if the base point of the curve should be used.
*/ */
public static void eval(final byte[] result, final int offset, public static void eval(final byte[] result, final int offset,
final byte[] privateKey, final byte[] publicKey) { final byte[] privateKey, @Nullable final byte[] publicKey) {
final Curve25519 state = new Curve25519(); final Curve25519 state = new Curve25519();
try { try {
// Unpack the public key value. If null, use 9 as the base point. // Unpack the public key value. If null, use 9 as the base point.
@@ -0,0 +1,25 @@
/*
* Copyright © 2018 Eric Kuck <eric@bluelinelabs.com>.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.util;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
/**
* This annotation can be applied to a package, class or method to indicate that all
* class fields and method parameters and return values in that element are nonnull
* by default unless overridden.
*/
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface NonNullForAll { }