diff --git a/.gitignore b/.gitignore
index 3dde301c..d85bf2d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@ build/
*.iml
*.jks
keystore.properties
+package-info.java
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 56aadf89..b9a1bf45 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -94,6 +94,8 @@
+
+
diff --git a/app/build.gradle b/app/build.gradle
index b0bcc3b6..f63726d3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,4 +1,5 @@
apply plugin: 'com.android.application'
+apply from: 'nonnull.gradle'
// Create a variable called keystorePropertiesFile, and initialize it to your
// keystore.properties file, in the rootProject folder.
@@ -56,6 +57,7 @@ ext {
databindingVersion = '3.1.3'
supportLibsVersion = '27.1.1'
streamsupportVersion = '1.6.0'
+ jsr305Version = '3.0.2'
}
dependencies {
@@ -67,6 +69,7 @@ dependencies {
implementation "com.android.support:support-annotations:$supportLibsVersion"
implementation "net.sourceforge.streamsupport:android-retrofuture:$streamsupportVersion"
implementation "net.sourceforge.streamsupport:android-retrostreams:$streamsupportVersion"
+ implementation "com.google.code.findbugs:jsr305:$jsr305Version"
}
tasks.withType(JavaCompile) {
diff --git a/app/nonnull.gradle b/app/nonnull.gradle
new file mode 100644
index 00000000..014e999a
--- /dev/null
+++ b/app/nonnull.gradle
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2018 Eric Kuck .
+ * 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"
+}
+
diff --git a/app/src/main/java/com/wireguard/android/Application.java b/app/src/main/java/com/wireguard/android/Application.java
index f3045831..f4a4290e 100644
--- a/app/src/main/java/com/wireguard/android/Application.java
+++ b/app/src/main/java/com/wireguard/android/Application.java
@@ -10,6 +10,7 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatDelegate;
import com.wireguard.android.backend.Backend;
@@ -26,18 +27,19 @@ import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Objects;
import java.util.concurrent.Executor;
public class Application extends android.app.Application {
- private static WeakReference weakSelf;
- private AsyncWorker asyncWorker;
- private Backend backend;
- private RootShell rootShell;
- private SharedPreferences sharedPreferences;
- private ToolsInstaller toolsInstaller;
- private TunnelManager tunnelManager;
- private Handler handler;
- private Collection haveBackendCallbacks = new ArrayList<>();
+ @SuppressWarnings("NullableProblems") private static WeakReference weakSelf;
+ @SuppressWarnings("NullableProblems") private AsyncWorker asyncWorker;
+ @SuppressWarnings("NullableProblems") private RootShell rootShell;
+ @SuppressWarnings("NullableProblems") private SharedPreferences sharedPreferences;
+ @SuppressWarnings("NullableProblems") private ToolsInstaller toolsInstaller;
+ @SuppressWarnings("NullableProblems") private TunnelManager tunnelManager;
+ @SuppressWarnings("NullableProblems") private Handler handler;
+ @Nullable private Backend backend;
+ @Nullable private Collection haveBackendCallbacks = new ArrayList<>();
private final Object haveBackendCallbacksLock = new Object();
public Application() {
@@ -65,9 +67,11 @@ public class Application extends android.app.Application {
if (app.backend == null)
app.backend = new GoBackend(app.getApplicationContext());
synchronized (app.haveBackendCallbacksLock) {
- for (final BackendCallback callback : app.haveBackendCallbacks)
- app.handler.post(() -> callback.callback(app.backend));
- app.haveBackendCallbacks = null;
+ if (app.haveBackendCallbacks != null) {
+ for (final BackendCallback callback : app.haveBackendCallbacks)
+ app.handler.post(() -> callback.callback(app.backend));
+ app.haveBackendCallbacks = null;
+ }
}
}
return app.backend;
@@ -82,10 +86,12 @@ public class Application extends android.app.Application {
public static void onHaveBackend(final BackendCallback callback) {
final Application app = get();
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);
- else
+ } else {
app.haveBackendCallbacks.add(callback);
+ }
}
}
diff --git a/app/src/main/java/com/wireguard/android/QuickTileService.java b/app/src/main/java/com/wireguard/android/QuickTileService.java
index 77f01502..008fdee8 100644
--- a/app/src/main/java/com/wireguard/android/QuickTileService.java
+++ b/app/src/main/java/com/wireguard/android/QuickTileService.java
@@ -12,12 +12,11 @@ import android.databinding.Observable;
import android.databinding.Observable.OnPropertyChangedCallback;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;
@@ -41,9 +40,9 @@ public class QuickTileService extends TileService {
private final OnStateChangedCallback onStateChangedCallback = new OnStateChangedCallback();
private final OnTunnelChangedCallback onTunnelChangedCallback = new OnTunnelChangedCallback();
- private Tunnel tunnel;
- private Icon iconOn;
- private Icon iconOff;
+ @Nullable private Tunnel tunnel;
+ @Nullable private Icon iconOn;
+ @Nullable private Icon iconOff;
@SuppressWarnings("deprecation")
@Override
@@ -91,7 +90,7 @@ public class QuickTileService extends TileService {
}
private void onToggleFinished(@SuppressWarnings("unused") final State state,
- final Throwable throwable) {
+ @Nullable final Throwable throwable) {
if (throwable == null)
return;
final String error = ExceptionLoggers.unwrapMessage(throwable);
diff --git a/app/src/main/java/com/wireguard/android/activity/BaseActivity.java b/app/src/main/java/com/wireguard/android/activity/BaseActivity.java
index 9b535d79..51357d89 100644
--- a/app/src/main/java/com/wireguard/android/activity/BaseActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/BaseActivity.java
@@ -9,6 +9,7 @@ package com.wireguard.android.activity;
import android.databinding.CallbackRegistry;
import android.databinding.CallbackRegistry.NotifierCallback;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import com.wireguard.android.Application;
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 final SelectionChangeRegistry selectionChangeRegistry = new SelectionChangeRegistry();
- private Tunnel selectedTunnel;
+ @Nullable private Tunnel selectedTunnel;
- public void addOnSelectedTunnelChangedListener(
- final OnSelectedTunnelChangedListener listener) {
+ public void addOnSelectedTunnelChangedListener(final OnSelectedTunnelChangedListener listener) {
selectionChangeRegistry.add(listener);
}
+ @Nullable
public Tunnel getSelectedTunnel() {
return selectedTunnel;
}
@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.
String savedTunnelName = null;
if (savedInstanceState != null)
@@ -59,14 +60,14 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity {
super.onSaveInstanceState(outState);
}
- protected abstract void onSelectedTunnelChanged(Tunnel oldTunnel, Tunnel newTunnel);
+ protected abstract void onSelectedTunnelChanged(@Nullable Tunnel oldTunnel, @Nullable Tunnel newTunnel);
public void removeOnSelectedTunnelChangedListener(
final OnSelectedTunnelChangedListener listener) {
selectionChangeRegistry.remove(listener);
}
- public void setSelectedTunnel(final Tunnel tunnel) {
+ public void setSelectedTunnel(@Nullable final Tunnel tunnel) {
final Tunnel oldTunnel = selectedTunnel;
if (Objects.equals(oldTunnel, tunnel))
return;
@@ -76,7 +77,7 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity {
}
public interface OnSelectedTunnelChangedListener {
- void onSelectedTunnelChanged(Tunnel oldTunnel, Tunnel newTunnel);
+ void onSelectedTunnelChanged(@Nullable Tunnel oldTunnel, @Nullable Tunnel newTunnel);
}
private static final class SelectionChangeNotifier
diff --git a/app/src/main/java/com/wireguard/android/activity/MainActivity.java b/app/src/main/java/com/wireguard/android/activity/MainActivity.java
index e7f438f2..5a8134f3 100644
--- a/app/src/main/java/com/wireguard/android/activity/MainActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/MainActivity.java
@@ -9,6 +9,7 @@ package com.wireguard.android.activity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
@@ -22,6 +23,8 @@ import com.wireguard.android.fragment.TunnelEditorFragment;
import com.wireguard.android.fragment.TunnelListFragment;
import com.wireguard.android.model.Tunnel;
+import java.util.List;
+
import java9.util.stream.Stream;
/**
@@ -33,6 +36,7 @@ import java9.util.stream.Stream;
public class MainActivity extends BaseActivity {
private static final String KEY_STATE = "fragment_state";
private static final String TAG = "WireGuard/" + MainActivity.class.getSimpleName();
+
private State state = State.EMPTY;
private boolean moveToState(final State nextState) {
@@ -70,13 +74,19 @@ public class MainActivity extends BaseActivity {
@Override
public void onBackPressed() {
- TunnelListFragment fragment = null;
- try {
- fragment = ((TunnelListFragment) getSupportFragmentManager().getFragments().get(0));
- } catch (final ClassCastException ignored) { }
- if (fragment == null || !fragment.collapseActionMenu()) {
- if (!moveToState(State.ofLayer(state.layer - 1)))
- super.onBackPressed();
+ final List fragments = getSupportFragmentManager().getFragments();
+
+ boolean handled = false;
+ if (!fragments.isEmpty() && fragments.get(0) instanceof TunnelListFragment) {
+ handled = ((TunnelListFragment) fragments.get(0)).collapseActionMenu();
+ }
+
+ 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.
@SuppressLint("ClickableViewAccessibility")
@Override
- protected void onCreate(final Bundle savedInstanceState) {
+ protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
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());
if (actionBarId != 0 && findViewById(actionBarId) != null) {
findViewById(actionBarId).setOnTouchListener((v, e) -> {
- try {
- ((TunnelListFragment) getSupportFragmentManager().getFragments().get(0)).collapseActionMenu();
- } catch (final ClassCastException ignored) { }
+ final List fragments = getSupportFragmentManager().getFragments();
+ if (!fragments.isEmpty() && fragments.get(0) instanceof TunnelListFragment) {
+ ((TunnelListFragment) fragments.get(0)).collapseActionMenu();
+ }
return false;
});
}
@@ -142,7 +153,7 @@ public class MainActivity extends BaseActivity {
}
@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);
}
@@ -157,10 +168,10 @@ public class MainActivity extends BaseActivity {
DETAIL(TunnelDetailFragment.class, 2),
EDITOR(TunnelEditorFragment.class, 3);
- private final String fragment;
+ @Nullable private final String fragment;
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.layer = layer;
}
diff --git a/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java b/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
index ed2da4dc..066d377f 100644
--- a/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java
@@ -8,12 +8,13 @@ package com.wireguard.android.activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.preference.PreferenceScreen;
+import android.util.SparseArray;
import android.view.MenuItem;
import com.wireguard.android.Application;
@@ -22,16 +23,14 @@ import com.wireguard.android.backend.WgQuickBackend;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* Interface for changing application-global persistent settings.
*/
public class SettingsActivity extends ThemeChangeAwareActivity {
- private final Map permissionRequestCallbacks = new HashMap<>();
+ private final SparseArray permissionRequestCallbacks = new SparseArray<>();
private int permissionRequestCounter;
public void ensurePermissions(final String[] permissions, final PermissionRequestCallback cb) {
@@ -54,7 +53,7 @@ public class SettingsActivity extends ThemeChangeAwareActivity {
}
@Override
- protected void onCreate(final Bundle savedInstanceState) {
+ protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
getSupportFragmentManager().beginTransaction()
@@ -76,8 +75,8 @@ public class SettingsActivity extends ThemeChangeAwareActivity {
@Override
public void onRequestPermissionsResult(final int requestCode,
- @NonNull final String[] permissions,
- @NonNull final int[] grantResults) {
+ final String[] permissions,
+ final int[] grantResults) {
final PermissionRequestCallback f = permissionRequestCallbacks.get(requestCode);
if (f != null) {
permissionRequestCallbacks.remove(requestCode);
diff --git a/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java b/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java
index be61f256..d85a0170 100644
--- a/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java
@@ -8,6 +8,7 @@ package com.wireguard.android.activity;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate;
import android.util.Log;
@@ -19,7 +20,7 @@ import java.lang.reflect.Field;
public abstract class ThemeChangeAwareActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "WireGuard/" + ThemeChangeAwareActivity.class.getSimpleName();
- private static Resources lastResources;
+ @Nullable private static Resources lastResources;
private static boolean lastDarkMode;
private static synchronized void invalidateDrawableCache(final Resources resources, final boolean darkMode) {
if (resources == lastResources && darkMode == lastDarkMode)
@@ -51,7 +52,7 @@ public abstract class ThemeChangeAwareActivity extends AppCompatActivity impleme
@Override
- protected void onCreate(final Bundle savedInstanceState) {
+ protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
diff --git a/app/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.java b/app/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.java
index 044548ce..99bb4141 100644
--- a/app/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.java
@@ -7,6 +7,7 @@
package com.wireguard.android.activity;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import com.wireguard.android.fragment.TunnelEditorFragment;
import com.wireguard.android.model.Tunnel;
@@ -18,7 +19,7 @@ import com.wireguard.android.model.Tunnel;
public class TunnelCreatorActivity extends BaseActivity {
@Override
@SuppressWarnings("UnnecessaryFullyQualifiedName")
- protected void onCreate(final Bundle savedInstanceState) {
+ protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
getSupportFragmentManager().beginTransaction()
@@ -28,7 +29,7 @@ public class TunnelCreatorActivity extends BaseActivity {
}
@Override
- protected void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
+ protected void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
finish();
}
}
diff --git a/app/src/main/java/com/wireguard/android/backend/GoBackend.java b/app/src/main/java/com/wireguard/android/backend/GoBackend.java
index 66d3698f..a075913f 100644
--- a/app/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/app/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -10,6 +10,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.ParcelFileDescriptor;
+import android.support.annotation.Nullable;
import android.support.v4.util.ArraySet;
import android.util.Log;
@@ -29,6 +30,7 @@ import com.wireguard.crypto.KeyEncoding;
import java.net.InetAddress;
import java.util.Collections;
import java.util.Formatter;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -40,7 +42,7 @@ public final class GoBackend implements Backend {
private static CompletableFuture vpnService = new CompletableFuture<>();
private final Context context;
- private Tunnel currentTunnel;
+ @Nullable private Tunnel currentTunnel;
private int currentTunnelHandle = -1;
public GoBackend(final Context context) {
@@ -114,12 +116,14 @@ public final class GoBackend implements Backend {
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 {
if (state == State.UP) {
Log.i(TAG, "Bringing tunnel up");
+ Objects.requireNonNull(config, "Trying to bring up a tunnel with no config");
+
if (VpnService.prepare(context) != null)
throw new Exception("VPN service not authorized by user");
@@ -245,7 +249,7 @@ public final class GoBackend implements Backend {
}
@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);
if (intent == null || intent.getComponent() == null || !intent.getComponent().getPackageName().equals(getPackageName())) {
Log.d(TAG, "Service started by Always-on VPN feature");
diff --git a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java b/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
index fbc43dc0..25634841 100644
--- a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
+++ b/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
@@ -7,6 +7,7 @@
package com.wireguard.android.backend;
import android.content.Context;
+import android.support.annotation.Nullable;
import android.util.Log;
import com.wireguard.android.Application;
@@ -21,6 +22,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java9.util.stream.Collectors;
@@ -106,8 +108,9 @@ public final class WgQuickBackend implements Backend {
return getState(tunnel);
}
- private void setStateInternal(final Tunnel tunnel, final Config config, final State state)
- throws Exception {
+ private void setStateInternal(final Tunnel tunnel, @Nullable final Config config, final State state) throws Exception {
+ Objects.requireNonNull(config, "Trying to set state with a null config");
+
final File tempFile = new File(localTemporaryDir, tunnel.getName() + ".conf");
try (final FileOutputStream stream = new FileOutputStream(tempFile, false)) {
stream.write(config.toString().getBytes(StandardCharsets.UTF_8));
diff --git a/app/src/main/java/com/wireguard/android/databinding/ItemChangeListener.java b/app/src/main/java/com/wireguard/android/databinding/ItemChangeListener.java
index 0a87d491..909adddc 100644
--- a/app/src/main/java/com/wireguard/android/databinding/ItemChangeListener.java
+++ b/app/src/main/java/com/wireguard/android/databinding/ItemChangeListener.java
@@ -9,6 +9,7 @@ package com.wireguard.android.databinding;
import android.databinding.DataBindingUtil;
import android.databinding.ObservableList;
import android.databinding.ViewDataBinding;
+import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -16,6 +17,7 @@ import android.view.ViewGroup;
import com.wireguard.android.BR;
import java.lang.ref.WeakReference;
+import java.util.Objects;
/**
* Helper class for binding an ObservableList to the children of a ViewGroup.
@@ -26,7 +28,7 @@ class ItemChangeListener {
private final ViewGroup container;
private final int layoutId;
private final LayoutInflater layoutInflater;
- private ObservableList list;
+ @Nullable private ObservableList list;
ItemChangeListener(final ViewGroup container, final int layoutId) {
this.container = container;
@@ -34,17 +36,21 @@ class ItemChangeListener {
layoutInflater = LayoutInflater.from(container.getContext());
}
- private View getView(final int position, final View convertView) {
- ViewDataBinding binding = DataBindingUtil.getBinding(convertView);
- if (binding == null)
+ private View getView(final int position, @Nullable final View convertView) {
+ ViewDataBinding binding = convertView != null ? DataBindingUtil.getBinding(convertView) : null;
+ if (binding == null) {
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.item, list.get(position));
binding.executePendingBindings();
return binding.getRoot();
}
- void setList(final ObservableList newList) {
+ void setList(@Nullable final ObservableList newList) {
if (list != null)
list.removeOnListChangedCallback(callback);
list = newList;
diff --git a/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java b/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java
index d45e60a5..835a3dc4 100644
--- a/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java
+++ b/app/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.java
@@ -10,7 +10,7 @@ import android.content.Context;
import android.databinding.DataBindingUtil;
import android.databinding.ObservableList;
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.Adapter;
import android.view.LayoutInflater;
@@ -31,8 +31,8 @@ public class ObservableKeyedRecyclerViewAdapter>
private final OnListChangedCallback callback = new OnListChangedCallback<>(this);
private final int layoutId;
private final LayoutInflater layoutInflater;
- private ObservableKeyedList list;
- private RowConfigurationHandler rowConfigurationHandler;
+ @Nullable private ObservableKeyedList list;
+ @Nullable private RowConfigurationHandler rowConfigurationHandler;
ObservableKeyedRecyclerViewAdapter(final Context context, final int layoutId,
final ObservableKeyedList list) {
@@ -46,6 +46,7 @@ public class ObservableKeyedRecyclerViewAdapter>
return list != null ? list.size() : 0;
}
+ @Nullable
private E getItem(final int position) {
if (list == null || position < 0 || position >= list.size())
return null;
@@ -58,30 +59,34 @@ public class ObservableKeyedRecyclerViewAdapter>
return key != null ? key.hashCode() : -1;
}
+ @Nullable
private K getKey(final int position) {
final E item = getItem(position);
return item != null ? item.getKey() : null;
}
- @NonNull @Override
- public ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
+ @Override
+ public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
return new ViewHolder(DataBindingUtil.inflate(layoutInflater, layoutId, parent, false));
}
@SuppressWarnings("unchecked")
@Override
- public void onBindViewHolder(@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.key, getKey(position));
holder.binding.setVariable(BR.item, getItem(position));
holder.binding.executePendingBindings();
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 newList) {
+ void setList(@Nullable final ObservableKeyedList newList) {
if (list != null)
list.removeOnListChangedCallback(callback);
list = newList;
diff --git a/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java b/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java
index 15571297..50de0c39 100644
--- a/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.java
@@ -39,7 +39,7 @@ public class AppListDialogFragment extends DialogFragment {
private static final String KEY_EXCLUDED_APPS = "excludedApps";
- private List currentlyExcludedApps;
+ private final List currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
private final ObservableKeyedList appData = new ObservableKeyedArrayList<>();
public static AppListDialogFragment newInstance(final String[] excludedApps, final T target) {
@@ -51,24 +51,12 @@ public class AppListDialogFragment extends DialogFragment {
return fragment;
}
- @Override
- public void onCreate(@Nullable final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
- }
-
- @Override
- public void onAttach(final Context context) {
- super.onAttach(context);
- }
-
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
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();
alertDialogBuilder.setView(binding.getRoot());
diff --git a/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java b/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java
index e1d4c87b..f4c6ea81 100644
--- a/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/BaseFragment.java
@@ -10,7 +10,7 @@ import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
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 int REQUEST_CODE_VPN_PERMISSION = 23491;
- private BaseActivity activity;
- private Tunnel pendingTunnel;
- private Boolean pendingTunnelUp;
+ @Nullable private BaseActivity activity;
+ @Nullable private Tunnel pendingTunnel;
+ @Nullable private Boolean pendingTunnelUp;
+ @Nullable
protected Tunnel getSelectedTunnel() {
return activity != null ? activity.getSelectedTunnel() : null;
}
@@ -65,7 +66,7 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
}
@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);
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)
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) -> {
if (throwable == null)
return;
diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
index 5c35686f..cb1712fc 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
@@ -7,7 +7,7 @@
package com.wireguard.android.fragment;
import android.os.Bundle;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -24,14 +24,16 @@ import com.wireguard.config.Config;
*/
public class TunnelDetailFragment extends BaseFragment {
- private TunnelDetailFragmentBinding binding;
+ @Nullable private TunnelDetailFragmentBinding binding;
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
- public void onCreate(final Bundle savedInstanceState) {
+ public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@@ -42,8 +44,8 @@ public class TunnelDetailFragment extends BaseFragment {
}
@Override
- public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
- final Bundle savedInstanceState) {
+ public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
+ @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
binding = TunnelDetailFragmentBinding.inflate(inflater, container, false);
binding.executePendingBindings();
@@ -57,7 +59,7 @@ public class TunnelDetailFragment extends BaseFragment {
}
@Override
- public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
+ public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
if (binding == null)
return;
binding.setTunnel(newTunnel);
@@ -68,7 +70,11 @@ public class TunnelDetailFragment extends BaseFragment {
}
@Override
- public void onViewStateRestored(final Bundle savedInstanceState) {
+ public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
+ if (binding == null) {
+ return;
+ }
+
binding.setFragment(this);
onSelectedTunnelChanged(null, getSelectedTunnel());
super.onViewStateRestored(savedInstanceState);
diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
index f6f1483a..a6e315f9 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java
@@ -11,7 +11,7 @@ import android.content.Context;
import android.databinding.Observable;
import android.databinding.ObservableList;
import android.os.Bundle;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.FragmentManager;
import android.util.Log;
@@ -37,6 +37,7 @@ import com.wireguard.config.Config;
import com.wireguard.config.Peer;
import java.util.List;
+import java.util.Objects;
/**
* 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 TAG = "WireGuard/" + TunnelEditorFragment.class.getSimpleName();
- private TunnelEditorFragmentBinding binding;
- private Tunnel tunnel;
+ @Nullable private TunnelEditorFragmentBinding binding;
+ @Nullable private Tunnel tunnel;
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,
- final Throwable throwable) {
+ @Nullable final Throwable throwable) {
final String message;
if (throwable == null) {
message = getString(R.string.config_save_success, savedTunnel.getName());
@@ -73,7 +76,7 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
}
@Override
- public void onCreate(final Bundle savedInstanceState) {
+ public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@@ -124,8 +127,8 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
};
@Override
- public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
- final Bundle savedInstanceState) {
+ public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
+ @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
binding = TunnelEditorFragmentBinding.inflate(inflater, container, false);
binding.addOnPropertyChangedCallback(breakObjectOrientedLayeringHandler);
@@ -197,14 +200,14 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
}
@Override
- public void onSaveInstanceState(@NonNull final Bundle outState) {
+ public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(KEY_LOCAL_CONFIG, binding.getConfig());
outState.putString(KEY_ORIGINAL_NAME, tunnel == null ? null : tunnel.getName());
super.onSaveInstanceState(outState);
}
@Override
- public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
+ public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
tunnel = newTunnel;
if (binding == null)
return;
@@ -213,7 +216,7 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
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;
if (throwable == null) {
tunnel = newTunnel;
@@ -232,7 +235,7 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
}
private void onTunnelRenamed(final Tunnel renamedTunnel, final Config newConfig,
- final Throwable throwable) {
+ @Nullable final Throwable throwable) {
final String message;
if (throwable == null) {
message = getString(R.string.tunnel_rename_success, renamedTunnel.getName());
@@ -251,7 +254,11 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
}
@Override
- public void onViewStateRestored(final Bundle savedInstanceState) {
+ public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
+ if (binding == null) {
+ return;
+ }
+
binding.setFragment(this);
if (savedInstanceState == null) {
@@ -271,15 +278,16 @@ public class TunnelEditorFragment extends BaseFragment implements AppExclusionLi
public void onRequestSetExcludedApplications(@SuppressWarnings("unused") final View view) {
final FragmentManager fragmentManager = getFragmentManager();
- if (fragmentManager != null) {
+ if (fragmentManager != null && binding != null) {
final String[] excludedApps = Attribute.stringToList(binding.getConfig().getInterfaceSection().getExcludedApplications());
final AppListDialogFragment fragment = AppListDialogFragment.newInstance(excludedApps, this);
- fragment.show(getFragmentManager(), null);
+ fragment.show(fragmentManager, null);
}
}
@Override
public void onExcludedAppsSelected(final List excludedApps) {
+ Objects.requireNonNull(binding, "Tried to set excluded apps while no view was loaded");
binding.getConfig().getInterfaceSection().setExcludedApplications(Attribute.iterableToString(excludedApps));
}
diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
index 5dda6cfe..dd8e1337 100644
--- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
+++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java
@@ -15,7 +15,6 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.OpenableColumns;
-import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
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 final ActionModeListener actionModeListener = new ActionModeListener();
- private ActionMode actionMode;
- private TunnelListFragmentBinding binding;
+ @Nullable private ActionMode actionMode;
+ @Nullable private TunnelListFragmentBinding binding;
public boolean collapseActionMenu() {
- if (binding.createMenu.isExpanded()) {
+ if (binding != null && binding.createMenu.isExpanded()) {
binding.createMenu.collapse();
return true;
}
return false;
}
- private void importTunnel(final Uri uri) {
+ private void importTunnel(@Nullable final Uri uri) {
final Activity activity = getActivity();
- if (activity == null)
+ if (activity == null || uri == null)
return;
final ContentResolver contentResolver = activity.getContentResolver();
@@ -165,10 +164,10 @@ public class TunnelListFragment extends BaseFragment {
}
@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) {
case REQUEST_IMPORT:
- if (resultCode == Activity.RESULT_OK)
+ if (resultCode == Activity.RESULT_OK && data != null)
importTunnel(data.getData());
return;
default:
@@ -178,8 +177,8 @@ public class TunnelListFragment extends BaseFragment {
@SuppressLint("ClickableViewAccessibility")
@Override
- public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
- final Bundle savedInstanceState) {
+ public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
+ @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
binding = TunnelListFragmentBinding.inflate(inflater, container, false);
@@ -216,16 +215,18 @@ public class TunnelListFragment extends BaseFragment {
@Override
public void onPause() {
- binding.createMenu.collapse();
+ if (binding != null) {
+ binding.createMenu.collapse();
+ }
super.onPause();
}
@Override
- public void onSelectedTunnelChanged(final Tunnel oldTunnel, final Tunnel newTunnel) {
+ public void onSelectedTunnelChanged(@Nullable final Tunnel oldTunnel, @Nullable final Tunnel newTunnel) {
// Do nothing.
}
- private void onTunnelDeletionFinished(final Integer count, final Throwable throwable) {
+ private void onTunnelDeletionFinished(final Integer count, @Nullable final Throwable throwable) {
final String message;
if (throwable == null) {
message = getResources().getQuantityString(R.plurals.delete_success, count, count);
@@ -265,8 +266,13 @@ public class TunnelListFragment extends BaseFragment {
}
@Override
- public void onViewStateRestored(final Bundle savedInstanceState) {
+ public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
+
+ if (binding == null) {
+ return;
+ }
+
binding.setFragment(this);
binding.setTunnels(Application.getTunnelManager().getTunnels());
binding.setRowConfigurationHandler((ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler) (binding, tunnel, position) -> {
@@ -290,7 +296,7 @@ public class TunnelListFragment extends BaseFragment {
private final class ActionModeListener implements ActionMode.Callback {
private final Collection checkedItems = new HashSet<>();
- private Resources resources;
+ @Nullable private Resources resources;
@Override
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
@@ -357,7 +363,9 @@ public class TunnelListFragment extends BaseFragment {
actionMode.finish();
}
- binding.tunnelList.getAdapter().notifyItemChanged(position);
+ if (binding != null) {
+ binding.tunnelList.getAdapter().notifyItemChanged(position);
+ }
updateTitle(actionMode);
}
diff --git a/app/src/main/java/com/wireguard/android/model/ApplicationData.java b/app/src/main/java/com/wireguard/android/model/ApplicationData.java
index 26f81030..73dfb4a9 100644
--- a/app/src/main/java/com/wireguard/android/model/ApplicationData.java
+++ b/app/src/main/java/com/wireguard/android/model/ApplicationData.java
@@ -9,36 +9,32 @@ package com.wireguard.android.model;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
import com.wireguard.android.BR;
import com.wireguard.util.Keyed;
public class ApplicationData extends BaseObservable implements Keyed {
- @NonNull private final Drawable icon;
- @NonNull private final String name;
- @NonNull private final String packageName;
+ private final Drawable icon;
+ private final String name;
+ private final String packageName;
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.name = name;
this.packageName = packageName;
this.excludedFromTunnel = excludedFromTunnel;
}
- @NonNull
public Drawable getIcon() {
return icon;
}
- @NonNull
public String getName() {
return name;
}
- @NonNull
public String getPackageName() {
return packageName;
}
diff --git a/app/src/main/java/com/wireguard/android/model/Tunnel.java b/app/src/main/java/com/wireguard/android/model/Tunnel.java
index 5ea2c0a8..b0d2c1da 100644
--- a/app/src/main/java/com/wireguard/android/model/Tunnel.java
+++ b/app/src/main/java/com/wireguard/android/model/Tunnel.java
@@ -8,13 +8,12 @@ package com.wireguard.android.model;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
-import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.wireguard.android.BR;
import com.wireguard.android.util.ExceptionLoggers;
-import com.wireguard.util.Keyed;
import com.wireguard.config.Config;
+import com.wireguard.util.Keyed;
import java.util.regex.Pattern;
@@ -30,20 +29,20 @@ public class Tunnel extends BaseObservable implements Keyed {
private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,15}");
private final TunnelManager manager;
- private Config config;
+ @Nullable private Config config;
private String name;
private State state;
- private Statistics statistics;
+ @Nullable private Statistics statistics;
- Tunnel(@NonNull final TunnelManager manager, @NonNull final String name,
- @Nullable final Config config, @NonNull final State state) {
+ Tunnel(final TunnelManager manager, final String name,
+ @Nullable final Config config, final State state) {
this.manager = manager;
this.name = name;
this.config = config;
this.state = state;
}
- public static boolean isNameInvalid(@NonNull final CharSequence name) {
+ public static boolean isNameInvalid(final CharSequence name) {
return !NAME_PATTERN.matcher(name).matches();
}
@@ -51,7 +50,7 @@ public class Tunnel extends BaseObservable implements Keyed {
return manager.delete(this);
}
- @Bindable
+ @Bindable @Nullable
public Config getConfig() {
if (config == null)
manager.getTunnelConfig(this).whenComplete(ExceptionLoggers.E);
@@ -83,7 +82,7 @@ public class Tunnel extends BaseObservable implements Keyed {
return TunnelManager.getTunnelState(this);
}
- @Bindable
+ @Bindable @Nullable
public Statistics getStatistics() {
// FIXME: Check age of statistics.
if (statistics == null)
@@ -118,25 +117,26 @@ public class Tunnel extends BaseObservable implements Keyed {
return state;
}
- Statistics onStatisticsChanged(final Statistics statistics) {
+ @Nullable
+ Statistics onStatisticsChanged(@Nullable final Statistics statistics) {
this.statistics = statistics;
notifyPropertyChanged(BR.statistics);
return statistics;
}
- public CompletionStage setConfig(@NonNull final Config config) {
+ public CompletionStage setConfig(final Config config) {
if (!config.equals(this.config))
return manager.setTunnelConfig(this, config);
return CompletableFuture.completedFuture(this.config);
}
- public CompletionStage setName(@NonNull final String name) {
+ public CompletionStage setName(final String name) {
if (!name.equals(this.name))
return manager.setTunnelName(this, name);
return CompletableFuture.completedFuture(this.name);
}
- public CompletionStage setState(@NonNull final State state) {
+ public CompletionStage setState(final State state) {
if (state != this.state)
return manager.setTunnelState(this, state);
return CompletableFuture.completedFuture(this.state);
@@ -152,6 +152,5 @@ public class Tunnel extends BaseObservable implements Keyed {
}
}
- public static class Statistics extends BaseObservable {
- }
+ public static class Statistics extends BaseObservable { }
}
diff --git a/app/src/main/java/com/wireguard/android/model/TunnelManager.java b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
index a9998d5a..f7b18c07 100644
--- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java
+++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
@@ -11,7 +11,7 @@ import android.content.Context;
import android.content.Intent;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import com.wireguard.android.Application;
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 final ConfigStore configStore;
- private final ObservableSortedKeyedList tunnels =
- new ObservableSortedKeyedArrayList<>(COMPARATOR);
- private Tunnel lastUsedTunnel;
+ private final ObservableSortedKeyedList tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR);
+ @Nullable private Tunnel lastUsedTunnel;
private boolean haveLoaded;
private final ArrayList> delayedLoadRestoreTunnels = new ArrayList<>();
@@ -57,13 +56,13 @@ public final class TunnelManager extends BaseObservable {
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);
tunnels.add(tunnel);
return tunnel;
}
- public CompletionStage create(@NonNull final String name, final Config config) {
+ public CompletionStage create(final String name, @Nullable final Config config) {
if (Tunnel.isNameInvalid(name))
return CompletableFuture.failedFuture(new IllegalArgumentException("Invalid name"));
if (tunnels.containsKey(name)) {
@@ -102,7 +101,7 @@ public final class TunnelManager extends BaseObservable {
});
}
- @Bindable
+ @Bindable @Nullable
public Tunnel getLastUsedTunnel() {
return lastUsedTunnel;
}
@@ -191,7 +190,7 @@ public final class TunnelManager extends BaseObservable {
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)
return;
lastUsedTunnel = tunnel;
@@ -256,7 +255,7 @@ public final class TunnelManager extends BaseObservable {
public static final class IntentReceiver extends BroadcastReceiver {
@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();
if (intent == null)
return;
diff --git a/app/src/main/java/com/wireguard/android/preference/LogExporterPreference.java b/app/src/main/java/com/wireguard/android/preference/LogExporterPreference.java
index f9ac9a41..a96cb9c8 100644
--- a/app/src/main/java/com/wireguard/android/preference/LogExporterPreference.java
+++ b/app/src/main/java/com/wireguard/android/preference/LogExporterPreference.java
@@ -10,6 +10,7 @@ import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
+import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
@@ -33,7 +34,7 @@ import java.io.InputStreamReader;
public class LogExporterPreference extends Preference {
private static final String TAG = "WireGuard/" + LogExporterPreference.class.getSimpleName();
- private String exportedFilePath;
+ @Nullable private String exportedFilePath;
public LogExporterPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
@@ -73,7 +74,7 @@ public class LogExporterPreference extends Preference {
}).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) {
final String error = ExceptionLoggers.unwrapMessage(throwable);
final String message = getContext().getString(R.string.log_export_error, error);
diff --git a/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java b/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java
index 44599edc..4006d0e8 100644
--- a/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java
+++ b/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java
@@ -7,7 +7,7 @@
package com.wireguard.android.preference;
import android.content.Context;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
@@ -43,7 +43,7 @@ public class ToolsInstallerPreference extends Preference {
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)
setState(State.INITIAL);
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);
}
- private void onInstallResult(final Integer result, final Throwable throwable) {
+ private void onInstallResult(final Integer result, @Nullable final Throwable throwable) {
if (throwable != null)
setState(State.FAILURE);
else if ((result & (ToolsInstaller.YES | ToolsInstaller.MAGISK)) == (ToolsInstaller.YES | ToolsInstaller.MAGISK))
@@ -73,7 +73,7 @@ public class ToolsInstallerPreference extends Preference {
setState(State.FAILURE);
}
- private void setState(@NonNull final State state) {
+ private void setState(final State state) {
if (this.state == state)
return;
this.state = state;
diff --git a/app/src/main/java/com/wireguard/android/preference/VersionPreference.java b/app/src/main/java/com/wireguard/android/preference/VersionPreference.java
index de34047d..525396bc 100644
--- a/app/src/main/java/com/wireguard/android/preference/VersionPreference.java
+++ b/app/src/main/java/com/wireguard/android/preference/VersionPreference.java
@@ -9,6 +9,7 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.support.annotation.Nullable;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
@@ -17,7 +18,7 @@ import com.wireguard.android.BuildConfig;
import com.wireguard.android.R;
public class VersionPreference extends Preference {
- private String versionSummary;
+ @Nullable private String versionSummary;
public VersionPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
@@ -33,7 +34,7 @@ public class VersionPreference extends Preference {
});
}
- @Override
+ @Override @Nullable
public CharSequence getSummary() {
return versionSummary;
}
diff --git a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java
index 16094007..a1477214 100644
--- a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java
+++ b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java
@@ -10,6 +10,7 @@ import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
+import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
@@ -40,7 +41,7 @@ import java9.util.concurrent.CompletableFuture;
public class ZipExporterPreference extends Preference {
private static final String TAG = "WireGuard/" + ZipExporterPreference.class.getSimpleName();
- private String exportedFilePath;
+ @Nullable private String exportedFilePath;
public ZipExporterPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
@@ -79,7 +80,7 @@ public class ZipExporterPreference extends Preference {
}).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) {
final String error = ExceptionLoggers.unwrapMessage(throwable);
final String message = getContext().getString(R.string.zip_export_error, error);
diff --git a/app/src/main/java/com/wireguard/android/util/ExceptionLoggers.java b/app/src/main/java/com/wireguard/android/util/ExceptionLoggers.java
index b8c0c4fa..70d97fb1 100644
--- a/app/src/main/java/com/wireguard/android/util/ExceptionLoggers.java
+++ b/app/src/main/java/com/wireguard/android/util/ExceptionLoggers.java
@@ -6,8 +6,9 @@
package com.wireguard.android.util;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.util.Log;
+
import java9.util.concurrent.CompletionException;
import java9.util.function.BiConsumer;
@@ -34,7 +35,6 @@ public enum ExceptionLoggers implements BiConsumer