diff options
48 files changed, 481 insertions, 310 deletions
@@ -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 @@ <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> </XML> <codeStyleSettings language="JAVA"> + <option name="METHOD_ANNOTATION_WRAP" value="0" /> + <option name="FIELD_ANNOTATION_WRAP" value="0" /> <arrangement> <groups /> <rules> 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 <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" +} + 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<Application> weakSelf; - private AsyncWorker asyncWorker; - private Backend backend; - private RootShell rootShell; - private SharedPreferences sharedPreferences; - private ToolsInstaller toolsInstaller; - private TunnelManager tunnelManager; - private Handler handler; - private Collection<BackendCallback> haveBackendCallbacks = new ArrayList<>(); + @SuppressWarnings("NullableProblems") private static WeakReference<Application> 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<BackendCallback> 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<Fragment> 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<Fragment> 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<Integer, PermissionRequestCallback> permissionRequestCallbacks = new HashMap<>(); + private final SparseArray<PermissionRequestCallback> 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> 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<T> { private final ViewGroup container; private final int layoutId; private final LayoutInflater layoutInflater; - private ObservableList<T> list; + @Nullable private ObservableList<T> list; ItemChangeListener(final ViewGroup container, final int layoutId) { this.container = container; @@ -34,17 +36,21 @@ class ItemChangeListener<T> { 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<T> newList) { + void setList(@Nullable final ObservableList<T> 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<K, E extends Keyed<? extends K>> private final OnListChangedCallback<E> callback = new OnListChangedCallback<>(this); private final int layoutId; private final LayoutInflater layoutInflater; - private ObservableKeyedList<K, E> list; - private RowConfigurationHandler rowConfigurationHandler; + @Nullable private ObservableKeyedList<K, E> list; + @Nullable private RowConfigurationHandler rowConfigurationHandler; ObservableKeyedRecyclerViewAdapter(final Context context, final int layoutId, final ObservableKeyedList<K, E> list) { @@ -46,6 +46,7 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>> 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<K, E extends Keyed<? extends K>> 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<K, E> newList) { + void setList(@Nullable final ObservableKeyedList<K, E> 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<String> currentlyExcludedApps; + private final List<String> currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS)); private final ObservableKeyedList<String, ApplicationData> appData = new ObservableKeyedArrayList<>(); public static <T extends Fragment & AppExclusionListener> AppListDialogFragment newInstance(final String[] excludedApps, final T target) { @@ -52,23 +52,11 @@ public class AppListDialogFragment extends DialogFragment { } @Override - public void onCreate(@Nullable final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS)); - } - - @Override - public 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<String> excludedApps) { + Objects.requireNonNull(binding, "Tried to set excluded apps while no view was loaded"); binding.getConfig().getInterfaceSection().setExcludedApplications(Attribute.iterableToString(excludedApps)); } diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java index 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<TunnelListItemBinding, Tunnel>) (binding, tunnel, position) -> { @@ -290,7 +296,7 @@ public class TunnelListFragment extends BaseFragment { private final class ActionModeListener implements ActionMode.Callback { private final Collection<Integer> 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<String> { - @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<String> { 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<String> { 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<String> { 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<String> { return state; } - Statistics onStatisticsChanged(final Statistics statistics) { + @Nullable + Statistics onStatisticsChanged(@Nullable final Statistics statistics) { this.statistics = statistics; notifyPropertyChanged(BR.statistics); return statistics; } - public CompletionStage<Config> setConfig(@NonNull final Config config) { + public CompletionStage<Config> setConfig(final Config config) { if (!config.equals(this.config)) return manager.setTunnelConfig(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)) return manager.setTunnelName(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) return manager.setTunnelState(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 { } } 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<String, Tunnel> tunnels = - new ObservableSortedKeyedArrayList<>(COMPARATOR); - private Tunnel lastUsedTunnel; + private final ObservableSortedKeyedList<String, Tunnel> tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR); + @Nullable private Tunnel lastUsedTunnel; private boolean haveLoaded; private final ArrayList<CompletableFuture<Void>> 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<Tunnel> create(@NonNull final String name, final Config config) { + public CompletionStage<Tunnel> 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<Object, Throwable> { return throwable; } - @NonNull public static String unwrapMessage(Throwable throwable) { throwable = unwrap(throwable); final String message = throwable.getMessage(); @@ -44,7 +44,7 @@ public enum ExceptionLoggers implements BiConsumer<Object, Throwable> { } @Override - public void accept(final Object result, final Throwable throwable) { + public void accept(final Object result, @Nullable final Throwable throwable) { if (throwable != null) Log.println(Log.ERROR, TAG, Log.getStackTraceString(throwable)); else if (priority <= Log.DEBUG) diff --git a/app/src/main/java/com/wireguard/android/util/ObservableKeyedArrayList.java b/app/src/main/java/com/wireguard/android/util/ObservableKeyedArrayList.java index 1e064e42..0be3c005 100644 --- a/app/src/main/java/com/wireguard/android/util/ObservableKeyedArrayList.java +++ b/app/src/main/java/com/wireguard/android/util/ObservableKeyedArrayList.java @@ -7,7 +7,7 @@ package com.wireguard.android.util; import android.databinding.ObservableArrayList; -import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import com.wireguard.util.Keyed; @@ -25,28 +25,28 @@ import java.util.Objects; public class ObservableKeyedArrayList<K, E extends Keyed<? extends K>> extends ObservableArrayList<E> implements ObservableKeyedList<K, E> { @Override - public boolean add(final E e) { + public boolean add(@Nullable final E e) { if (e == null) throw new NullPointerException("Trying to add a null element"); return super.add(e); } @Override - public void add(final int index, final E e) { + public void add(final int index, @Nullable final E e) { if (e == null) throw new NullPointerException("Trying to add a null element"); super.add(index, e); } @Override - public boolean addAll(@NonNull final Collection<? extends E> c) { + public boolean addAll(final Collection<? extends E> c) { if (c.contains(null)) throw new NullPointerException("Trying to add a collection with null element(s)"); return super.addAll(c); } @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)) throw new NullPointerException("Trying to add a collection with null element(s)"); return super.addAll(index, c); @@ -65,13 +65,13 @@ public class ObservableKeyedArrayList<K, E extends Keyed<? extends K>> return indexOfKey(key) >= 0; } - @Override + @Override @Nullable public E get(final K key) { final int index = indexOfKey(key); return index >= 0 ? get(index) : null; } - @Override + @Override @Nullable public E getLast(final K key) { final int index = lastIndexOfKey(key); return index >= 0 ? get(index) : null; @@ -100,7 +100,7 @@ public class ObservableKeyedArrayList<K, E extends Keyed<? extends K>> } @Override - public E set(final int index, final E e) { + public E set(final int index, @Nullable final E e) { if (e == null) throw new NullPointerException("Trying to set a null key"); return super.set(index, e); diff --git a/app/src/main/java/com/wireguard/android/util/ObservableSortedKeyedArrayList.java b/app/src/main/java/com/wireguard/android/util/ObservableSortedKeyedArrayList.java index 4ff3a771..239520c4 100644 --- a/app/src/main/java/com/wireguard/android/util/ObservableSortedKeyedArrayList.java +++ b/app/src/main/java/com/wireguard/android/util/ObservableSortedKeyedArrayList.java @@ -6,7 +6,7 @@ package com.wireguard.android.util; -import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import com.wireguard.util.Keyed; import com.wireguard.util.SortedKeyedList; @@ -29,6 +29,7 @@ import java.util.Spliterator; public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>> extends ObservableKeyedArrayList<K, E> implements ObservableSortedKeyedList<K, E> { + @Nullable private final Comparator<? super K> comparator; private final transient KeyList<K, E> keyList = new KeyList<>(this); @@ -75,7 +76,7 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>> } @Override - public boolean addAll(@NonNull final Collection<? extends E> c) { + public boolean addAll(final Collection<? extends E> c) { boolean didChange = false; for (final E e : c) if (add(e)) @@ -84,12 +85,13 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>> } @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) add(index++, e); return true; } + @Nullable @Override public Comparator<? super K> comparator() { return comparator; @@ -128,7 +130,6 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>> } @Override - @NonNull public Set<K> keySet() { return keyList; } @@ -168,7 +169,6 @@ public class ObservableSortedKeyedArrayList<K, E extends Keyed<? extends K>> } @Override - @NonNull public Collection<E> values() { return this; } diff --git a/app/src/main/java/com/wireguard/android/util/RootShell.java b/app/src/main/java/com/wireguard/android/util/RootShell.java index 9293dff9..18e04102 100644 --- a/app/src/main/java/com/wireguard/android/util/RootShell.java +++ b/app/src/main/java/com/wireguard/android/util/RootShell.java @@ -7,6 +7,7 @@ package com.wireguard.android.util; import android.content.Context; +import android.support.annotation.Nullable; import android.util.Log; import com.wireguard.android.R; @@ -34,10 +35,10 @@ public class RootShell { private final File localTemporaryDir; private final Object lock = new Object(); private final String preamble; - private Process process; - private BufferedReader stderr; - private OutputStreamWriter stdin; - private BufferedReader stdout; + @Nullable private Process process; + @Nullable private BufferedReader stderr; + @Nullable private OutputStreamWriter stdin; + @Nullable private BufferedReader stdout; public RootShell(final Context context) { deviceNotRootedMessage = context.getString(R.string.error_root); @@ -80,7 +81,7 @@ public class RootShell { * @param command Command to run as root. * @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 { synchronized (lock) { /* Start inside synchronized block to prevent a concurrent call to stop(). */ diff --git a/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java b/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java index e0bb579d..997dd45c 100644 --- a/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java +++ b/app/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java @@ -19,8 +19,7 @@ import java.util.zip.ZipFile; public final class SharedLibraryLoader { private static final String TAG = "WireGuard/" + SharedLibraryLoader.class.getSimpleName(); - private SharedLibraryLoader() { - } + private SharedLibraryLoader() { } public static void loadSharedLibrary(final Context context, final String libName) { Throwable noAbiException; diff --git a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java index 9cdb6a59..16c906eb 100644 --- a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java +++ b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java @@ -7,6 +7,7 @@ package com.wireguard.android.util; import android.content.Context; +import android.support.annotation.Nullable; import android.system.OsConstants; import android.util.Log; @@ -39,20 +40,21 @@ public final class ToolsInstaller { new File("/system/xbin"), 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 final File localBinaryDir; private final Object lock = new Object(); private final File nativeLibraryDir; - private Boolean areToolsAvailable; - private Boolean installAsMagiskModule; + @Nullable private Boolean areToolsAvailable; + @Nullable private Boolean installAsMagiskModule; public ToolsInstaller(final Context context) { localBinaryDir = new File(context.getCacheDir(), "bin"); nativeLibraryDir = new File(context.getApplicationInfo().nativeLibraryDir); } + @Nullable private static File getInstallDir() { final String path = System.getenv("PATH"); if (path == null) diff --git a/app/src/main/java/com/wireguard/android/widget/KeyInputFilter.java b/app/src/main/java/com/wireguard/android/widget/KeyInputFilter.java index fff3bc22..a7c11717 100644 --- a/app/src/main/java/com/wireguard/android/widget/KeyInputFilter.java +++ b/app/src/main/java/com/wireguard/android/widget/KeyInputFilter.java @@ -6,6 +6,7 @@ package com.wireguard.android.widget; +import android.support.annotation.Nullable; import android.text.InputFilter; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -25,7 +26,7 @@ public class KeyInputFilter implements InputFilter { return new KeyInputFilter(); } - @Override + @Override @Nullable public CharSequence filter(final CharSequence source, final int sStart, final int sEnd, final Spanned dest, diff --git a/app/src/main/java/com/wireguard/android/widget/NameInputFilter.java b/app/src/main/java/com/wireguard/android/widget/NameInputFilter.java index b31c9176..514b9f88 100644 --- a/app/src/main/java/com/wireguard/android/widget/NameInputFilter.java +++ b/app/src/main/java/com/wireguard/android/widget/NameInputFilter.java @@ -6,6 +6,7 @@ package com.wireguard.android.widget; +import android.support.annotation.Nullable; import android.text.InputFilter; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -25,7 +26,7 @@ public class NameInputFilter implements InputFilter { return new NameInputFilter(); } - @Override + @Override @Nullable public CharSequence filter(final CharSequence source, final int sStart, final int sEnd, final Spanned dest, diff --git a/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java b/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java index 64fe7f73..53530e0a 100644 --- a/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java +++ b/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java @@ -25,11 +25,9 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.support.annotation.ColorInt; import android.support.annotation.IntRange; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.FloatProperty; - @TargetApi(Build.VERSION_CODES.N) 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 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 float mRotation; private boolean mSlashed; - private Mode mTintMode; - private ColorStateList mTintList; private boolean mAnimationEnabled = true; public SlashDrawable(final Drawable d) { - setDrawable(d); + mDrawable = d; } @Override public int getIntrinsicHeight() { - return mDrawable != null ? mDrawable.getIntrinsicHeight(): 0; + return mDrawable.getIntrinsicHeight(); } @Override public int getIntrinsicWidth() { - return mDrawable != null ? mDrawable.getIntrinsicWidth(): 0; + return mDrawable.getIntrinsicWidth(); } @Override @@ -81,17 +77,6 @@ public class SlashDrawable extends Drawable { 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) { if (mRotation == rotation) return; @@ -139,7 +124,7 @@ public class SlashDrawable extends Drawable { @SuppressWarnings("deprecation") @Override - public void draw(@NonNull final Canvas canvas) { + public void draw(final Canvas canvas) { canvas.save(); final Matrix m = new Matrix(); final int width = getBounds().width(); @@ -201,7 +186,6 @@ public class SlashDrawable extends Drawable { @Override public void setTintList(@Nullable final ColorStateList tint) { - mTintList = tint; super.setTintList(tint); setDrawableTintList(tint); mPaint.setColor(tint == null ? 0 : tint.getDefaultColor()); @@ -213,8 +197,7 @@ public class SlashDrawable extends Drawable { } @Override - public void setTintMode(@NonNull final Mode tintMode) { - mTintMode = tintMode; + public void setTintMode(final Mode tintMode) { super.setTintMode(tintMode); mDrawable.setTintMode(tintMode); } diff --git a/app/src/main/java/com/wireguard/android/widget/ToggleSwitch.java b/app/src/main/java/com/wireguard/android/widget/ToggleSwitch.java index b71ad447..b2928293 100644 --- a/app/src/main/java/com/wireguard/android/widget/ToggleSwitch.java +++ b/app/src/main/java/com/wireguard/android/widget/ToggleSwitch.java @@ -7,22 +7,23 @@ package com.wireguard.android.widget; import android.content.Context; import android.os.Parcelable; +import android.support.annotation.Nullable; import android.util.AttributeSet; import android.widget.Switch; public class ToggleSwitch extends Switch { private boolean isRestoringState; - private OnBeforeCheckedChangeListener listener; - - @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) - public ToggleSwitch(final Context context, final AttributeSet attrs) { - super(context, attrs); - } + @Nullable private OnBeforeCheckedChangeListener listener; public ToggleSwitch(final Context context) { this(context, null); } + @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) + public ToggleSwitch(final Context context, @Nullable final AttributeSet attrs) { + super(context, attrs); + } + @Override public void onRestoreInstanceState(final Parcelable state) { isRestoringState = true; diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java index fb87b1e9..7ca6d976 100644 --- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java +++ b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java @@ -20,7 +20,7 @@ import android.graphics.drawable.LayerDrawable; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Keep; -import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.v4.content.res.ResourcesCompat; import android.support.v7.widget.AppCompatTextView; @@ -57,32 +57,32 @@ public class FloatingActionsMenu extends ViewGroup { private boolean mExpanded; private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); - private FloatingActionButton mAddButton; - private RotatingDrawable mRotatingDrawable; + @Nullable private FloatingActionButton mAddButton; + @Nullable private RotatingDrawable mRotatingDrawable; private int mMaxButtonWidth; private int mMaxButtonHeight; private int mLabelsStyle; private int mLabelsPosition; private int mButtonsCount; - private TouchDelegateGroup mTouchDelegateGroup; - private OnFloatingActionsMenuUpdateListener mListener; + @Nullable private TouchDelegateGroup mTouchDelegateGroup; + @Nullable private OnFloatingActionsMenuUpdateListener mListener; private final Rect touchArea = new Rect(0, 0, 0, 0); public FloatingActionsMenu(final Context context) { this(context, null); } - public FloatingActionsMenu(final Context context, final AttributeSet attrs) { + public FloatingActionsMenu(final Context context, @Nullable final AttributeSet attrs) { super(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); 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)); mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin); mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset); @@ -530,7 +530,7 @@ public class FloatingActionsMenu extends ViewGroup { } @Override - public void writeToParcel(@NonNull final Parcel out, final int flags) { + public void writeToParcel(final Parcel out, final int flags) { super.writeToParcel(out, flags); out.writeInt(mExpanded ? 1 : 0); } diff --git a/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java b/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java index a203282e..cc6c97cc 100644 --- a/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java +++ b/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java @@ -8,6 +8,7 @@ package com.wireguard.android.widget.fab; import android.content.Context; import android.content.res.TypedArray; +import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.util.AttributeSet; import android.widget.TextView; @@ -16,17 +17,17 @@ import com.wireguard.android.R; public class LabeledFloatingActionButton extends FloatingActionButton { - private final String title; + @Nullable private final String title; public LabeledFloatingActionButton(final Context context) { this(context, null); } - public LabeledFloatingActionButton(final Context context, final AttributeSet attrs) { + public LabeledFloatingActionButton(final Context context, @Nullable final AttributeSet attrs) { 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); final TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.LabeledFloatingActionButton, 0, 0); @@ -34,10 +35,12 @@ public class LabeledFloatingActionButton extends FloatingActionButton { attr.recycle(); } + @Nullable TextView getLabelView() { return (TextView) getTag(R.id.fab_label); } + @Nullable public String getTitle() { return title; } diff --git a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java b/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java index f6152934..6812f885 100644 --- a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java +++ b/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java @@ -7,7 +7,7 @@ package com.wireguard.android.widget.fab; import android.graphics.Rect; -import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.view.MotionEvent; import android.view.TouchDelegate; import android.view.View; @@ -18,14 +18,14 @@ import java.util.Collection; public class TouchDelegateGroup extends TouchDelegate { private static final Rect USELESS_HACKY_RECT = new Rect(); private final Collection<TouchDelegate> mTouchDelegates = new ArrayList<>(); - private TouchDelegate mCurrentTouchDelegate; + @Nullable private TouchDelegate mCurrentTouchDelegate; private boolean mEnabled; public TouchDelegateGroup(final View uselessHackyView) { super(USELESS_HACKY_RECT, uselessHackyView); } - public void addTouchDelegate(@NonNull final TouchDelegate touchDelegate) { + public void addTouchDelegate(final TouchDelegate touchDelegate) { mTouchDelegates.add(touchDelegate); } @@ -42,7 +42,7 @@ public class TouchDelegateGroup extends TouchDelegate { } @Override - public boolean onTouchEvent(@NonNull final MotionEvent event) { + public boolean onTouchEvent(final MotionEvent event) { if (!mEnabled) return false; diff --git a/app/src/main/java/com/wireguard/config/Attribute.java b/app/src/main/java/com/wireguard/config/Attribute.java index bd9fa05d..e8b731b5 100644 --- a/app/src/main/java/com/wireguard/config/Attribute.java +++ b/app/src/main/java/com/wireguard/config/Attribute.java @@ -6,6 +6,7 @@ package com.wireguard.config; +import android.support.annotation.Nullable; import android.text.TextUtils; import java.util.HashMap; @@ -59,13 +60,13 @@ public enum Attribute { 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)) return EMPTY_LIST; 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); } @@ -77,11 +78,13 @@ public enum Attribute { return String.format("%s = %s%n", token, iterableToString(value)); } + @Nullable public String parse(final CharSequence line) { final Matcher matcher = pattern.matcher(line); return matcher.matches() ? matcher.group(1) : null; } + @Nullable public String[] parseList(final CharSequence line) { final Matcher matcher = pattern.matcher(line); return matcher.matches() ? stringToList(matcher.group(1)) : null; diff --git a/app/src/main/java/com/wireguard/config/Config.java b/app/src/main/java/com/wireguard/config/Config.java index 62ba252c..0599dec3 100644 --- a/app/src/main/java/com/wireguard/config/Config.java +++ b/app/src/main/java/com/wireguard/config/Config.java @@ -12,6 +12,7 @@ import android.databinding.ObservableArrayList; import android.databinding.ObservableList; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.Nullable; import com.android.databinding.library.baseAdapters.BR; @@ -96,13 +97,19 @@ public class Config { return new Observable[size]; } }; - private String name; - private Interface.Observable observableInterface; - private ObservableList<Peer.Observable> observablePeers; + @Nullable private String name; + private final Interface.Observable observableInterface; + 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; - 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) { @@ -144,15 +151,6 @@ public class Config { 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) { this.name = name; notifyPropertyChanged(BR.name); diff --git a/app/src/main/java/com/wireguard/config/InetAddresses.java b/app/src/main/java/com/wireguard/config/InetAddresses.java index b943f03e..3cc84b01 100644 --- a/app/src/main/java/com/wireguard/config/InetAddresses.java +++ b/app/src/main/java/com/wireguard/config/InetAddresses.java @@ -6,7 +6,6 @@ package com.wireguard.config; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; import java.lang.reflect.InvocationTargetException; @@ -29,7 +28,6 @@ public final class InetAddresses { // Prevent instantiation. } - @NonNull public static InetAddress parse(@Nullable final String address) { if (address == null || address.isEmpty()) throw new IllegalArgumentException("Empty address"); diff --git a/app/src/main/java/com/wireguard/config/InetNetwork.java b/app/src/main/java/com/wireguard/config/InetNetwork.java index 6f1be914..8f434753 100644 --- a/app/src/main/java/com/wireguard/config/InetNetwork.java +++ b/app/src/main/java/com/wireguard/config/InetNetwork.java @@ -6,8 +6,6 @@ package com.wireguard.config; -import android.support.annotation.NonNull; - import java.net.Inet4Address; import java.net.InetAddress; import java.util.Objects; @@ -16,7 +14,7 @@ public class InetNetwork { private final InetAddress address; private final int mask; - public InetNetwork(@NonNull final String input) { + public InetNetwork(final String input) { final int slash = input.lastIndexOf('/'); final int rawMask; final String rawAddress; @@ -40,7 +38,6 @@ public class InetNetwork { return Objects.equals(address, other.address) && mask == other.mask; } - @NonNull public InetAddress getAddress() { return address; } diff --git a/app/src/main/java/com/wireguard/config/Interface.java b/app/src/main/java/com/wireguard/config/Interface.java index 3f72e812..99336ae4 100644 --- a/app/src/main/java/com/wireguard/config/Interface.java +++ b/app/src/main/java/com/wireguard/config/Interface.java @@ -10,6 +10,7 @@ import android.databinding.BaseObservable; import android.databinding.Bindable; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.Nullable; import com.wireguard.android.BR; import com.wireguard.crypto.Keypair; @@ -27,7 +28,7 @@ public class Interface { private final List<InetNetwork> addressList; private final List<InetAddress> dnsList; private final List<String> excludedApplications; - private Keypair keypair; + @Nullable private Keypair keypair; private int listenPort; private int mtu; @@ -37,7 +38,7 @@ public class Interface { excludedApplications = new ArrayList<>(); } - private void addAddresses(final String[] addresses) { + private void addAddresses(@Nullable final String[] addresses) { if (addresses != null && addresses.length > 0) { for (final String addr : addresses) { 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) { for (final String dns : dnses) { 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) { excludedApplications.addAll(Arrays.asList(applications)); } } + @Nullable private String getAddressString() { if (addressList.isEmpty()) return null; @@ -71,6 +73,7 @@ public class Interface { return addressList.toArray(new InetNetwork[addressList.size()]); } + @Nullable private String getDnsString() { if (dnsList.isEmpty()) return null; @@ -88,6 +91,7 @@ public class Interface { return dnsList.toArray(new InetAddress[dnsList.size()]); } + @Nullable private String getExcludedApplicationsString() { if (excludedApplications.isEmpty()) return null; @@ -102,6 +106,7 @@ public class Interface { return listenPort; } + @Nullable private String getListenPortString() { if (listenPort == 0) return null; @@ -112,18 +117,21 @@ public class Interface { return mtu; } + @Nullable private String getMtuString() { if (mtu == 0) return null; return Integer.toString(mtu); } + @Nullable public String getPrivateKey() { if (keypair == null) return null; return keypair.getPrivateKey(); } + @Nullable public String getPublicKey() { if (keypair == 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(); addAddresses(Attribute.stringToList(addressString)); } - private void setDnsString(final String dnsString) { + private void setDnsString(@Nullable final String dnsString) { dnsList.clear(); addDnses(Attribute.stringToList(dnsString)); } - private void setExcludedApplicationsString(final String applicationsString) { + private void setExcludedApplicationsString(@Nullable final String applicationsString) { excludedApplications.clear(); addExcludedApplications(Attribute.stringToList(applicationsString)); } @@ -175,7 +183,7 @@ public class Interface { this.listenPort = listenPort; } - private void setListenPortString(final String port) { + private void setListenPortString(@Nullable final String port) { if (port != null && !port.isEmpty()) setListenPort(Integer.parseInt(port, 10)); else @@ -186,14 +194,14 @@ public class Interface { this.mtu = mtu; } - private void setMtuString(final String mtu) { + private void setMtuString(@Nullable final String mtu) { if (mtu != null && !mtu.isEmpty()) setMtu(Integer.parseInt(mtu, 10)); else setMtu(0); } - private void setPrivateKey(String privateKey) { + private void setPrivateKey(@Nullable String privateKey) { if (privateKey != null && privateKey.isEmpty()) privateKey = null; keypair = privateKey == null ? null : new Keypair(privateKey); @@ -229,15 +237,15 @@ public class Interface { return new Observable[size]; } }; - private String addresses; - private String dnses; - private String excludedApplications; - private String listenPort; - private String mtu; - private String privateKey; - private String publicKey; - - public Observable(final Interface parent) { + @Nullable private String addresses; + @Nullable private String dnses; + @Nullable private String excludedApplications; + @Nullable private String listenPort; + @Nullable private String mtu; + @Nullable private String privateKey; + @Nullable private String publicKey; + + public Observable(@Nullable final Interface parent) { if (parent != null) loadData(parent); } @@ -276,16 +284,19 @@ public class Interface { notifyPropertyChanged(BR.publicKey); } + @Nullable @Bindable public String getAddresses() { return addresses; } + @Nullable @Bindable public String getDnses() { return dnses; } + @Nullable @Bindable public String getExcludedApplications() { return excludedApplications; @@ -296,21 +307,25 @@ public class Interface { return Attribute.stringToList(excludedApplications).length; } + @Nullable @Bindable public String getListenPort() { return listenPort; } + @Nullable @Bindable public String getMtu() { return mtu; } + @Nullable @Bindable public String getPrivateKey() { return privateKey; } + @Nullable @Bindable public String getPublicKey() { return publicKey; diff --git a/app/src/main/java/com/wireguard/config/Peer.java b/app/src/main/java/com/wireguard/config/Peer.java index 371072de..60fe5c82 100644 --- a/app/src/main/java/com/wireguard/config/Peer.java +++ b/app/src/main/java/com/wireguard/config/Peer.java @@ -10,6 +10,7 @@ import android.databinding.BaseObservable; import android.databinding.Bindable; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.Nullable; import com.android.databinding.library.baseAdapters.BR; import com.wireguard.crypto.KeyEncoding; @@ -34,16 +35,16 @@ import java9.lang.Iterables; public class Peer { private final List<InetNetwork> allowedIPsList; - private InetSocketAddress endpoint; + @Nullable private InetSocketAddress endpoint; private int persistentKeepalive; - private String preSharedKey; - private String publicKey; + @Nullable private String preSharedKey; + @Nullable private String publicKey; public Peer() { allowedIPsList = new ArrayList<>(); } - private void addAllowedIPs(final String[] allowedIPs) { + private void addAllowedIPs(@Nullable final String[] allowedIPs) { if (allowedIPs != null && allowedIPs.length > 0) { for (final String allowedIP : allowedIPs) { allowedIPsList.add(new InetNetwork(allowedIP)); @@ -55,16 +56,19 @@ public class Peer { return allowedIPsList.toArray(new InetNetwork[allowedIPsList.size()]); } + @Nullable private String getAllowedIPsString() { if (allowedIPsList.isEmpty()) return null; return Attribute.iterableToString(allowedIPsList); } + @Nullable public InetSocketAddress getEndpoint() { return endpoint; } + @Nullable private String getEndpointString() { if (endpoint == null) return null; @@ -75,16 +79,19 @@ public class Peer { return persistentKeepalive; } + @Nullable private String getPersistentKeepaliveString() { if (persistentKeepalive == 0) return null; return Integer.valueOf(persistentKeepalive).toString(); } + @Nullable public String getPreSharedKey() { return preSharedKey; } + @Nullable public String getPublicKey() { return publicKey; } @@ -130,16 +137,16 @@ public class Peer { } } - private void setAllowedIPsString(final String allowedIPsString) { + private void setAllowedIPsString(@Nullable final String allowedIPsString) { allowedIPsList.clear(); addAllowedIPs(Attribute.stringToList(allowedIPsString)); } - private void setEndpoint(final InetSocketAddress endpoint) { + private void setEndpoint(@Nullable final InetSocketAddress endpoint) { this.endpoint = endpoint; } - private void setEndpointString(final String endpoint) { + private void setEndpointString(@Nullable final String endpoint) { if (endpoint != null && !endpoint.isEmpty()) { final InetSocketAddress constructedEndpoint; if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1) @@ -160,14 +167,14 @@ public class Peer { this.persistentKeepalive = persistentKeepalive; } - private void setPersistentKeepaliveString(final String persistentKeepalive) { + private void setPersistentKeepaliveString(@Nullable final String persistentKeepalive) { if (persistentKeepalive != null && !persistentKeepalive.isEmpty()) setPersistentKeepalive(Integer.parseInt(persistentKeepalive, 10)); else setPersistentKeepalive(0); } - private void setPreSharedKey(String preSharedKey) { + private void setPreSharedKey(@Nullable String preSharedKey) { if (preSharedKey != null && preSharedKey.isEmpty()) preSharedKey = null; if (preSharedKey != null) @@ -175,7 +182,7 @@ public class Peer { this.preSharedKey = preSharedKey; } - private void setPublicKey(String publicKey) { + private void setPublicKey(@Nullable String publicKey) { if (publicKey != null && publicKey.isEmpty()) publicKey = null; if (publicKey != null) @@ -211,12 +218,12 @@ public class Peer { return new Observable[size]; } }; - private String allowedIPs; - private String endpoint; - private String persistentKeepalive; - private String preSharedKey; - private String publicKey; - private List<String> interfaceDNSRoutes; + @Nullable private String allowedIPs; + @Nullable private String endpoint; + @Nullable private String persistentKeepalive; + @Nullable private String preSharedKey; + @Nullable private String publicKey; + private final List<String> interfaceDNSRoutes = new ArrayList<>(); private int numSiblings; public Observable(final Peer parent) { @@ -230,7 +237,6 @@ public class Peer { preSharedKey = in.readString(); publicKey = in.readString(); numSiblings = in.readInt(); - interfaceDNSRoutes = new ArrayList<>(); in.readStringList(interfaceDNSRoutes); } @@ -284,27 +290,27 @@ public class Peer { return numSiblings == 0 && Arrays.asList(Attribute.stringToList(allowedIPs)).containsAll(DEFAULT_ROUTE_MOD_RFC1918_V4); } - @Bindable + @Bindable @Nullable public String getAllowedIPs() { return allowedIPs; } - @Bindable + @Bindable @Nullable public String getEndpoint() { return endpoint; } - @Bindable + @Bindable @Nullable public String getPersistentKeepalive() { return persistentKeepalive; } - @Bindable + @Bindable @Nullable public String getPreSharedKey() { return preSharedKey; } - @Bindable + @Bindable @Nullable public String getPublicKey() { return publicKey; } @@ -315,7 +321,6 @@ public class Peer { persistentKeepalive = parent.getPersistentKeepaliveString(); preSharedKey = parent.getPreSharedKey(); publicKey = parent.getPublicKey(); - interfaceDNSRoutes = new ArrayList<>(); } public void setAllowedIPs(final String allowedIPs) { diff --git a/app/src/main/java/com/wireguard/crypto/Curve25519.java b/app/src/main/java/com/wireguard/crypto/Curve25519.java index a47db7de..d279f2ae 100644 --- a/app/src/main/java/com/wireguard/crypto/Curve25519.java +++ b/app/src/main/java/com/wireguard/crypto/Curve25519.java @@ -5,6 +5,8 @@ package com.wireguard.crypto; +import android.support.annotation.Nullable; + import java.util.Arrays; /** @@ -93,7 +95,7 @@ public final class Curve25519 { * if the base point of the curve should be used. */ 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(); try { // Unpack the public key value. If null, use 9 as the base point. diff --git a/app/src/main/java/com/wireguard/util/NonNullForAll.java b/app/src/main/java/com/wireguard/util/NonNullForAll.java new file mode 100644 index 00000000..f74cb616 --- /dev/null +++ b/app/src/main/java/com/wireguard/util/NonNullForAll.java @@ -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 { } |