Improved boot

pull/152/head
M66B 6 years ago
parent fe6fa7a2d5
commit d32b55d2c5

@ -58,7 +58,8 @@ public class ActivityMain extends AppCompatActivity implements FragmentManager.O
startActivity(new Intent(ActivityMain.this, ActivitySetup.class)); startActivity(new Intent(ActivityMain.this, ActivitySetup.class));
else { else {
startActivity(new Intent(ActivityMain.this, ActivityView.class)); startActivity(new Intent(ActivityMain.this, ActivityView.class));
ServiceSynchronize.init(ActivityMain.this, false); ServiceSynchronize.boot(ActivityMain.this);
ServiceSend.boot(ActivityMain.this);
} }
finish(); finish();
} }

@ -197,7 +197,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
if (checked) { if (checked) {
if (Helper.isPro(getContext())) { if (Helper.isPro(getContext())) {
prefs.edit().putBoolean("schedule", true).apply(); prefs.edit().putBoolean("schedule", true).apply();
ServiceSynchronize.schedule(getContext()); ServiceSynchronize.reschedule(getContext());
} else { } else {
swSchedule.setChecked(false); swSchedule.setChecked(false);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
@ -645,7 +645,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
editor.putBoolean("schedule", true); editor.putBoolean("schedule", true);
editor.apply(); editor.apply();
ServiceSynchronize.schedule(getContext()); ServiceSynchronize.reschedule(getContext());
} }
} }

@ -23,43 +23,14 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import java.util.List;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
public class ReceiverAutostart extends BroadcastReceiver { public class ReceiverAutostart extends BroadcastReceiver {
@Override @Override
public void onReceive(final Context context, Intent intent) { public void onReceive(final Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) || if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) ||
Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) { Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) {
EntityLog.log(context, intent.getAction()); Log.i("Received " + intent);
ServiceSynchronize.boot(context);
ServiceSynchronize.init(context, true); ServiceSend.boot(context);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
DB db = DB.getInstance(context);
List<EntityMessage> messages = db.message().getSnoozed();
for (EntityMessage message : messages)
EntityMessage.snooze(context, message.id, message.ui_snoozed);
EntityFolder outbox = db.folder().getOutbox();
if (outbox == null)
return;
if (db.operation().getOperations(outbox.id).size() > 0)
ServiceSend.start(context);
} catch (Throwable ex) {
Log.e(ex);
}
}
});
thread.setPriority(THREAD_PRIORITY_BACKGROUND);
thread.start();
} }
} }
} }

@ -60,6 +60,8 @@ import androidx.lifecycle.Observer;
public class ServiceSend extends LifecycleService { public class ServiceSend extends LifecycleService {
private int lastUnsent = 0; private int lastUnsent = 0;
private static boolean booted = false;
private static final int IDENTITY_ERROR_AFTER = 30; // minutes private static final int IDENTITY_ERROR_AFTER = 30; // minutes
@Override @Override
@ -413,6 +415,27 @@ public class ServiceSend extends LifecycleService {
} }
} }
static void boot(final Context context) {
if (!booted) {
booted = true;
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
DB db = DB.getInstance(context);
EntityFolder outbox = db.folder().getOutbox();
if (outbox != null && db.operation().getOperations(outbox.id).size() > 0)
start(context);
} catch (Throwable ex) {
Log.e(ex);
}
}
});
thread.start();
}
}
static void start(Context context) { static void start(Context context) {
context.startService(new Intent(context, ServiceSend.class)); context.startService(new Intent(context, ServiceSend.class));
} }

@ -89,6 +89,8 @@ public class ServiceSynchronize extends LifecycleService {
private TupleAccountStats lastStats = new TupleAccountStats(); private TupleAccountStats lastStats = new TupleAccountStats();
private ServiceManager serviceManager = new ServiceManager(); private ServiceManager serviceManager = new ServiceManager();
private static boolean booted = false;
private static final int CONNECT_BACKOFF_START = 8; // seconds private static final int CONNECT_BACKOFF_START = 8; // seconds
private static final int CONNECT_BACKOFF_MAX = 64; // seconds (totally 2 minutes) private static final int CONNECT_BACKOFF_MAX = 64; // seconds (totally 2 minutes)
private static final int CONNECT_BACKOFF_AlARM = 15; // minutes private static final int CONNECT_BACKOFF_AlARM = 15; // minutes
@ -97,7 +99,7 @@ public class ServiceSynchronize extends LifecycleService {
private static final int BACKOFF_ERROR_AFTER = 16; // seconds private static final int BACKOFF_ERROR_AFTER = 16; // seconds
private static final long STOP_DELAY = 5000L; // milliseconds private static final long STOP_DELAY = 5000L; // milliseconds
static final int PI_SCHEDULE = 1; static final int PI_ALARM = 1;
@Override @Override
public void onCreate() { public void onCreate() {
@ -165,15 +167,13 @@ public class ServiceSynchronize extends LifecycleService {
if (action != null) if (action != null)
try { try {
final String[] parts = action.split(":"); switch (action) {
switch (parts[0]) {
case "init": case "init":
// Network events will manage the service serviceManager.service_init();
serviceManager.service_init(intent.getBooleanExtra("boot", false));
break; break;
case "schedule": case "alarm":
serviceManager.service_schedule(); serviceManager.service_alarm();
break; break;
case "reload": case "reload":
@ -941,19 +941,14 @@ public class ServiceSynchronize extends LifecycleService {
return (db.account().getSynchronizingAccounts(false).size() > 0); return (db.account().getSynchronizingAccounts(false).size() > 0);
} }
private void service_init(boolean boot) { private void service_init() {
EntityLog.log(ServiceSynchronize.this, "Service init boot=" + boot); EntityLog.log(ServiceSynchronize.this, "Service init");
// Network events will manage the service
if (boot)
next_schedule();
if (!isEnabled())
stopSelf();
} }
private void service_schedule() { private void service_alarm() {
next_schedule(); schedule(ServiceSynchronize.this);
service_reload("schedule"); service_reload("alarm");
} }
private void service_reload(String reason) { private void service_reload(String reason) {
@ -1071,61 +1066,6 @@ public class ServiceSynchronize extends LifecycleService {
state = null; state = null;
} }
private void next_schedule() {
Intent schedule = new Intent(ServiceSynchronize.this, ServiceSynchronize.class);
schedule.setAction("schedule");
PendingIntent piSchedule = PendingIntent.getService(
ServiceSynchronize.this, PI_SCHEDULE, schedule, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.cancel(piSchedule);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSynchronize.this);
if (!prefs.getBoolean("schedule", false))
return;
int minuteStart = prefs.getInt("schedule_start", 0);
int minuteEnd = prefs.getInt("schedule_end", 0);
if (minuteEnd <= minuteStart)
minuteEnd += 24 * 60;
Calendar calStart = Calendar.getInstance();
calStart.set(Calendar.HOUR_OF_DAY, minuteStart / 60);
calStart.set(Calendar.MINUTE, minuteStart % 60);
calStart.set(Calendar.SECOND, 0);
calStart.set(Calendar.MILLISECOND, 0);
Calendar calEnd = Calendar.getInstance();
calEnd.set(Calendar.HOUR_OF_DAY, minuteEnd / 60);
calEnd.set(Calendar.MINUTE, minuteEnd % 60);
calEnd.set(Calendar.SECOND, 0);
calEnd.set(Calendar.MILLISECOND, 0);
long now = new Date().getTime();
if (now > calEnd.getTimeInMillis()) {
calStart.set(Calendar.DAY_OF_MONTH, calStart.get(Calendar.DAY_OF_MONTH) + 1);
calEnd.set(Calendar.DAY_OF_MONTH, calEnd.get(Calendar.DAY_OF_MONTH) + 1);
}
long start = calStart.getTimeInMillis();
long end = calEnd.getTimeInMillis();
long next = (now < start ? start : end);
EntityLog.log(ServiceSynchronize.this, "Schedule now=" + new Date(now));
EntityLog.log(ServiceSynchronize.this, "Schedule start=" + new Date(start));
EntityLog.log(ServiceSynchronize.this, "Schedule end=" + new Date(end));
EntityLog.log(ServiceSynchronize.this, "Schedule next=" + new Date(next));
boolean enabled = (now >= start && now < end);
prefs.edit().putBoolean("enabled", enabled).apply();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, next, piSchedule);
else
am.set(AlarmManager.RTC_WAKEUP, next, piSchedule);
}
private void queue_reload(final boolean start, final String reason) { private void queue_reload(final boolean start, final String reason) {
final boolean doStop = started; final boolean doStop = started;
final boolean doStart = (start && isEnabled() && suitableNetwork()); final boolean doStart = (start && isEnabled() && suitableNetwork());
@ -1192,20 +1132,103 @@ public class ServiceSynchronize extends LifecycleService {
} }
} }
public static void init(Context context, boolean boot) { private static void schedule(Context context) {
ContextCompat.startForegroundService(context, Intent alarm = new Intent(context, ServiceSynchronize.class);
new Intent(context, ServiceSynchronize.class) alarm.setAction("alarm");
.setAction("init") PendingIntent piAlarm = PendingIntent.getService(context, PI_ALARM, alarm, PendingIntent.FLAG_UPDATE_CURRENT);
.putExtra("boot", boot));
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(piAlarm);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (!prefs.getBoolean("schedule", false))
return;
int minuteStart = prefs.getInt("schedule_start", 0);
int minuteEnd = prefs.getInt("schedule_end", 0);
if (minuteEnd <= minuteStart)
minuteEnd += 24 * 60;
Calendar calStart = Calendar.getInstance();
calStart.set(Calendar.HOUR_OF_DAY, minuteStart / 60);
calStart.set(Calendar.MINUTE, minuteStart % 60);
calStart.set(Calendar.SECOND, 0);
calStart.set(Calendar.MILLISECOND, 0);
Calendar calEnd = Calendar.getInstance();
calEnd.set(Calendar.HOUR_OF_DAY, minuteEnd / 60);
calEnd.set(Calendar.MINUTE, minuteEnd % 60);
calEnd.set(Calendar.SECOND, 0);
calEnd.set(Calendar.MILLISECOND, 0);
long now = new Date().getTime();
if (now > calEnd.getTimeInMillis()) {
calStart.set(Calendar.DAY_OF_MONTH, calStart.get(Calendar.DAY_OF_MONTH) + 1);
calEnd.set(Calendar.DAY_OF_MONTH, calEnd.get(Calendar.DAY_OF_MONTH) + 1);
}
long start = calStart.getTimeInMillis();
long end = calEnd.getTimeInMillis();
long next = (now < start ? start : end);
Log.i("Schedule now=" + new Date(now));
Log.i("Schedule start=" + new Date(start));
Log.i("Schedule end=" + new Date(end));
Log.i("Schedule next=" + new Date(next));
boolean enabled = (now >= start && now < end);
prefs.edit().putBoolean("enabled", enabled).apply();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, next, piAlarm);
else
am.set(AlarmManager.RTC_WAKEUP, next, piAlarm);
}
static void boot(final Context context) {
if (!booted) {
booted = true;
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
DB db = DB.getInstance(context);
// Restore snooze timers
for (EntityMessage message : db.message().getSnoozed())
EntityMessage.snooze(context, message.id, message.ui_snoozed);
// Restore schedule
schedule(context);
// Conditionally init service
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean enabled = prefs.getBoolean("enabled", true);
int accounts = db.account().getSynchronizingAccounts(false).size();
if (enabled && accounts > 0)
ContextCompat.startForegroundService(context,
new Intent(context, ServiceSynchronize.class)
.setAction("init"));
} catch (Throwable ex) {
Log.e(ex);
}
}
});
thread.start();
}
} }
public static void schedule(Context context) { static void reschedule(Context context) {
ContextCompat.startForegroundService(context, ContextCompat.startForegroundService(context,
new Intent(context, ServiceSynchronize.class) new Intent(context, ServiceSynchronize.class)
.setAction("schedule")); .setAction("alarm"));
} }
public static void reload(Context context, String reason) { static void reload(Context context, String reason) {
ContextCompat.startForegroundService(context, ContextCompat.startForegroundService(context,
new Intent(context, ServiceSynchronize.class) new Intent(context, ServiceSynchronize.class)
.setAction("reload") .setAction("reload")

Loading…
Cancel
Save