global: Add nullity annotations

Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
This commit is contained in:
Eric Kuck 2018-07-12 19:10:35 -05:00 committed by Jason A. Donenfeld
parent fbaa4d9ab1
commit 67ea8b2936
48 changed files with 480 additions and 309 deletions

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ build/
*.iml
*.jks
keystore.properties
package-info.java

View File

@ -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>

View File

@ -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) {

87
app/nonnull.gradle Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright © 2018 Eric Kuck <eric@bluelinelabs.com>.
* SPDX-License-Identifier: Apache-2.0
*/
task generateNonNullJavaFiles(dependsOn: "assembleDebug", type: Copy) {
group = "Copying"
description = "Generate package-info.java classes"
def basePackage = "com" + File.separatorChar + "wireguard"
def mainSrcPhrase = "src" + File.separatorChar + "main" + File.separatorChar +
"java" + File.separatorChar
def mainTestSrcPhrase = "src" + File.separatorChar + "test" + File.separatorChar +
"java" + File.separatorChar
def mainAndroidTestSrcPhrase = "src" + File.separatorChar + "androidTest" + File.separatorChar +
"java" + File.separatorChar
def sourceDir = file( "${projectDir}" + File.separatorChar + "src" + File.separatorChar +
"main" + File.separatorChar + "java" + File.separatorChar +
basePackage )
def testSourceDir = file( "${projectDir}" + File.separatorChar + "src" + File.separatorChar +
"test" + File.separatorChar + "java" + File.separatorChar +
basePackage)
def androidTestSourceDir = file( "${projectDir}" + File.separatorChar + "src" + File
.separatorChar +
"androidTest" + File.separatorChar + "java" + File.separatorChar +
basePackage )
generateInfoFiles(sourceDir, mainSrcPhrase);
sourceDir.eachDirRecurse { dir ->
generateInfoFiles(dir, mainSrcPhrase)
}
if (file(testSourceDir).exists()) {
generateInfoFiles(testSourceDir, mainTestSrcPhrase);
testSourceDir.eachDirRecurse { dir ->
generateInfoFiles(dir, mainTestSrcPhrase)
}
}
if (file(androidTestSourceDir).exists()) {
generateInfoFiles(androidTestSourceDir, mainAndroidTestSrcPhrase);
androidTestSourceDir.eachDirRecurse { dir ->
generateInfoFiles(dir, mainAndroidTestSrcPhrase)
}
}
println "[SUCCESS] NonNull generator: package-info.java files checked"
}
private void generateInfoFiles(File dir, String mainSrcPhrase) {
def infoFileContentHeader = getFileContentHeader();
def infoFileContentFooter = getFileContentFooter();
def infoFilePath = dir.getAbsolutePath() + File.separatorChar + "package-info.java"
//file(infoFilePath).delete(); //do not use in production code
if (!file(infoFilePath).exists()) {
def infoFileContentPackage = getFileContentPackage(dir.getAbsolutePath(), mainSrcPhrase);
new File(infoFilePath).write(infoFileContentHeader +
infoFileContentPackage + infoFileContentFooter)
println "[dir] " + infoFilePath + " created";
}
}
def getFileContentPackage(String path, String mainSrcPhrase) {
def mainSrcPhraseIndex = path.indexOf(mainSrcPhrase)
def output = path.substring(mainSrcPhraseIndex)
// Win hotfix
if (System.properties['os.name'].toLowerCase().contains('windows')) {
output = output.replace("\\", "/")
mainSrcPhrase = mainSrcPhrase.replace("\\", "/")
}
return "package " + output.replaceAll(mainSrcPhrase, "").replaceAll(
"/", ".") + ";\n"
}
def getFileContentHeader() {
return "/**\n" +
" * Make all method parameters @NonNull by default.\n" +
" */\n" +
"@NonNullForAll\n"
}
def getFileContentFooter() {
return "\n" +
"import com.wireguard.util.NonNullForAll;\n"
}

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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");

View File

@ -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));

View File

@ -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;

View File

@ -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;

View File

@ -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) {
@ -51,24 +51,12 @@ public class AppListDialogFragment extends DialogFragment {
return fragment;
}
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
currentlyExcludedApps = Arrays.asList(getArguments().getStringArray(KEY_EXCLUDED_APPS));
}
@Override
public void onAttach(final Context context) {
super.onAttach(context);
}
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setTitle(R.string.excluded_applications);
AppListDialogFragmentBinding binding = AppListDialogFragmentBinding.inflate(getActivity().getLayoutInflater(), null, false);
final AppListDialogFragmentBinding binding = AppListDialogFragmentBinding.inflate(getActivity().getLayoutInflater(), null, false);
binding.executePendingBindings();
alertDialogBuilder.setView(binding.getRoot());

View File

@ -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;

View File

@ -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);

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 { }
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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(). */

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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;
}

View File

@ -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;
@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(final Interface parent) {
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;

View File

@ -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) {

View File

@ -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.

View File

@ -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 { }