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 c6c3c7f25..089cc9e09 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java @@ -8,6 +8,7 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SyncStatusObserver; import android.content.res.Resources; +import android.hardware.display.DisplayManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; @@ -17,6 +18,7 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; +import android.view.Display; import androidx.annotation.Nullable; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import android.os.SystemClock; @@ -155,6 +157,12 @@ public class RunConditionMonitor { ReceiverManager.registerReceiver(mContext, new PowerSaveModeChangedReceiver(), new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); + + // ScreenStateReceiver + IntentFilter screenStateFilter = new IntentFilter(); + screenStateFilter.addAction(Intent.ACTION_SCREEN_ON); + screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF); + ReceiverManager.registerReceiver(mContext, new ScreenStateReceiver(), screenStateFilter); // SyncStatusObserver to monitor android's "AutoSync" quick toggle. mSyncStatusObserverHandle = ContentResolver.addStatusChangeListener( @@ -262,6 +270,18 @@ public class RunConditionMonitor { } } } + + private class ScreenStateReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_SCREEN_ON.equals(intent.getAction()) + || Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { + LogV("ScreenStateReceiver: onReceive"); + SystemClock.sleep(5000); + updateShouldRunDecision(); + } + } + } private class SyncTriggerReceiver extends BroadcastReceiver { @Override @@ -556,6 +576,15 @@ public class RunConditionMonitor { boolean prefRespectMasterSync = mPreferences.getBoolean(Constants.PREF_RESPECT_MASTER_SYNC, false); boolean prefRunInFlightMode = mPreferences.getBoolean(Constants.PREF_RUN_IN_FLIGHT_MODE, false); boolean prefRunOnTimeSchedule = mPreferences.getBoolean(Constants.PREF_RUN_ON_TIME_SCHEDULE, false); + boolean prefRunOnTimeScheduleOnlyWhenScreenOff = true; // TODO: add a checkbox in the app preferences + + boolean isScreenOn = isDeviceInteractive(); + /*DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); + for (Display display : dm.getDisplays()) { + if (display.getState() != Display.STATE_OFF) { + isScreenOn = true; + } + }*/ // PREF_BTNSTATE_FORCE_START_STOP switch (prefBtnStateForceStartStop) { @@ -573,18 +602,26 @@ public class RunConditionMonitor { // set mTimeConditionMatch to true if the last run was more than WAIT_FOR_NEXT_SYNC_DELAY_SECS ago if (SystemClock.elapsedRealtime() - mPreferences.getLong(Constants.PREF_LAST_RUN_TIME,0) > Integer.parseInt(mPreferences.getString(Constants.PREF_SLEEP_INTERVAL_MINUTES,"60")) * 60 * 1000) mTimeConditionMatch = true; - if (prefRunOnTimeSchedule && !mTimeConditionMatch) { - // Currently, we aren't within a "SyncthingNative should run" time frame. - LogV("decideShouldRun: PREF_RUN_ON_TIME_SCHEDULE && !mTimeConditionMatch"); - int minutes = (int) (SystemClock.elapsedRealtime() - mPreferences.getLong(Constants.PREF_LAST_RUN_TIME,0))/(60*1000); - String minutesText; - if (minutes == 0) - minutesText = res.getString(R.string.reason_not_within_time_frame_0_min); - else - minutesText = String.format(res.getQuantityString(R.plurals.reason_not_within_time_frame_minutes,minutes),minutes); - mRunDecisionExplanation = String.format(res.getString(R.string.reason_not_within_time_frame_2),minutesText); - return false; + if (prefRunOnTimeSchedule && !mTimeConditionMatch && (!prefRunOnTimeScheduleOnlyWhenScreenOff || !isScreenOn)) { + // Currently, we aren't within a "SyncthingNative should run" time frame. + LogV("decideShouldRun: PREF_RUN_ON_TIME_SCHEDULE && !mTimeConditionMatch"); + int minutes = (int) (SystemClock.elapsedRealtime() - mPreferences.getLong(Constants.PREF_LAST_RUN_TIME,0))/(60*1000); + String minutesText; + if (minutes == 0) + minutesText = res.getString(R.string.reason_not_within_time_frame_0_min); + else + minutesText = String.format(res.getQuantityString(R.plurals.reason_not_within_time_frame_minutes,minutes),minutes); + mRunDecisionExplanation = String.format(res.getString(R.string.reason_not_within_time_frame_2),minutesText); + if (prefRunOnTimeScheduleOnlyWhenScreenOff) { + LogV("decideShouldRun: screen is off"); + mRunDecisionExplanation += " and the screen is off"; + } + return false; } + + if (prefRunOnTimeSchedule && prefRunOnTimeScheduleOnlyWhenScreenOff || isScreenOn) { + mRunDecisionExplanation += "The schedule is ignored because the screen is on\n"; + } // PREF_POWER_SOURCE SyncConditionResult scr = checkConditionSyncOnPowerSource(Constants.PREF_POWER_SOURCE); @@ -742,6 +779,15 @@ public class RunConditionMonitor { } return powerManager.isPowerSaveMode(); } + + private boolean isDeviceInteractive() { + PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + if (powerManager == null) { + Log.e(TAG, "getSystemService(POWER_SERVICE) unexpectedly returned NULL."); + return false; + } + return powerManager.isInteractive(); + } private boolean isFlightMode() { ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);