From d2fcbf72ae3de646b3fe9cc753b115fba78c7ab3 Mon Sep 17 00:00:00 2001 From: Adam Szewera Date: Sun, 4 Feb 2024 22:10:29 +0100 Subject: [PATCH] Refactor to use Dagger2 Hilt --- app/build.gradle.kts | 7 ++- .../syncthingandroid/DaggerComponent.java | 37 ------------- .../syncthingandroid/SyncthingApp.java | 18 +++---- .../syncthingandroid/SyncthingModule.java | 27 +++++++--- .../activities/FirstStartActivity.java | 28 +++++----- .../activities/FolderPickerActivity.java | 4 -- .../activities/MainActivity.java | 34 +++++------- .../activities/SettingsActivity.java | 26 +++++++-- .../activities/WebGuiActivity.java | 9 +++- .../receiver/AppConfigReceiver.java | 10 ++-- .../service/EventProcessor.java | 10 +++- .../service/NotificationHandler.java | 18 ++++--- .../syncthingandroid/service/RestApi.java | 15 ++++-- .../service/RunConditionMonitor.java | 12 +++-- .../service/SyncthingRunnable.java | 14 +++-- .../service/SyncthingService.java | 54 +++++++++++++++---- .../syncthingandroid/util/ConfigXml.java | 33 ++++++++---- .../syncthingandroid/util/Languages.java | 14 +++-- build.gradle.kts | 1 + 19 files changed, 217 insertions(+), 154 deletions(-) delete mode 100644 app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b1c654fd3..35498479e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -4,6 +4,7 @@ plugins { id("com.android.application") id("com.github.ben-manes.versions") id("com.github.triplet.play") version "3.7.0" + id("com.google.dagger.hilt.android") } dependencies { @@ -21,9 +22,11 @@ dependencies { } implementation("com.google.zxing:core:3.4.1") + // dagger + implementation("com.google.dagger:hilt-android:2.49") + annotationProcessor("com.google.dagger:hilt-compiler:2.49") + implementation("androidx.constraintlayout:constraintlayout:2.0.4") - implementation("com.google.dagger:dagger:2.49") - annotationProcessor("com.google.dagger:dagger-compiler:2.49") androidTestImplementation("androidx.test:rules:1.4.0") androidTestImplementation("androidx.annotation:annotation:1.2.0") } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java b/app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java deleted file mode 100644 index 586616676..000000000 --- a/app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.nutomic.syncthingandroid; - -import com.nutomic.syncthingandroid.activities.FirstStartActivity; -import com.nutomic.syncthingandroid.activities.FolderPickerActivity; -import com.nutomic.syncthingandroid.activities.MainActivity; -import com.nutomic.syncthingandroid.activities.SettingsActivity; -import com.nutomic.syncthingandroid.receiver.AppConfigReceiver; -import com.nutomic.syncthingandroid.service.RunConditionMonitor; -import com.nutomic.syncthingandroid.service.EventProcessor; -import com.nutomic.syncthingandroid.service.NotificationHandler; -import com.nutomic.syncthingandroid.service.RestApi; -import com.nutomic.syncthingandroid.service.SyncthingRunnable; -import com.nutomic.syncthingandroid.service.SyncthingService; -import com.nutomic.syncthingandroid.util.Languages; - -import javax.inject.Singleton; - -import dagger.Component; - -@Singleton -@Component(modules = {SyncthingModule.class}) -public interface DaggerComponent { - - void inject(SyncthingApp app); - void inject(MainActivity activity); - void inject(FirstStartActivity activity); - void inject(FolderPickerActivity activity); - void inject(Languages languages); - void inject(SyncthingService service); - void inject(RunConditionMonitor runConditionMonitor); - void inject(EventProcessor eventProcessor); - void inject(SyncthingRunnable syncthingRunnable); - void inject(NotificationHandler notificationHandler); - void inject(AppConfigReceiver appConfigReceiver); - void inject(RestApi restApi); - void inject(SettingsActivity.SettingsFragment fragment); -} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/SyncthingApp.java b/app/src/main/java/com/nutomic/syncthingandroid/SyncthingApp.java index 4f3104b91..684d6d09f 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/SyncthingApp.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/SyncthingApp.java @@ -1,6 +1,7 @@ package com.nutomic.syncthingandroid; import android.app.Application; +import android.content.SharedPreferences; import android.os.StrictMode; import com.google.android.material.color.DynamicColors; @@ -8,9 +9,14 @@ import javax.inject.Inject; +import dagger.hilt.android.HiltAndroidApp; + +@HiltAndroidApp public class SyncthingApp extends Application { - @Inject DaggerComponent mComponent; + // temporarily here + @Inject + SharedPreferences mSharedPreferences; @Override public void onCreate() { @@ -18,12 +24,7 @@ public void onCreate() { super.onCreate(); - DaggerDaggerComponent.builder() - .syncthingModule(new SyncthingModule(this)) - .build() - .inject(this); - - new Languages(this).setLanguage(this); + new Languages(this, mSharedPreferences).setLanguage(this); // The main point here is to use a VM policy without // `detectFileUriExposure`, as that leads to exceptions when e.g. @@ -36,7 +37,4 @@ public void onCreate() { StrictMode.setVmPolicy(policy); } - public DaggerComponent component() { - return mComponent; - } } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/SyncthingModule.java b/app/src/main/java/com/nutomic/syncthingandroid/SyncthingModule.java index c06c8a016..d5f31cb17 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/SyncthingModule.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/SyncthingModule.java @@ -1,33 +1,44 @@ package com.nutomic.syncthingandroid; +import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import com.nutomic.syncthingandroid.service.NotificationHandler; +import com.nutomic.syncthingandroid.util.ConfigXml; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; +import dagger.hilt.InstallIn; +import dagger.hilt.android.qualifiers.ApplicationContext; +import dagger.hilt.components.SingletonComponent; @Module +@InstallIn(SingletonComponent.class) public class SyncthingModule { - private final SyncthingApp mApp; - - public SyncthingModule(SyncthingApp app) { - mApp = app; + @Provides + @Singleton + public static SharedPreferences getPreferences( + @ApplicationContext Context mApp + ) { + return PreferenceManager.getDefaultSharedPreferences(mApp); } @Provides @Singleton - public SharedPreferences getPreferences() { - return PreferenceManager.getDefaultSharedPreferences(mApp); + public static NotificationHandler getNotificationHandler( + @ApplicationContext Context mApp, + SharedPreferences preferences + ) { + return new NotificationHandler(mApp, preferences); } @Provides @Singleton - public NotificationHandler getNotificationHandler() { - return new NotificationHandler(mApp); + public static ConfigXml getConfigXml(@ApplicationContext Context mApp) { + return new ConfigXml(mApp); } } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/FirstStartActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/FirstStartActivity.java index f7c951daf..e56bd9b31 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/FirstStartActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/FirstStartActivity.java @@ -1,8 +1,8 @@ package com.nutomic.syncthingandroid.activities; +import android.Manifest; import android.annotation.SuppressLint; import android.annotation.TargetApi; -import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; @@ -10,17 +10,9 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Color; -import android.Manifest; import android.net.Uri; import android.os.Build; import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; -import androidx.viewpager.widget.PagerAdapter; -import androidx.viewpager.widget.ViewPager; - import android.preference.PreferenceManager; import android.provider.Settings; import android.text.Html; @@ -34,21 +26,30 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.activity.ComponentActivity; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + import com.google.android.material.color.MaterialColors; import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.databinding.ActivityFirstStartBinding; import com.nutomic.syncthingandroid.service.Constants; import com.nutomic.syncthingandroid.util.PermissionUtil; import com.nutomic.syncthingandroid.util.Util; -import java.io.File; - import org.apache.commons.io.FileUtils; +import java.io.File; + import javax.inject.Inject; -public class FirstStartActivity extends Activity { +import dagger.hilt.android.AndroidEntryPoint; + +@AndroidEntryPoint +public class FirstStartActivity extends ComponentActivity { private enum Slide { @@ -81,7 +82,6 @@ private enum Slide { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ((SyncthingApp) getApplication()).component().inject(this); /** * Recheck storage permission. If it has been revoked after the user diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java index 99a932196..ce09fe64b 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderPickerActivity.java @@ -6,7 +6,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; @@ -30,7 +29,6 @@ import com.google.common.collect.Sets; import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.service.Constants; import com.nutomic.syncthingandroid.service.SyncthingService; import com.nutomic.syncthingandroid.service.SyncthingServiceBinder; @@ -85,8 +83,6 @@ public static Intent createIntent(Context context, String initialDirectory, @Nul @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ((SyncthingApp) getApplication()).component().inject(this); - setContentView(R.layout.activity_folder_picker); mListView = findViewById(android.R.id.list); mListView.setOnItemClickListener(this); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java index 4c7154bde..9e76a2517 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/MainActivity.java @@ -1,10 +1,9 @@ package com.nutomic.syncthingandroid.activities; +import static java.lang.Math.min; + import android.annotation.SuppressLint; import android.app.Activity; - -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; import android.app.Dialog; import android.content.ActivityNotFoundException; import android.content.ComponentName; @@ -20,20 +19,8 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.os.PersistableBundle; import android.os.PowerManager; import android.provider.Settings; - -import com.google.android.material.color.DynamicColors; -import com.google.android.material.tabs.TabLayout; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; -import androidx.core.view.GravityCompat; -import androidx.viewpager.widget.ViewPager; -import androidx.drawerlayout.widget.DrawerLayout; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.ActionBarDrawerToggle; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; @@ -45,14 +32,21 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; - +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AlertDialog; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; import com.annimon.stream.function.Consumer; +import com.google.android.material.tabs.TabLayout; import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.fragments.DeviceListFragment; import com.nutomic.syncthingandroid.fragments.DrawerFragment; import com.nutomic.syncthingandroid.fragments.FolderListFragment; -import com.nutomic.syncthingandroid.service.Constants; import com.nutomic.syncthingandroid.service.RestApi; import com.nutomic.syncthingandroid.service.SyncthingService; import com.nutomic.syncthingandroid.service.SyncthingServiceBinder; @@ -64,13 +58,14 @@ import javax.inject.Inject; -import static java.lang.Math.min; +import dagger.hilt.android.AndroidEntryPoint; /** * Shows {@link FolderListFragment} and * {@link DeviceListFragment} in different tabs, and * {@link DrawerFragment} in the navigation drawer. */ +@AndroidEntryPoint public class MainActivity extends StateDialogActivity implements SyncthingService.OnServiceStateChangeListener { @@ -219,7 +214,6 @@ public CharSequence getPageTitle(int position) { */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ((SyncthingApp) getApplication()).component().inject(this); setContentView(R.layout.activity_main); mDrawerLayout = findViewById(R.id.drawer_layout); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java index edcccded8..81b09e422 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java @@ -1,5 +1,6 @@ package com.nutomic.syncthingandroid.activities; +import android.annotation.SuppressLint; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -45,20 +46,25 @@ import javax.inject.Inject; +import dagger.hilt.android.AndroidEntryPoint; import eu.chainfire.libsuperuser.Shell; +@AndroidEntryPoint public class SettingsActivity extends SyncthingActivity { public static final String EXTRA_OPEN_SUB_PREF_SCREEN = "com.nutomic.syncthingandroid.activities.SettingsActivity.OPEN_SUB_PREF_SCREEN"; + @Inject NotificationHandler mNotificationHandler; + @Inject SharedPreferences mPreferences; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_preferences); setTitle(R.string.settings_title); - SettingsFragment settingsFragment = new SettingsFragment(); + SettingsFragment settingsFragment = new SettingsFragment(mNotificationHandler, mPreferences); Bundle bundle = new Bundle(); bundle.putString(EXTRA_OPEN_SUB_PREF_SCREEN, getIntent().getStringExtra(EXTRA_OPEN_SUB_PREF_SCREEN)); settingsFragment.setArguments(bundle); @@ -90,6 +96,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } } + @SuppressLint("ValidFragment") public static class SettingsFragment extends PreferenceFragment implements SyncthingActivity.OnServiceConnectedListener, SyncthingService.OnServiceStateChangeListener, Preference.OnPreferenceChangeListener, @@ -102,8 +109,8 @@ public static class SettingsFragment extends PreferenceFragment private static final String KEY_ST_RESET_DATABASE = "st_reset_database"; private static final String KEY_ST_RESET_DELTAS = "st_reset_deltas"; - @Inject NotificationHandler mNotificationHandler; - @Inject SharedPreferences mPreferences; + private NotificationHandler mNotificationHandler; + private SharedPreferences mPreferences; private PreferenceGroup mCategoryRunConditions; private CheckBoxPreference mRunConditions; @@ -147,6 +154,16 @@ public static class SettingsFragment extends PreferenceFragment private Boolean mPendingConfig = false; + @SuppressLint("ValidFragment") + public SettingsFragment( + NotificationHandler NotificationHandler, + SharedPreferences preferences + ) { + super(); + mNotificationHandler = NotificationHandler; + mPreferences = preferences; + } + /** * Indicates if run conditions were changed and need to be * re-evaluated when the user leaves the preferences screen. @@ -156,7 +173,6 @@ public static class SettingsFragment extends PreferenceFragment @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ((SyncthingApp) getActivity().getApplication()).component().inject(this); ((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this); } @@ -193,7 +209,7 @@ public void onActivityCreated(Bundle savedInstanceState) { if (Build.VERSION.SDK_INT >= 24) { categoryBehaviour.removePreference(languagePref); } else { - Languages languages = new Languages(getActivity()); + Languages languages = new Languages(getActivity(), mPreferences); languagePref.setDefaultValue(Languages.USE_SYSTEM_DEFAULT); languagePref.setEntries(languages.getAllNames()); languagePref.setEntryValues(languages.getSupportedLocales()); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/WebGuiActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/WebGuiActivity.java index db64881c6..3a0c81b69 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/WebGuiActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/WebGuiActivity.java @@ -50,9 +50,14 @@ import java.util.Map; import java.util.Properties; +import javax.inject.Inject; + +import dagger.hilt.android.AndroidEntryPoint; + /** * Holds a WebView that shows the web ui of the local syncthing instance. */ +@AndroidEntryPoint public class WebGuiActivity extends StateDialogActivity implements SyncthingService.OnServiceStateChangeListener { @@ -64,7 +69,8 @@ public class WebGuiActivity extends StateDialogActivity private X509Certificate mCaCert; - private ConfigXml mConfig; + @Inject + ConfigXml mConfig; /** * Hides the loading screen and shows the WebView once it is fully loaded. @@ -128,7 +134,6 @@ public void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_web_gui); mLoadingView = findViewById(R.id.loading); - mConfig = new ConfigXml(this); loadCaCert(); mWebView = findViewById(R.id.webview); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java b/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java index 3e2265e5d..573719767 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java @@ -6,16 +6,19 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; -import com.nutomic.syncthingandroid.SyncthingApp; -import com.nutomic.syncthingandroid.service.NotificationHandler; import com.nutomic.syncthingandroid.service.Constants; +import com.nutomic.syncthingandroid.service.NotificationHandler; import com.nutomic.syncthingandroid.service.SyncthingService; import javax.inject.Inject; +import dagger.hilt.android.AndroidEntryPoint; +import dagger.hilt.android.qualifiers.ApplicationContext; + /** * Broadcast-receiver to control and configure Syncthing remotely. */ +@AndroidEntryPoint public class AppConfigReceiver extends BroadcastReceiver { /** @@ -33,8 +36,7 @@ public class AppConfigReceiver extends BroadcastReceiver { @Inject NotificationHandler mNotificationHandler; @Override - public void onReceive(Context context, Intent intent) { - ((SyncthingApp) context.getApplicationContext()).component().inject(this); + public void onReceive(@ApplicationContext Context context, Intent intent) { switch (intent.getAction()) { case ACTION_START: BootReceiver.startServiceCompat(context); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java b/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java index 6b02ed407..ddf957460 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java @@ -63,10 +63,16 @@ public class EventProcessor implements Runnable, RestApi.OnReceiveEventListener @Inject SharedPreferences mPreferences; @Inject NotificationHandler mNotificationHandler; - public EventProcessor(Context context, RestApi api) { - ((SyncthingApp) context.getApplicationContext()).component().inject(this); + public EventProcessor( + Context context, + RestApi api, + SharedPreferences preferences, + NotificationHandler notificationHandler + ) { mContext = context; mApi = api; + mPreferences = preferences; + mNotificationHandler = notificationHandler; } @Override diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java b/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java index 515de9dff..45fe472bd 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java @@ -1,6 +1,5 @@ package com.nutomic.syncthingandroid.service; -import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -9,20 +8,22 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; +import android.util.Log; + import androidx.annotation.StringRes; import androidx.core.app.NotificationCompat; -import android.util.Log; import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.activities.FirstStartActivity; import com.nutomic.syncthingandroid.activities.LogActivity; import com.nutomic.syncthingandroid.activities.MainActivity; -import com.nutomic.syncthingandroid.service.Constants; import com.nutomic.syncthingandroid.service.SyncthingService.State; import javax.inject.Inject; +import dagger.hilt.android.qualifiers.ApplicationContext; + + public class NotificationHandler { private static final String TAG = "NotificationHandler"; @@ -37,7 +38,7 @@ public class NotificationHandler { private static final String CHANNEL_PERSISTENT_WAITING = "03_syncthing_persistent_waiting"; private final Context mContext; - @Inject SharedPreferences mPreferences; + private SharedPreferences mPreferences; private final NotificationManager mNotificationManager; private final NotificationChannel mPersistentChannel; private final NotificationChannel mPersistentChannelWaiting; @@ -46,9 +47,12 @@ public class NotificationHandler { private Boolean lastStartForegroundService = false; private Boolean appShutdownInProgress = false; - public NotificationHandler(Context context) { - ((SyncthingApp) context.getApplicationContext()).component().inject(this); + public NotificationHandler( + @ApplicationContext Context context, + SharedPreferences preferences + ) { mContext = context; + mPreferences = preferences; mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java index 8a82da0f1..cd930812f 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java @@ -2,6 +2,7 @@ import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.util.Log; @@ -145,16 +146,22 @@ public interface OnResultListener2 { */ private Completion mCompletion = new Completion(); - @Inject NotificationHandler mNotificationHandler; + private NotificationHandler mNotificationHandler; - public RestApi(Context context, URL url, String apiKey, OnApiAvailableListener apiListener, - OnConfigChangedListener configListener) { - ((SyncthingApp) context.getApplicationContext()).component().inject(this); + public RestApi( + Context context, + URL url, + String apiKey, + OnApiAvailableListener apiListener, + OnConfigChangedListener configListener, + NotificationHandler notificationHandler + ) { mContext = context; mUrl = url; mApiKey = apiKey; mOnApiAvailableListener = apiListener; mOnConfigChangedListener = configListener; + mNotificationHandler = notificationHandler; } public interface OnApiAvailableListener { diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java b/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java index 997aedc6d..387cfda2e 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java @@ -46,7 +46,7 @@ public class RunConditionMonitor { private static final String POWER_SOURCE_CHARGER = "ac_power"; private static final String POWER_SOURCE_BATTERY = "battery_power"; - private @Nullable Object mSyncStatusObserverHandle = null; + private @Nullable Object mSyncStatusObserverHandle; private final SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() { @Override public void onStatusChanged(int which) { @@ -59,7 +59,7 @@ public interface OnRunConditionChangedListener { } private final Context mContext; - @Inject SharedPreferences mPreferences; + private SharedPreferences mPreferences; private ReceiverManager mReceiverManager; /** @@ -72,11 +72,15 @@ public interface OnRunConditionChangedListener { */ private RunConditionCheckResult lastRunConditionCheckResult; - public RunConditionMonitor(Context context, OnRunConditionChangedListener listener) { + public RunConditionMonitor( + Context context, + OnRunConditionChangedListener listener, + SharedPreferences preferences + ) { Log.v(TAG, "Created new instance"); - ((SyncthingApp) context.getApplicationContext()).component().inject(this); mContext = context; mOnRunConditionChangedListener = listener; + mPreferences = preferences; /** * Register broadcast receivers. diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java index 6be374ae4..d71386a3d 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java @@ -56,9 +56,9 @@ public class SyncthingRunnable implements Runnable { private final File mSyncthingBinary; private String[] mCommand; private final File mLogFile; - @Inject SharedPreferences mPreferences; + private SharedPreferences mPreferences; private final boolean mUseRoot; - @Inject NotificationHandler mNotificationHandler; + private NotificationHandler mNotificationHandler; public enum Command { deviceid, // Output the device ID to the command line. @@ -73,11 +73,17 @@ public enum Command { * * @param command Which type of Syncthing command to execute. */ - public SyncthingRunnable(Context context, Command command) { - ((SyncthingApp) context.getApplicationContext()).component().inject(this); + public SyncthingRunnable( + Context context, + Command command, + SharedPreferences preferences, + NotificationHandler notificationHandler + ) { mContext = context; mSyncthingBinary = Constants.getSyncthingBinary(mContext); mLogFile = Constants.getLogFile(mContext); + mPreferences = preferences; + mNotificationHandler = notificationHandler; // Get preferences relevant to starting syncthing core. mUseRoot = mPreferences.getBoolean(Constants.PREF_USE_ROOT, false) && Shell.SU.available(); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java index 138f6e979..a51200ef6 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java @@ -27,9 +27,13 @@ import javax.inject.Inject; +import dagger.hilt.android.AndroidEntryPoint; +import hilt_aggregated_deps._dagger_hilt_android_internal_lifecycle_HiltWrapper_DefaultViewModelFactories_ActivityModule; + /** * Holds the native syncthing instance and provides an API to access it. */ +@AndroidEntryPoint public class SyncthingService extends Service { private static final String TAG = "SyncthingService"; @@ -144,7 +148,6 @@ public enum State { private State mCurrentState = State.DISABLED; private AtomicReference mCurrentCheckResult = new AtomicReference<>(RunConditionCheckResult.SHOULD_RUN); - private ConfigXml mConfig; private @Nullable PollWebGuiAvailableTask mPollWebGuiAvailableTask = null; private @Nullable RestApi mApi = null; private @Nullable EventProcessor mEventProcessor = null; @@ -160,6 +163,7 @@ public enum State { @Inject NotificationHandler mNotificationHandler; @Inject SharedPreferences mPreferences; + @Inject ConfigXml mConfig; /** * Object that must be locked upon accessing mCurrentState @@ -189,7 +193,6 @@ public enum State { public void onCreate() { Log.v(TAG, "onCreate"); super.onCreate(); - ((SyncthingApp) getApplication()).component().inject(this); mHandler = new Handler(); /** @@ -238,7 +241,11 @@ public int onStartCommand(Intent intent, int flags, int startId) { * run/terminate syncthing. After initial run conditions are collected * the first decision is sent to {@link onUpdatedShouldRunDecision}. */ - mRunConditionMonitor = new RunConditionMonitor(SyncthingService.this, this::onUpdatedShouldRunDecision); + mRunConditionMonitor = new RunConditionMonitor( + SyncthingService.this, + this::onUpdatedShouldRunDecision, + mPreferences + ); } mNotificationHandler.updatePersistentNotification(this); @@ -249,12 +256,22 @@ public int onStartCommand(Intent intent, int flags, int startId) { shutdown(State.INIT, () -> launchStartupTask()); } else if (ACTION_RESET_DATABASE.equals(intent.getAction())) { shutdown(State.INIT, () -> { - new SyncthingRunnable(this, SyncthingRunnable.Command.resetdatabase).run(); + new SyncthingRunnable( + this, + SyncthingRunnable.Command.resetdatabase, + mPreferences, + mNotificationHandler + ).run(); launchStartupTask(); }); } else if (ACTION_RESET_DELTAS.equals(intent.getAction())) { shutdown(State.INIT, () -> { - new SyncthingRunnable(this, SyncthingRunnable.Command.resetdeltas).run(); + new SyncthingRunnable( + this, + SyncthingRunnable.Command.resetdeltas, + mPreferences, + mNotificationHandler + ).run(); launchStartupTask(); }); } else if (ACTION_REFRESH_NETWORK_INFO.equals(intent.getAction())) { @@ -365,7 +382,8 @@ protected Void doInBackground(Void... voids) { return null; } try { - syncthingService.mConfig = new ConfigXml(syncthingService); + // TODO: 04.02.2024 check if needed after all +// syncthingService.mConfig = new ConfigXml(syncthingService); syncthingService.mConfig.updateIfNeeded(); } catch (ConfigXml.OpenConfigException e) { syncthingService.mNotificationHandler.showCrashedNotification(R.string.config_create_failed, true); @@ -392,8 +410,14 @@ protected void onPostExecute(Void aVoid) { */ private void onStartupTaskCompleteListener() { if (mApi == null) { - mApi = new RestApi(this, mConfig.getWebGuiUrl(), mConfig.getApiKey(), - this::onApiAvailable, () -> onServiceStateChange(mCurrentState)); + mApi = new RestApi( + this, + mConfig.getWebGuiUrl(), + mConfig.getApiKey(), + this::onApiAvailable, + () -> onServiceStateChange(mCurrentState), + mNotificationHandler + ); Log.i(TAG, "Web GUI will be available at " + mConfig.getWebGuiUrl()); } @@ -402,7 +426,12 @@ private void onStartupTaskCompleteListener() { Log.e(TAG, "onStartupTaskCompleteListener: Syncthing binary lifecycle violated"); return; } - mSyncthingRunnable = new SyncthingRunnable(this, SyncthingRunnable.Command.main); + mSyncthingRunnable = new SyncthingRunnable( + this, + SyncthingRunnable.Command.main, + mPreferences, + mNotificationHandler + ); mSyncthingRunnableThread = new Thread(mSyncthingRunnable); mSyncthingRunnableThread.start(); @@ -456,7 +485,12 @@ private void onApiAvailable() { } if (mEventProcessor == null) { - mEventProcessor = new EventProcessor(SyncthingService.this, mApi); + mEventProcessor = new EventProcessor( + SyncthingService.this, + mApi, + mPreferences, + mNotificationHandler + ); mEventProcessor.start(); } } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java b/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java index 0e2d245dd..ecc4b5d61 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java @@ -4,12 +4,12 @@ import android.content.SharedPreferences; import android.os.Build; import android.os.Environment; -import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.service.Constants; +import com.nutomic.syncthingandroid.service.NotificationHandler; import com.nutomic.syncthingandroid.service.SyncthingRunnable; import org.mindrot.jbcrypt.BCrypt; @@ -19,16 +19,12 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import java.io.BufferedReader; import java.io.File; -import java.io.InputStreamReader; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; import java.util.Random; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.inject.Inject; import javax.xml.parsers.DocumentBuilder; @@ -40,6 +36,8 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import dagger.hilt.android.qualifiers.ApplicationContext; + /** * Provides direct access to the config.xml file in the file system. * @@ -54,19 +52,31 @@ public class OpenConfigException extends RuntimeException { private static final int FOLDER_ID_APPENDIX_LENGTH = 4; private final Context mContext; - @Inject SharedPreferences mPreferences; + + @Inject + SharedPreferences mPreferences; + + @Inject + NotificationHandler notificationHandler; private final File mConfigFile; private Document mConfig; - public ConfigXml(Context context) throws OpenConfigException { + public ConfigXml( + @ApplicationContext Context context + ) throws OpenConfigException { mContext = context; mConfigFile = Constants.getConfigFile(mContext); boolean isFirstStart = !mConfigFile.exists(); if (isFirstStart) { Log.i(TAG, "App started for the first time. Generating keys and config."); - new SyncthingRunnable(context, SyncthingRunnable.Command.generate).run(); + new SyncthingRunnable( + context, + SyncthingRunnable.Command.generate, + mPreferences, + notificationHandler + ).run(); } readConfig(); @@ -75,7 +85,12 @@ public ConfigXml(Context context) throws OpenConfigException { boolean changed = false; Log.i(TAG, "Starting syncthing to retrieve local device id."); - String logOutput = new SyncthingRunnable(context, SyncthingRunnable.Command.deviceid).run(true); + String logOutput = new SyncthingRunnable( + context, + SyncthingRunnable.Command.deviceid, + mPreferences, + notificationHandler + ).run(true); String localDeviceID = logOutput.replace("\n", ""); // Verify local device ID is correctly formatted. if (localDeviceID.matches("^([A-Z0-9]{7}-){7}[A-Z0-9]{7}$")) { diff --git a/app/src/main/java/com/nutomic/syncthingandroid/util/Languages.java b/app/src/main/java/com/nutomic/syncthingandroid/util/Languages.java index d74e1433e..c56b56629 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/util/Languages.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/util/Languages.java @@ -1,18 +1,15 @@ package com.nutomic.syncthingandroid.util; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; -import android.os.Build; import android.text.TextUtils; import com.nutomic.syncthingandroid.R; -import com.nutomic.syncthingandroid.SyncthingApp; import java.util.Arrays; import java.util.Collections; @@ -22,8 +19,6 @@ import java.util.Set; import java.util.TreeMap; -import javax.inject.Inject; - /** * Based on https://gitlab.com/fdroid/fdroidclient/blob/master/app/src/main/java/org/fdroid/fdroid/Languages.java */ @@ -34,15 +29,18 @@ public final class Languages { private static final Locale DEFAULT_LOCALE; public static final String PREFERENCE_LANGUAGE = "pref_current_language"; - @Inject SharedPreferences mPreferences; + private SharedPreferences mPreferences; private static Map mAvailableLanguages; static { DEFAULT_LOCALE = Locale.getDefault(); } - public Languages(Context context) { - ((SyncthingApp) context.getApplicationContext()).component().inject(this); + public Languages( + Context context, + SharedPreferences preferences + ) { + mPreferences = preferences; Map tmpMap = new TreeMap<>(); List locales = Arrays.asList(LOCALES_TO_TEST); // Capitalize language names diff --git a/build.gradle.kts b/build.gradle.kts index 2aa97e95f..6118d0972 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,6 +16,7 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:7.3.1") classpath("com.github.ben-manes:gradle-versions-plugin:0.36.0") + classpath("com.google.dagger:hilt-android-gradle-plugin:2.49") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files