diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 78451542..d5fc515b 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -108,18 +108,6 @@ android:value=".activities.MainActivity" /> - - - - - - - - - - - - diff --git a/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java b/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java index 02e85917..9e1d851f 100644 --- a/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java +++ b/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java @@ -3,6 +3,7 @@ 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.DeviceStateHolder; import com.nutomic.syncthingandroid.service.EventProcessor; @@ -32,4 +33,5 @@ public interface DaggerComponent { void inject(NotificationHandler notificationHandler); void inject(AppConfigReceiver appConfigReceiver); void inject(RestApi restApi); + void inject(SettingsActivity.SettingsFragment fragment); } diff --git a/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java b/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java index 50d5fb9e..3996ad84 100644 --- a/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java +++ b/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java @@ -2,6 +2,7 @@ package com.nutomic.syncthingandroid.activities; import android.app.AlertDialog; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Build; @@ -12,6 +13,7 @@ import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; +import android.support.annotation.Nullable; import android.util.Log; import android.widget.Toast; @@ -19,10 +21,12 @@ import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import com.nutomic.syncthingandroid.R; +import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.model.Config; import com.nutomic.syncthingandroid.model.Device; import com.nutomic.syncthingandroid.model.Options; import com.nutomic.syncthingandroid.service.Constants; +import com.nutomic.syncthingandroid.service.NotificationHandler; import com.nutomic.syncthingandroid.service.RestApi; import com.nutomic.syncthingandroid.service.SyncthingService; import com.nutomic.syncthingandroid.util.Languages; @@ -31,6 +35,8 @@ import com.nutomic.syncthingandroid.views.WifiSsidPreference; import java.security.InvalidParameterException; +import javax.inject.Inject; + import eu.chainfire.libsuperuser.Shell; public class SettingsActivity extends SyncthingActivity { @@ -46,7 +52,7 @@ public class SettingsActivity extends SyncthingActivity { public static class SettingsFragment extends PreferenceFragment implements SyncthingActivity.OnServiceConnectedListener, SyncthingService.OnApiChangeListener, Preference.OnPreferenceChangeListener, - Preference.OnPreferenceClickListener { + Preference.OnPreferenceClickListener, SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "SettingsFragment"; private static final String KEY_STTRACE = "sttrace"; @@ -54,6 +60,9 @@ public class SettingsActivity extends SyncthingActivity { private static final String KEY_IMPORT_CONFIG = "import_config"; private static final String KEY_STRESET = "streset"; + @Inject NotificationHandler mNotificationHandler; + @Inject SharedPreferences mPreferences; + private CheckBoxPreference mAlwaysRunInBackground; private CheckBoxPreference mSyncOnlyCharging; private CheckBoxPreference mSyncOnlyWifi; @@ -84,6 +93,14 @@ public class SettingsActivity extends SyncthingActivity { private Options mOptions; private Config.Gui mGui; + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ((SyncthingApp) getActivity().getApplication()).component().inject(this); + ((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this); + mPreferences.registerOnSharedPreferenceChangeListener(this); + } + /** * Loads layout, sets version from Rest API. * @@ -93,8 +110,6 @@ public class SettingsActivity extends SyncthingActivity { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - ((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this); - addPreferencesFromResource(R.xml.app_settings); PreferenceScreen screen = getPreferenceScreen(); mAlwaysRunInBackground = @@ -228,6 +243,7 @@ public class SettingsActivity extends SyncthingActivity { @Override public void onDestroy() { super.onDestroy(); + mPreferences.unregisterOnSharedPreferenceChangeListener(this); if (mSyncthingService != null) mSyncthingService.unregisterOnApiChangeListener(this); } @@ -394,6 +410,13 @@ public class SettingsActivity extends SyncthingActivity { } } + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(Constants.PREF_NOTIFICATION_TYPE) || key.equals(Constants.PREF_FOREGROUND_SERVICE)) { + mNotificationHandler.updatePersistentNotification(mSyncthingService); + } + } + /** * Enables or disables {@link #mUseRoot} preference depending whether root is available. */ diff --git a/src/main/java/com/nutomic/syncthingandroid/receiver/BatteryReceiver.java b/src/main/java/com/nutomic/syncthingandroid/receiver/BatteryReceiver.java index 27536956..3c705dc3 100644 --- a/src/main/java/com/nutomic/syncthingandroid/receiver/BatteryReceiver.java +++ b/src/main/java/com/nutomic/syncthingandroid/receiver/BatteryReceiver.java @@ -29,9 +29,6 @@ public class BatteryReceiver extends BroadcastReceiver { Intent i = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED); i.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging); lbm.sendBroadcast(i); - - // Make sure service is running. - BootReceiver.startServiceCompat(context); } /** diff --git a/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java b/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java index e97eddee..7b9b2afb 100644 --- a/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java +++ b/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java @@ -27,7 +27,7 @@ public class BootReceiver extends BroadcastReceiver { * * https://stackoverflow.com/a/44505719/1837158 */ - public static void startServiceCompat(Context context) { + private static void startServiceCompat(Context context) { // This method is called from {@link DeviceStateHolder#DeviceStateHolder()}, make sure it // is only executed if run in background is enabled. if (!DeviceStateHolder.alwaysRunInBackground(context)) diff --git a/src/main/java/com/nutomic/syncthingandroid/receiver/NetworkReceiver.java b/src/main/java/com/nutomic/syncthingandroid/receiver/NetworkReceiver.java index dd359eda..91fc46ba 100644 --- a/src/main/java/com/nutomic/syncthingandroid/receiver/NetworkReceiver.java +++ b/src/main/java/com/nutomic/syncthingandroid/receiver/NetworkReceiver.java @@ -42,9 +42,6 @@ public class NetworkReceiver extends BroadcastReceiver { Intent intent = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED); intent.putExtra(DeviceStateHolder.EXTRA_IS_ALLOWED_NETWORK_CONNECTION, isAllowedConnection); lbm.sendBroadcast(intent); - - // Make sure service is running. - BootReceiver.startServiceCompat(context); } } diff --git a/src/main/java/com/nutomic/syncthingandroid/service/DeviceStateHolder.java b/src/main/java/com/nutomic/syncthingandroid/service/DeviceStateHolder.java index d877ff79..657eb6db 100644 --- a/src/main/java/com/nutomic/syncthingandroid/service/DeviceStateHolder.java +++ b/src/main/java/com/nutomic/syncthingandroid/service/DeviceStateHolder.java @@ -5,18 +5,24 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.net.ConnectivityManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.os.Build; +import android.os.PowerManager; import android.preference.PreferenceManager; +import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; +import com.google.common.collect.Lists; import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.receiver.BatteryReceiver; import com.nutomic.syncthingandroid.receiver.NetworkReceiver; import com.nutomic.syncthingandroid.receiver.PowerSaveModeChangedReceiver; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.inject.Inject; @@ -27,7 +33,7 @@ import javax.inject.Inject; * This information is actively read on instance creation, and then updated from intents * that are passed with {@link #ACTION_DEVICE_STATE_CHANGED}. */ -public class DeviceStateHolder { +public class DeviceStateHolder implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "DeviceStateHolder"; @@ -68,25 +74,87 @@ public class DeviceStateHolder { private final OnDeviceStateChangedListener mListener; @Inject SharedPreferences mPreferences; - private boolean mIsAllowedNetworkConnection = false; + private @Nullable NetworkReceiver mNetworkReceiver; + private @Nullable BatteryReceiver mBatteryReceiver; + private @Nullable BroadcastReceiver mPowerSaveModeChangedReceiver; + + private boolean mIsAllowedNetworkConnection; private String mWifiSsid; - private boolean mIsCharging = false; - private boolean mIsPowerSaving = true; + private boolean mIsCharging; + private boolean mIsPowerSaving; public DeviceStateHolder(Context context, OnDeviceStateChangedListener listener) { ((SyncthingApp) context.getApplicationContext()).component().inject(this); mContext = context; mBroadcastManager = LocalBroadcastManager.getInstance(mContext); mBroadcastManager.registerReceiver(mReceiver, new IntentFilter(ACTION_DEVICE_STATE_CHANGED)); + mPreferences.registerOnSharedPreferenceChangeListener(this); mListener = listener; - - BatteryReceiver.updateInitialChargingStatus(mContext); - NetworkReceiver.updateNetworkStatus(mContext); - PowerSaveModeChangedReceiver.updatePowerSavingState(mContext); + updateReceivers(); } public void shutdown() { mBroadcastManager.unregisterReceiver(mReceiver); + mPreferences.unregisterOnSharedPreferenceChangeListener(this); + + unregisterReceiver(mNetworkReceiver); + unregisterReceiver(mBatteryReceiver); + unregisterReceiver(mPowerSaveModeChangedReceiver); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + List watched = Lists.newArrayList(Constants.PREF_SYNC_ONLY_CHARGING, + Constants.PREF_SYNC_ONLY_WIFI, Constants.PREF_RESPECT_BATTERY_SAVING, + Constants.PREF_SYNC_ONLY_WIFI_SSIDS); + if (watched.contains(key)) { + updateReceivers(); + } + } + + private void updateReceivers() { + if (mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_WIFI, false)) { + Log.i(TAG, "Listening for network state changes"); + NetworkReceiver.updateNetworkStatus(mContext); + mNetworkReceiver = new NetworkReceiver(); + mContext.registerReceiver(mNetworkReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); + } else { + Log.i(TAG, "Stopped listening to network state changes"); + unregisterReceiver(mNetworkReceiver); + mNetworkReceiver = null; + } + + if (mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_CHARGING, false)) { + Log.i(TAG, "Listening to battery state changes"); + BatteryReceiver.updateInitialChargingStatus(mContext); + mBatteryReceiver = new BatteryReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_POWER_CONNECTED); + filter.addAction(Intent.ACTION_POWER_DISCONNECTED); + mContext.registerReceiver(mBatteryReceiver, filter); + } else { + Log.i(TAG, "Stopped listening to battery state changes"); + unregisterReceiver(mBatteryReceiver); + mBatteryReceiver = null; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && + mPreferences.getBoolean("respect_battery_saving", true)) { + Log.i(TAG, "Listening to power saving changes"); + PowerSaveModeChangedReceiver.updatePowerSavingState(mContext); + mPowerSaveModeChangedReceiver = new PowerSaveModeChangedReceiver(); + mContext.registerReceiver(mPowerSaveModeChangedReceiver, + new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); + } else { + Log.i(TAG, "Stopped listening to power saving changes"); + unregisterReceiver(mPowerSaveModeChangedReceiver); + mPowerSaveModeChangedReceiver = null; + } + } + + private void unregisterReceiver(BroadcastReceiver receiver) { + if (receiver != null) + mContext.unregisterReceiver(receiver); } private class DeviceStateChangedReceiver extends BroadcastReceiver { @@ -154,7 +222,6 @@ public class DeviceStateHolder { } } } - Log.d(TAG, "Wifi not connected"); return false; } diff --git a/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java b/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java index 9fc8c39c..8b3ee155 100644 --- a/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java +++ b/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java @@ -39,7 +39,7 @@ public class NotificationHandler { * Shows or hides the persistent notification based on running state and * {@link Constants#PREF_NOTIFICATION_TYPE}. */ - public void updatePersistentNotification(SyncthingService service, SyncthingService.State currentState) { + public void updatePersistentNotification(SyncthingService service) { String type = mPreferences.getString(Constants.PREF_NOTIFICATION_TYPE, "low_priority"); boolean foreground = mPreferences.getBoolean(Constants.PREF_FOREGROUND_SERVICE, false); @@ -57,8 +57,8 @@ public class NotificationHandler { type = "low_priority"; } - boolean syncthingRunning = currentState == SyncthingService.State.ACTIVE || - currentState == SyncthingService.State.STARTING; + boolean syncthingRunning = service.getCurrentState() == SyncthingService.State.ACTIVE || + service.getCurrentState() == SyncthingService.State.STARTING; if (foreground || (syncthingRunning && !type.equals("none"))) { // Launch FirstStartActivity instead of MainActivity so we can request permission if // necessary. diff --git a/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java b/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java index 12d0ced0..828b25af 100644 --- a/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java +++ b/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java @@ -1,15 +1,10 @@ package com.nutomic.syncthingandroid.service; import android.app.Service; -import android.content.BroadcastReceiver; import android.content.Intent; -import android.content.IntentFilter; import android.content.SharedPreferences; -import android.net.ConnectivityManager; import android.os.AsyncTask; -import android.os.Build; import android.os.IBinder; -import android.os.PowerManager; import android.support.annotation.Nullable; import android.util.Log; import android.widget.Toast; @@ -21,8 +16,6 @@ import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask; import com.nutomic.syncthingandroid.model.Folder; -import com.nutomic.syncthingandroid.receiver.NetworkReceiver; -import com.nutomic.syncthingandroid.receiver.PowerSaveModeChangedReceiver; import com.nutomic.syncthingandroid.util.ConfigXml; import com.nutomic.syncthingandroid.util.FolderObserver; @@ -38,8 +31,7 @@ import javax.inject.Inject; /** * Holds the native syncthing instance and provides an API to access it. */ -public class SyncthingService extends Service implements - SharedPreferences.OnSharedPreferenceChangeListener { +public class SyncthingService extends Service { private static final String TAG = "SyncthingService"; @@ -96,8 +88,6 @@ public class SyncthingService extends Service implements private final LinkedList mObservers = new LinkedList<>(); private final HashSet mOnApiChangeListeners = new HashSet<>(); private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this); - private final NetworkReceiver mNetworkReceiver = new NetworkReceiver(); - private final BroadcastReceiver mPowerSaveModeChangedReceiver = new PowerSaveModeChangedReceiver(); @Inject NotificationHandler mNotificationHandler; @Inject SharedPreferences mPreferences; @@ -167,16 +157,6 @@ public class SyncthingService extends Service implements } } - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals(Constants.PREF_NOTIFICATION_TYPE) || key.equals(Constants.PREF_FOREGROUND_SERVICE)) - mNotificationHandler.updatePersistentNotification(this, mCurrentState); - else if (key.equals(Constants.PREF_SYNC_ONLY_CHARGING) || key.equals(Constants.PREF_SYNC_ONLY_WIFI) - || key.equals(Constants.PREF_SYNC_ONLY_WIFI_SSIDS) || key.equals(Constants.PREF_RESPECT_BATTERY_SAVING)) { - updateState(); - } - } - /** * Starts the native binary. */ @@ -187,20 +167,8 @@ public class SyncthingService extends Service implements ((SyncthingApp) getApplication()).component().inject(this); mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this, this::updateState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - registerReceiver(mPowerSaveModeChangedReceiver, - new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); - } - // Android 7 ignores network receiver that was set in manifest - // https://github.com/syncthing/syncthing-android/issues/783 - // https://developer.android.com/about/versions/nougat/android-7.0-changes.html#bg-opt - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - registerReceiver(mNetworkReceiver, - new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - } updateState(); - mPreferences.registerOnSharedPreferenceChangeListener(this); - mNotificationHandler.updatePersistentNotification(this, mCurrentState); + mNotificationHandler.updatePersistentNotification(this); } /** @@ -278,7 +246,6 @@ public class SyncthingService extends Service implements */ @Override public void onDestroy() { - synchronized (mStateLock) { if (mCurrentState == State.INIT || mCurrentState == State.STARTING) { Log.i(TAG, "Delay shutting down service until initialisation of Syncthing finished"); @@ -290,12 +257,7 @@ public class SyncthingService extends Service implements } } - mPreferences.unregisterOnSharedPreferenceChangeListener(this); mDeviceStateHolder.shutdown(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - unregisterReceiver(mPowerSaveModeChangedReceiver); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - unregisterReceiver(mNetworkReceiver); } /** @@ -399,7 +361,7 @@ public class SyncthingService extends Service implements */ private void onApiChange(State newState) { mCurrentState = newState; - mNotificationHandler.updatePersistentNotification(this, mCurrentState); + mNotificationHandler.updatePersistentNotification(this); for (Iterator i = mOnApiChangeListeners.iterator(); i.hasNext(); ) { OnApiChangeListener listener = i.next();