diff --git a/app/build.gradle b/app/build.gradle index 00f4cb10..bd9cba44 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -52,19 +52,16 @@ android { ext { databindingVersion = '3.1.2' supportLibsVersion = '27.1.1' - daggerVersion = '2.14.1' streamsupportVersion = '1.6.0' } dependencies { - annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" implementation "com.android.databinding:library:$databindingVersion" implementation "com.android.support:appcompat-v7:$supportLibsVersion" implementation "com.android.support:cardview-v7:$supportLibsVersion" implementation "com.android.support:design:$supportLibsVersion" implementation "com.android.support:preference-v14:$supportLibsVersion" implementation "com.android.support:support-annotations:$supportLibsVersion" - implementation "com.google.dagger:dagger:$daggerVersion" implementation "net.sourceforge.streamsupport:android-retrofuture:$streamsupportVersion" implementation "net.sourceforge.streamsupport:android-retrostreams:$streamsupportVersion" } diff --git a/app/src/main/java/com/wireguard/android/Application.java b/app/src/main/java/com/wireguard/android/Application.java index eaf2d75c..d0dc22d9 100644 --- a/app/src/main/java/com/wireguard/android/Application.java +++ b/app/src/main/java/com/wireguard/android/Application.java @@ -1,12 +1,10 @@ /* - * Copyright © 2018 Samuel Holland * Copyright © 2018 Jason A. Donenfeld . All Rights Reserved. * SPDX-License-Identifier: GPL-2.0-or-later */ package com.wireguard.android; -import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Handler; @@ -25,123 +23,72 @@ import com.wireguard.android.util.RootShell; import com.wireguard.android.util.ToolsInstaller; import java.io.File; +import java.lang.ref.WeakReference; import java.util.concurrent.Executor; -import javax.inject.Qualifier; -import javax.inject.Scope; - -import dagger.Component; -import dagger.Module; -import dagger.Provides; - -/** - * Base context for the WireGuard Android application. This class (instantiated once during the - * application lifecycle) maintains and mediates access to the global state of the application. - */ - public class Application extends android.app.Application { - private static ApplicationComponent component; + private static WeakReference weakSelf; + private AsyncWorker asyncWorker; + private Backend backend; + private RootShell rootShell; + private SharedPreferences sharedPreferences; + private ToolsInstaller toolsInstaller; + private TunnelManager tunnelManager; + public Application() { + weakSelf = new WeakReference<>(this); + } - public static ApplicationComponent getComponent() { - if (component == null) - throw new IllegalStateException("Application instance not yet created"); - return component; + public static Application get() { + return weakSelf.get(); + } + + public static AsyncWorker getAsyncWorker() { + return get().asyncWorker; + } + + public static Class getBackendType() { + return get().backend.getClass(); + } + + public static RootShell getRootShell() { + return get().rootShell; + } + + public static SharedPreferences getSharedPreferences() { + return get().sharedPreferences; + } + + public static ToolsInstaller getToolsInstaller() { + return get().toolsInstaller; + } + + public static TunnelManager getTunnelManager() { + return get().tunnelManager; } @Override public void onCreate() { super.onCreate(); - component = DaggerApplication_ApplicationComponent.builder() - .applicationModule(new ApplicationModule(this)) - .build(); - component.getTunnelManager().onCreate(); - } - @ApplicationScope - @Component(modules = ApplicationModule.class) - public interface ApplicationComponent { - AsyncWorker getAsyncWorker(); + final Executor executor = AsyncTask.SERIAL_EXECUTOR; + final Handler handler = new Handler(Looper.getMainLooper()); + final ConfigStore configStore = new FileConfigStore(getApplicationContext()); - Class getBackendType(); + asyncWorker = new AsyncWorker(executor, handler); + rootShell = new RootShell(getApplicationContext()); + toolsInstaller = new ToolsInstaller(getApplicationContext()); - ToolsInstaller getToolsInstaller(); + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + AppCompatDelegate.setDefaultNightMode( + sharedPreferences.getBoolean("dark_theme", false) ? + AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO); - TunnelManager getTunnelManager(); + if (new File("/sys/module/wireguard").exists()) + backend = new WgQuickBackend(getApplicationContext()); + else + backend = new GoBackend(getApplicationContext()); - RootShell getRootShell(); - } - - @Qualifier - public @interface ApplicationContext { - } - - @Qualifier - public @interface ApplicationHandler { - } - - @Scope - public @interface ApplicationScope { - } - - @Module - public static final class ApplicationModule { - private final Context context; - - private ApplicationModule(final Application application) { - context = application.getApplicationContext(); - - AppCompatDelegate.setDefaultNightMode( - getPreferences(context).getBoolean("dark_theme", false) ? - AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO); - } - - @ApplicationScope - @Provides - public static Backend getBackend(@ApplicationContext final Context context, - final RootShell rootShell, - final ToolsInstaller toolsInstaller) { - if (new File("/sys/module/wireguard").exists()) - return new WgQuickBackend(context, rootShell, toolsInstaller); - else - return new GoBackend(context); - } - - @ApplicationScope - @Provides - public static Class getBackendType(final Backend backend) { - return backend.getClass(); - } - - @ApplicationScope - @Provides - public static ConfigStore getConfigStore(@ApplicationContext final Context context) { - return new FileConfigStore(context); - } - - @ApplicationScope - @Provides - public static Executor getExecutor() { - return AsyncTask.SERIAL_EXECUTOR; - } - - @ApplicationHandler - @ApplicationScope - @Provides - public static Handler getHandler() { - return new Handler(Looper.getMainLooper()); - } - - @ApplicationScope - @Provides - public static SharedPreferences getPreferences(@ApplicationContext final Context context) { - return PreferenceManager.getDefaultSharedPreferences(context); - } - - @ApplicationContext - @ApplicationScope - @Provides - public Context getContext() { - return context; - } + tunnelManager = new TunnelManager(backend, configStore); + tunnelManager.onCreate(); } } diff --git a/app/src/main/java/com/wireguard/android/BootShutdownReceiver.java b/app/src/main/java/com/wireguard/android/BootShutdownReceiver.java index 675bbb42..3c2bb85c 100644 --- a/app/src/main/java/com/wireguard/android/BootShutdownReceiver.java +++ b/app/src/main/java/com/wireguard/android/BootShutdownReceiver.java @@ -20,13 +20,13 @@ public class BootShutdownReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { - if (Application.getComponent().getBackendType() != WgQuickBackend.class) { + if (Application.getBackendType() != WgQuickBackend.class) { return; } final String action = intent.getAction(); if (action == null) return; - final TunnelManager tunnelManager = Application.getComponent().getTunnelManager(); + final TunnelManager tunnelManager = Application.getTunnelManager(); if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { Log.i(TAG, "Broadcast receiver restoring state (boot)"); tunnelManager.restoreState(false).whenComplete(ExceptionLoggers.D); diff --git a/app/src/main/java/com/wireguard/android/QuickTileService.java b/app/src/main/java/com/wireguard/android/QuickTileService.java index 8480b65e..99f72de2 100644 --- a/app/src/main/java/com/wireguard/android/QuickTileService.java +++ b/app/src/main/java/com/wireguard/android/QuickTileService.java @@ -38,7 +38,6 @@ public class QuickTileService extends TileService { private final OnStateChangedCallback onStateChangedCallback = new OnStateChangedCallback(); private final OnTunnelChangedCallback onTunnelChangedCallback = new OnTunnelChangedCallback(); private Tunnel tunnel; - private TunnelManager tunnelManager; @Override public void onClick() { @@ -54,12 +53,11 @@ public class QuickTileService extends TileService { @Override public void onCreate() { super.onCreate(); - tunnelManager = Application.getComponent().getTunnelManager(); } @Override public void onStartListening() { - tunnelManager.addOnPropertyChangedCallback(onTunnelChangedCallback); + Application.getTunnelManager().addOnPropertyChangedCallback(onTunnelChangedCallback); if (tunnel != null) tunnel.addOnPropertyChangedCallback(onStateChangedCallback); updateTile(); @@ -69,7 +67,7 @@ public class QuickTileService extends TileService { public void onStopListening() { if (tunnel != null) tunnel.removeOnPropertyChangedCallback(onStateChangedCallback); - tunnelManager.removeOnPropertyChangedCallback(onTunnelChangedCallback); + Application.getTunnelManager().removeOnPropertyChangedCallback(onTunnelChangedCallback); } private void onToggleFinished(@SuppressWarnings("unused") final State state, @@ -84,7 +82,7 @@ public class QuickTileService extends TileService { private void updateTile() { // Update the tunnel. - final Tunnel newTunnel = tunnelManager.getLastUsedTunnel(); + final Tunnel newTunnel = Application.getTunnelManager().getLastUsedTunnel(); if (newTunnel != tunnel) { if (tunnel != null) tunnel.removeOnPropertyChangedCallback(onStateChangedCallback); 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 a44035f9..e7071da4 100644 --- a/app/src/main/java/com/wireguard/android/activity/BaseActivity.java +++ b/app/src/main/java/com/wireguard/android/activity/BaseActivity.java @@ -47,14 +47,14 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity { else if (getIntent() != null) savedTunnelName = getIntent().getStringExtra(KEY_SELECTED_TUNNEL); if (savedTunnelName != null) { - final TunnelManager tunnelManager = Application.getComponent().getTunnelManager(); + final TunnelManager tunnelManager = Application.getTunnelManager(); selectedTunnel = tunnelManager.getTunnels().get(savedTunnelName); } // The selected tunnel must be set before the superclass method recreates fragments. super.onCreate(savedInstanceState); - if (Application.getComponent().getBackendType() == GoBackend.class) { + if (Application.getBackendType() == GoBackend.class) { final Intent intent = GoBackend.VpnService.prepare(this); if (intent != null) { startActivityForResult(intent, 0); 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 cfc9f3ef..03ae11a0 100644 --- a/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java +++ b/app/src/main/java/com/wireguard/android/activity/SettingsActivity.java @@ -95,7 +95,7 @@ public class SettingsActivity extends ThemeChangeAwareActivity { @Override public void onCreatePreferences(final Bundle savedInstanceState, final String key) { addPreferencesFromResource(R.xml.preferences); - if (Application.getComponent().getBackendType() != WgQuickBackend.class) { + if (Application.getBackendType() != WgQuickBackend.class) { Preference pref = getPreferenceManager().findPreference("tools_installer"); getPreferenceScreen().removePreference(pref); pref = getPreferenceManager().findPreference("restore_on_boot"); 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 250cf0a7..589ac7d0 100644 --- a/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java +++ b/app/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.java @@ -8,11 +8,12 @@ package com.wireguard.android.activity; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; -import android.preference.PreferenceManager; import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatDelegate; import android.util.Log; +import com.wireguard.android.Application; + import java.lang.reflect.Field; public abstract class ThemeChangeAwareActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -52,12 +53,12 @@ public abstract class ThemeChangeAwareActivity extends AppCompatActivity impleme @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this); + Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @Override protected void onDestroy() { - PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this); + Application.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); super.onDestroy(); } 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 21df018e..8c8d593a 100644 --- a/app/src/main/java/com/wireguard/android/backend/GoBackend.java +++ b/app/src/main/java/com/wireguard/android/backend/GoBackend.java @@ -229,7 +229,7 @@ public final class GoBackend implements Backend { @Override public void onDestroy() { - for (final Tunnel tunnel : Application.getComponent().getTunnelManager().getTunnels()) { + for (final Tunnel tunnel : Application.getTunnelManager().getTunnels()) { if (tunnel != null && tunnel.getState() != State.DOWN) tunnel.setState(State.DOWN); } @@ -242,7 +242,7 @@ public final class GoBackend implements Backend { vpnService.complete(this); if (intent == null || intent.getComponent() == null || !intent.getComponent().getPackageName().equals(getPackageName())) { Log.d(TAG, "Service started by Always-on VPN feature"); - Application.getComponent().getTunnelManager().restoreState(true).whenComplete(ExceptionLoggers.D); + Application.getTunnelManager().restoreState(true).whenComplete(ExceptionLoggers.D); } return super.onStartCommand(intent, flags, startId); } 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 e5a5574f..56d62a1f 100644 --- a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java +++ b/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java @@ -9,6 +9,7 @@ package com.wireguard.android.backend; import android.content.Context; import android.util.Log; +import com.wireguard.android.Application; import com.wireguard.android.model.Tunnel; import com.wireguard.android.model.Tunnel.State; import com.wireguard.android.model.Tunnel.Statistics; @@ -35,14 +36,9 @@ public final class WgQuickBackend implements Backend { private static final String TAG = "WireGuard/" + WgQuickBackend.class.getSimpleName(); private final File localTemporaryDir; - private final RootShell rootShell; - private final ToolsInstaller toolsInstaller; - public WgQuickBackend(final Context context, final RootShell rootShell, - final ToolsInstaller toolsInstaller) { + public WgQuickBackend(final Context context) { localTemporaryDir = new File(context.getCacheDir(), "tmp"); - this.rootShell = rootShell; - this.toolsInstaller = toolsInstaller; } @Override @@ -66,8 +62,8 @@ public final class WgQuickBackend implements Backend { final List output = new ArrayList<>(); // Don't throw an exception here or nothing will show up in the UI. try { - toolsInstaller.ensureToolsAvailable(); - if (rootShell.run(output, "wg show interfaces") != 0 || output.isEmpty()) + Application.getToolsInstaller().ensureToolsAvailable(); + if (Application.getRootShell().run(output, "wg show interfaces") != 0 || output.isEmpty()) return Collections.emptySet(); } catch (final Exception e) { Log.w(TAG, "Unable to enumerate running tunnels", e); @@ -95,7 +91,7 @@ public final class WgQuickBackend implements Backend { if (state == originalState) return originalState; Log.d(TAG, "Changing tunnel " + tunnel.getName() + " to state " + state); - toolsInstaller.ensureToolsAvailable(); + Application.getToolsInstaller().ensureToolsAvailable(); setStateInternal(tunnel, tunnel.getConfig(), state); return getState(tunnel); } @@ -110,7 +106,7 @@ public final class WgQuickBackend implements Backend { state.toString().toLowerCase(), tempFile.getAbsolutePath()); if (state == State.UP) command = "cat /sys/module/wireguard/version && " + command; - final int result = rootShell.run(null, command); + final int result = Application.getRootShell().run(null, command); // noinspection ResultOfMethodCallIgnored tempFile.delete(); if (result != 0) diff --git a/app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java b/app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java index 1655470b..231b6b1b 100644 --- a/app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java +++ b/app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java @@ -9,7 +9,6 @@ package com.wireguard.android.configStore; import android.content.Context; import android.util.Log; -import com.wireguard.android.Application.ApplicationContext; import com.wireguard.config.Config; import java.io.File; @@ -32,7 +31,7 @@ public final class FileConfigStore implements ConfigStore { private final Context context; - public FileConfigStore(@ApplicationContext final Context context) { + public FileConfigStore(final Context context) { this.context = context; } 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 5eeb720e..ea03077c 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.java @@ -128,7 +128,7 @@ public class TunnelEditorFragment extends BaseFragment { } if (tunnel == null) { Log.d(TAG, "Attempting to create new tunnel " + binding.getConfig().getName()); - final TunnelManager manager = Application.getComponent().getTunnelManager(); + final TunnelManager manager = Application.getTunnelManager(); manager.create(binding.getConfig().getName(), newConfig) .whenComplete(this::onTunnelCreated); } else if (!tunnel.getName().equals(binding.getConfig().getName())) { 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 f6e99759..1b1b01fe 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java @@ -34,7 +34,6 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import com.wireguard.android.Application; -import com.wireguard.android.Application.ApplicationComponent; import com.wireguard.android.R; import com.wireguard.android.activity.TunnelCreatorActivity; import com.wireguard.android.databinding.TunnelListFragmentBinding; @@ -70,9 +69,7 @@ public class TunnelListFragment extends BaseFragment { private final MultiChoiceModeListener actionModeListener = new ActionModeListener(); private final ListViewCallbacks listViewCallbacks = new ListViewCallbacks(); private ActionMode actionMode; - private AsyncWorker asyncWorker; private TunnelListFragmentBinding binding; - private TunnelManager tunnelManager; public boolean collapseActionMenu() { if (binding.createMenu.isExpanded()) { @@ -90,7 +87,7 @@ public class TunnelListFragment extends BaseFragment { final Collection> futureTunnels = new ArrayList<>(); final List throwables = new ArrayList<>(); - asyncWorker.supplyAsync(() -> { + Application.getAsyncWorker().supplyAsync(() -> { final String[] columns = {OpenableColumns.DISPLAY_NAME}; String name = null; try (Cursor cursor = contentResolver.query(uri, columns, @@ -137,11 +134,11 @@ public class TunnelListFragment extends BaseFragment { throwables.add(e); } if (config != null) - futureTunnels.add(tunnelManager.create(name, config).toCompletableFuture()); + futureTunnels.add(Application.getTunnelManager().create(name, config).toCompletableFuture()); } } } else { - futureTunnels.add(tunnelManager.create(name, + futureTunnels.add(Application.getTunnelManager().create(name, Config.from(contentResolver.openInputStream(uri))).toCompletableFuture()); } @@ -190,9 +187,6 @@ public class TunnelListFragment extends BaseFragment { @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final ApplicationComponent applicationComponent = Application.getComponent(); - asyncWorker = applicationComponent.getAsyncWorker(); - tunnelManager = applicationComponent.getTunnelManager(); } @Override @@ -284,7 +278,7 @@ public class TunnelListFragment extends BaseFragment { public void onViewStateRestored(final Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); binding.setFragment(this); - binding.setTunnels(tunnelManager.getTunnels()); + binding.setTunnels(Application.getTunnelManager().getTunnels()); } private final class ActionModeListener implements MultiChoiceModeListener { 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 91d98842..6747d449 100644 --- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java +++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java @@ -9,19 +9,16 @@ package com.wireguard.android.model; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.databinding.BaseObservable; import android.databinding.Bindable; import android.support.annotation.NonNull; import com.wireguard.android.Application; -import com.wireguard.android.Application.ApplicationScope; import com.wireguard.android.BR; import com.wireguard.android.backend.Backend; import com.wireguard.android.configStore.ConfigStore; import com.wireguard.android.model.Tunnel.State; import com.wireguard.android.model.Tunnel.Statistics; -import com.wireguard.android.util.AsyncWorker; import com.wireguard.android.util.ExceptionLoggers; import com.wireguard.android.util.ObservableKeyedList; import com.wireguard.android.util.ObservableSortedKeyedArrayList; @@ -33,8 +30,6 @@ import java.util.Collection; import java.util.Comparator; import java.util.Set; -import javax.inject.Inject; - import java9.util.Comparators; import java9.util.concurrent.CompletableFuture; import java9.util.concurrent.CompletionStage; @@ -45,7 +40,6 @@ import java9.util.stream.StreamSupport; * Maintains and mediates changes to the set of available WireGuard tunnels, */ -@ApplicationScope public final class TunnelManager extends BaseObservable { private static final Comparator COMPARATOR = Comparators.thenComparing( String.CASE_INSENSITIVE_ORDER, Comparators.naturalOrder()); @@ -53,23 +47,17 @@ public final class TunnelManager extends BaseObservable { private static final String KEY_RESTORE_ON_BOOT = "restore_on_boot"; private static final String KEY_RUNNING_TUNNELS = "enabled_configs"; - private final AsyncWorker asyncWorker; private final Backend backend; private final ConfigStore configStore; - private final SharedPreferences preferences; private final ObservableSortedKeyedList tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR); private Tunnel lastUsedTunnel; private boolean haveLoaded; private final ArrayList> delayedLoadRestoreTunnels = new ArrayList<>(); - @Inject - public TunnelManager(final AsyncWorker asyncWorker, final Backend backend, - final ConfigStore configStore, final SharedPreferences preferences) { - this.asyncWorker = asyncWorker; + public TunnelManager(final Backend backend, final ConfigStore configStore) { this.backend = backend; this.configStore = configStore; - this.preferences = preferences; } private Tunnel addToList(final String name, final Config config, final State state) { @@ -85,7 +73,7 @@ public final class TunnelManager extends BaseObservable { final String message = "Tunnel " + name + " already exists"; return CompletableFuture.failedFuture(new IllegalArgumentException(message)); } - return asyncWorker.supplyAsync(() -> configStore.create(name, config)) + return Application.getAsyncWorker().supplyAsync(() -> configStore.create(name, config)) .thenApply(savedConfig -> addToList(name, savedConfig, State.DOWN)); } @@ -96,7 +84,7 @@ public final class TunnelManager extends BaseObservable { if (wasLastUsed) setLastUsedTunnel(null); tunnels.remove(tunnel); - return asyncWorker.runAsync(() -> { + return Application.getAsyncWorker().runAsync(() -> { if (originalState == State.UP) backend.setState(tunnel, State.DOWN); try { @@ -123,17 +111,17 @@ public final class TunnelManager extends BaseObservable { } CompletionStage getTunnelConfig(final Tunnel tunnel) { - return asyncWorker.supplyAsync(() -> configStore.load(tunnel.getName())) + return Application.getAsyncWorker().supplyAsync(() -> configStore.load(tunnel.getName())) .thenApply(tunnel::onConfigChanged); } CompletionStage getTunnelState(final Tunnel tunnel) { - return asyncWorker.supplyAsync(() -> backend.getState(tunnel)) + return Application.getAsyncWorker().supplyAsync(() -> backend.getState(tunnel)) .thenApply(tunnel::onStateChanged); } CompletionStage getTunnelStatistics(final Tunnel tunnel) { - return asyncWorker.supplyAsync(() -> backend.getStatistics(tunnel)) + return Application.getAsyncWorker().supplyAsync(() -> backend.getStatistics(tunnel)) .thenApply(tunnel::onStatisticsChanged); } @@ -142,8 +130,8 @@ public final class TunnelManager extends BaseObservable { } public void onCreate() { - asyncWorker.supplyAsync(configStore::enumerate) - .thenAcceptBoth(asyncWorker.supplyAsync(backend::enumerate), this::onTunnelsLoaded) + Application.getAsyncWorker().supplyAsync(configStore::enumerate) + .thenAcceptBoth(Application.getAsyncWorker().supplyAsync(backend::enumerate), this::onTunnelsLoaded) .whenComplete(ExceptionLoggers.E); } @@ -151,7 +139,7 @@ public final class TunnelManager extends BaseObservable { private void onTunnelsLoaded(final Iterable present, final Collection running) { for (final String name : present) addToList(name, null, running.contains(name) ? State.UP : State.DOWN); - final String lastUsedName = preferences.getString(KEY_LAST_USED_TUNNEL, null); + final String lastUsedName = Application.getSharedPreferences().getString(KEY_LAST_USED_TUNNEL, null); if (lastUsedName != null) setLastUsedTunnel(tunnels.get(lastUsedName)); final CompletableFuture[] toComplete; @@ -171,7 +159,7 @@ public final class TunnelManager extends BaseObservable { } public void refreshTunnelStates() { - asyncWorker.supplyAsync(backend::enumerate) + Application.getAsyncWorker().supplyAsync(backend::enumerate) .thenAccept(running -> { for (final Tunnel tunnel : tunnels) tunnel.onStateChanged(running.contains(tunnel.getName()) ? State.UP : State.DOWN); @@ -180,7 +168,7 @@ public final class TunnelManager extends BaseObservable { } public CompletionStage restoreState(final boolean force) { - if (!force && !preferences.getBoolean(KEY_RESTORE_ON_BOOT, false)) + if (!force && !Application.getSharedPreferences().getBoolean(KEY_RESTORE_ON_BOOT, false)) return CompletableFuture.completedFuture(null); synchronized (delayedLoadRestoreTunnels) { if (!haveLoaded) { @@ -189,7 +177,7 @@ public final class TunnelManager extends BaseObservable { return f; } } - final Set previouslyRunning = preferences.getStringSet(KEY_RUNNING_TUNNELS, null); + final Set previouslyRunning = Application.getSharedPreferences().getStringSet(KEY_RUNNING_TUNNELS, null); if (previouslyRunning == null) return CompletableFuture.completedFuture(null); return CompletableFuture.allOf(StreamSupport.stream(tunnels) @@ -203,7 +191,7 @@ public final class TunnelManager extends BaseObservable { .filter(tunnel -> tunnel.getState() == State.UP) .map(Tunnel::getName) .collect(Collectors.toUnmodifiableSet()); - preferences.edit().putStringSet(KEY_RUNNING_TUNNELS, runningTunnels).apply(); + Application.getSharedPreferences().edit().putStringSet(KEY_RUNNING_TUNNELS, runningTunnels).apply(); } private void setLastUsedTunnel(final Tunnel tunnel) { @@ -212,13 +200,13 @@ public final class TunnelManager extends BaseObservable { lastUsedTunnel = tunnel; notifyPropertyChanged(BR.lastUsedTunnel); if (tunnel != null) - preferences.edit().putString(KEY_LAST_USED_TUNNEL, tunnel.getName()).apply(); + Application.getSharedPreferences().edit().putString(KEY_LAST_USED_TUNNEL, tunnel.getName()).apply(); else - preferences.edit().remove(KEY_LAST_USED_TUNNEL).apply(); + Application.getSharedPreferences().edit().remove(KEY_LAST_USED_TUNNEL).apply(); } CompletionStage setTunnelConfig(final Tunnel tunnel, final Config config) { - return asyncWorker.supplyAsync(() -> { + return Application.getAsyncWorker().supplyAsync(() -> { final Config appliedConfig = backend.applyConfig(tunnel, config); return configStore.save(tunnel.getName(), appliedConfig); }).thenApply(tunnel::onConfigChanged); @@ -237,7 +225,7 @@ public final class TunnelManager extends BaseObservable { if (wasLastUsed) setLastUsedTunnel(null); tunnels.remove(tunnel); - return asyncWorker.supplyAsync(() -> { + return Application.getAsyncWorker().supplyAsync(() -> { if (originalState == State.UP) backend.setState(tunnel, State.DOWN); configStore.rename(tunnel.getName(), name); @@ -259,7 +247,7 @@ public final class TunnelManager extends BaseObservable { CompletionStage setTunnelState(final Tunnel tunnel, final State state) { // Ensure the configuration is loaded before trying to use it. return tunnel.getConfigAsync().thenCompose(x -> - asyncWorker.supplyAsync(() -> backend.setState(tunnel, state)) + Application.getAsyncWorker().supplyAsync(() -> backend.setState(tunnel, state)) ).whenComplete((newState, e) -> { // Ensure onStateChanged is always called (failure or not), and with the correct state. tunnel.onStateChanged(e == null ? newState : tunnel.getState()); @@ -272,7 +260,7 @@ public final class TunnelManager extends BaseObservable { public static final class IntentReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { - final TunnelManager manager = Application.getComponent().getTunnelManager(); + final TunnelManager manager = Application.getTunnelManager(); if (intent == null) return; final String action = intent.getAction(); 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 4770c4b3..36cc513e 100644 --- a/app/src/main/java/com/wireguard/android/preference/LogExporterPreference.java +++ b/app/src/main/java/com/wireguard/android/preference/LogExporterPreference.java @@ -51,7 +51,7 @@ public class LogExporterPreference extends Preference { } private void exportLog() { - Application.getComponent().getAsyncWorker().supplyAsync(() -> { + Application.getAsyncWorker().supplyAsync(() -> { final File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); final File file = new File(path, "wireguard-log.txt"); if (!path.isDirectory() && !path.mkdirs()) 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 0d04641c..f8cab060 100644 --- a/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java +++ b/app/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.java @@ -13,10 +13,7 @@ import android.system.OsConstants; import android.util.AttributeSet; import com.wireguard.android.Application; -import com.wireguard.android.Application.ApplicationComponent; import com.wireguard.android.R; -import com.wireguard.android.util.AsyncWorker; -import com.wireguard.android.util.ToolsInstaller; /** * Preference implementing a button that asynchronously runs {@code ToolsInstaller} and displays the @@ -24,16 +21,10 @@ import com.wireguard.android.util.ToolsInstaller; */ public class ToolsInstallerPreference extends Preference { - private final AsyncWorker asyncWorker; - private final ToolsInstaller toolsInstaller; private State state = State.INITIAL; - @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) public ToolsInstallerPreference(final Context context, final AttributeSet attrs) { super(context, attrs); - final ApplicationComponent applicationComponent = Application.getComponent(); - asyncWorker = applicationComponent.getAsyncWorker(); - toolsInstaller = applicationComponent.getToolsInstaller(); } @Override @@ -49,7 +40,7 @@ public class ToolsInstallerPreference extends Preference { @Override public void onAttached() { super.onAttached(); - asyncWorker.supplyAsync(toolsInstaller::areInstalled).whenComplete(this::onCheckResult); + Application.getAsyncWorker().supplyAsync(Application.getToolsInstaller()::areInstalled).whenComplete(this::onCheckResult); } private void onCheckResult(final Integer result, final Throwable throwable) { @@ -60,7 +51,7 @@ public class ToolsInstallerPreference extends Preference { @Override protected void onClick() { setState(workingState()); - asyncWorker.supplyAsync(toolsInstaller::install).whenComplete(this::onInstallResult); + Application.getAsyncWorker().supplyAsync(Application.getToolsInstaller()::install).whenComplete(this::onInstallResult); } private void onInstallResult(final Integer result, final Throwable throwable) { @@ -86,13 +77,13 @@ public class ToolsInstallerPreference extends Preference { } private State initialState() { - return toolsInstaller.willInstallAsMagiskModule(false) ? State.INITIAL_MAGISK : State.INITIAL_SYSTEM; + return Application.getToolsInstaller().willInstallAsMagiskModule(false) ? State.INITIAL_MAGISK : State.INITIAL_SYSTEM; } private State workingState() { - return toolsInstaller.willInstallAsMagiskModule(false) ? State.WORKING_MAGISK : State.WORKING_SYSTEM; + return Application.getToolsInstaller().willInstallAsMagiskModule(false) ? State.WORKING_MAGISK : State.WORKING_SYSTEM; } private State successState() { - return toolsInstaller.willInstallAsMagiskModule(false) ? State.SUCCESS_MAGISK : State.SUCCESS_SYSTEM; + return Application.getToolsInstaller().willInstallAsMagiskModule(false) ? State.SUCCESS_MAGISK : State.SUCCESS_SYSTEM; } private enum 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 2cce769d..c42fe32a 100644 --- a/app/src/main/java/com/wireguard/android/preference/VersionPreference.java +++ b/app/src/main/java/com/wireguard/android/preference/VersionPreference.java @@ -16,28 +16,23 @@ import com.wireguard.android.BuildConfig; import com.wireguard.android.R; import com.wireguard.android.backend.GoBackend; import com.wireguard.android.backend.WgQuickBackend; -import com.wireguard.android.util.RootShell; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; - -import java9.util.concurrent.CompletionStage; - public class VersionPreference extends Preference { private String versionSummary; public VersionPreference(final Context context, final AttributeSet attrs) { super(context, attrs); - if (Application.getComponent().getBackendType() == GoBackend.class) { + if (Application.getBackendType() == GoBackend.class) { versionSummary = getContext().getString(R.string.version_userspace_summary, GoBackend.getVersion()); - } else if (Application.getComponent().getBackendType() == WgQuickBackend.class) { + } else if (Application.getBackendType() == WgQuickBackend.class) { versionSummary = getContext().getString(R.string.version_kernel_summary_checking); - Application.getComponent().getAsyncWorker().supplyAsync(() -> { + Application.getAsyncWorker().supplyAsync(() -> { final List output = new ArrayList<>(); - if (Application.getComponent().getRootShell() + if (Application.getRootShell() .run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty()) throw new RuntimeException("Unable to determine kernel module version"); return output.get(0); 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 7625dec1..98ab6eb3 100644 --- a/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java +++ b/app/src/main/java/com/wireguard/android/preference/ZipExporterPreference.java @@ -58,7 +58,7 @@ public class ZipExporterPreference extends Preference { } private void exportZip() { - final List tunnels = new ArrayList<>(Application.getComponent().getTunnelManager().getTunnels()); + final List tunnels = new ArrayList<>(Application.getTunnelManager().getTunnels()); final List> futureConfigs = new ArrayList<>(tunnels.size()); for (final Tunnel tunnel : tunnels) futureConfigs.add(tunnel.getConfigAsync().toCompletableFuture()); @@ -67,7 +67,7 @@ public class ZipExporterPreference extends Preference { return; } CompletableFuture.allOf(futureConfigs.toArray(new CompletableFuture[futureConfigs.size()])) - .whenComplete((ignored1, exception) -> Application.getComponent().getAsyncWorker().supplyAsync(() -> { + .whenComplete((ignored1, exception) -> Application.getAsyncWorker().supplyAsync(() -> { if (exception != null) throw exception; final File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); diff --git a/app/src/main/java/com/wireguard/android/util/AsyncWorker.java b/app/src/main/java/com/wireguard/android/util/AsyncWorker.java index 16eda82e..a15613a9 100644 --- a/app/src/main/java/com/wireguard/android/util/AsyncWorker.java +++ b/app/src/main/java/com/wireguard/android/util/AsyncWorker.java @@ -8,13 +8,8 @@ package com.wireguard.android.util; import android.os.Handler; -import com.wireguard.android.Application.ApplicationHandler; -import com.wireguard.android.Application.ApplicationScope; - import java.util.concurrent.Executor; -import javax.inject.Inject; - import java9.util.concurrent.CompletableFuture; import java9.util.concurrent.CompletionStage; @@ -22,13 +17,11 @@ import java9.util.concurrent.CompletionStage; * Helper class for running asynchronous tasks and ensuring they are completed on the main thread. */ -@ApplicationScope public class AsyncWorker { private final Executor executor; private final Handler handler; - @Inject - AsyncWorker(final Executor executor, @ApplicationHandler final Handler handler) { + public AsyncWorker(final Executor executor, final Handler handler) { this.executor = executor; this.handler = handler; } 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 7a73929c..a90ff82e 100644 --- a/app/src/main/java/com/wireguard/android/util/RootShell.java +++ b/app/src/main/java/com/wireguard/android/util/RootShell.java @@ -9,8 +9,6 @@ package com.wireguard.android.util; import android.content.Context; import android.util.Log; -import com.wireguard.android.Application.ApplicationContext; -import com.wireguard.android.Application.ApplicationScope; import com.wireguard.android.R; import java.io.BufferedReader; @@ -23,13 +21,10 @@ import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.UUID; -import javax.inject.Inject; - /** * Helper class for running commands as root. */ -@ApplicationScope public class RootShell { private static final String SU = "su"; private static final String TAG = "WireGuard/" + RootShell.class.getSimpleName(); @@ -44,8 +39,7 @@ public class RootShell { private OutputStreamWriter stdin; private BufferedReader stdout; - @Inject - public RootShell(@ApplicationContext final Context context) { + public RootShell(final Context context) { deviceNotRootedMessage = context.getString(R.string.error_root); final File cacheDir = context.getCacheDir(); localBinaryDir = new File(cacheDir, "bin"); 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 d4a96f84..dbd3085e 100644 --- a/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java +++ b/app/src/main/java/com/wireguard/android/util/ToolsInstaller.java @@ -11,27 +11,19 @@ import android.system.OsConstants; import android.util.Log; import com.wireguard.android.Application; -import com.wireguard.android.Application.ApplicationContext; -import com.wireguard.android.Application.ApplicationScope; import com.wireguard.android.BuildConfig; import com.wireguard.android.util.RootShell.NoRootException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.inject.Inject; - -import java9.util.concurrent.CompletionStage; - /** * Helper to install WireGuard tools to the system partition. */ -@ApplicationScope public final class ToolsInstaller { private static final String[][] EXECUTABLES = { {"libwg.so", "wg"}, @@ -47,15 +39,12 @@ public final class ToolsInstaller { private final File localBinaryDir; private final Object lock = new Object(); private final File nativeLibraryDir; - private final RootShell rootShell; private Boolean areToolsAvailable; private Boolean installAsMagiskModule; - @Inject - public ToolsInstaller(@ApplicationContext final Context context, final RootShell rootShell) { + public ToolsInstaller(final Context context) { localBinaryDir = new File(context.getCacheDir(), "bin"); nativeLibraryDir = new File(context.getApplicationInfo().nativeLibraryDir); - this.rootShell = rootShell; } private static File getInstallDir() { @@ -82,7 +71,7 @@ public final class ToolsInstaller { } script.append("exit ").append(OsConstants.EALREADY).append(';'); try { - return rootShell.run(null, script.toString()); + return Application.getRootShell().run(null, script.toString()); } catch (final IOException ignored) { return OsConstants.EXIT_FAILURE; } @@ -114,7 +103,7 @@ public final class ToolsInstaller { if (!checkForIt) throw new RuntimeException("Expected to already know whether this is a Magisk system"); try { - installAsMagiskModule = rootShell.run(null, "[ -d /sbin/.core/mirror -a -d /sbin/.core/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS; + installAsMagiskModule = Application.getRootShell().run(null, "[ -d /sbin/.core/mirror -a -d /sbin/.core/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS; } catch (final Exception ignored) { installAsMagiskModule = false; } @@ -134,7 +123,7 @@ public final class ToolsInstaller { new File(nativeLibraryDir, names[0]), destination, destination, destination)); } try { - return rootShell.run(null, script.toString()); + return Application.getRootShell().run(null, script.toString()); } catch (final IOException ignored) { return OsConstants.EXIT_FAILURE; } @@ -155,7 +144,7 @@ public final class ToolsInstaller { script.append("trap - INT TERM EXIT;"); try { - return rootShell.run(null, script.toString()); + return Application.getRootShell().run(null, script.toString()); } catch (final IOException ignored) { return OsConstants.EXIT_FAILURE; } @@ -182,7 +171,7 @@ public final class ToolsInstaller { script.append("exit ").append(OsConstants.EXIT_SUCCESS).append(';'); try { - return rootShell.run(null, script.toString()); + return Application.getRootShell().run(null, script.toString()); } catch (final IOException ignored) { return OsConstants.EXIT_FAILURE; }