Merge pull request #3763 from ojiofong/oji_mail_sync
Change mail sync to work with background execution limits
This commit is contained in:
commit
2f8778be33
28 changed files with 523 additions and 961 deletions
|
@ -22,6 +22,7 @@ dependencies {
|
|||
implementation "com.squareup.moshi:moshi:1.2.0"
|
||||
implementation "com.jakewharton.timber:timber:${versions.timber}"
|
||||
implementation "org.apache.james:apache-mime4j-core:${versions.mime4j}"
|
||||
implementation 'com.evernote:android-job:1.2.6'
|
||||
|
||||
testImplementation project(':mail:testing')
|
||||
testImplementation project(":backend:imap")
|
||||
|
|
|
@ -104,6 +104,8 @@ public class Account implements BaseAccount, StoreConfig {
|
|||
public static final long NO_OPENPGP_KEY = 0;
|
||||
public static final int UNASSIGNED_ACCOUNT_NUMBER = -1;
|
||||
|
||||
public static final int INTERVAL_MINUTES_NEVER = -1;
|
||||
|
||||
private DeletePolicy deletePolicy = DeletePolicy.NEVER;
|
||||
|
||||
private final String accountUuid;
|
||||
|
|
|
@ -24,7 +24,7 @@ class AccountPreferenceSerializer(
|
|||
transportUri = Base64.decode(storage.getString("$accountUuid.transportUri", null))
|
||||
description = storage.getString("$accountUuid.description", null)
|
||||
alwaysBcc = storage.getString("$accountUuid.alwaysBcc", alwaysBcc)
|
||||
automaticCheckIntervalMinutes = storage.getInt("$accountUuid.automaticCheckIntervalMinutes", -1)
|
||||
automaticCheckIntervalMinutes = storage.getInt("$accountUuid.automaticCheckIntervalMinutes", Account.INTERVAL_MINUTES_NEVER)
|
||||
idleRefreshMinutes = storage.getInt("$accountUuid.idleRefreshMinutes", 24)
|
||||
isPushPollOnConnect = storage.getBoolean("$accountUuid.pushPollOnConnect", true)
|
||||
displayCount = storage.getInt("$accountUuid.displayCount", K9.DEFAULT_VISIBLE_LIMIT)
|
||||
|
@ -499,7 +499,7 @@ class AccountPreferenceSerializer(
|
|||
fun loadDefaults(account: Account) {
|
||||
with (account) {
|
||||
localStorageProviderId = storageManager.defaultProviderId
|
||||
automaticCheckIntervalMinutes = -1
|
||||
automaticCheckIntervalMinutes = Account.INTERVAL_MINUTES_NEVER
|
||||
idleRefreshMinutes = 24
|
||||
isPushPollOnConnect = true
|
||||
displayCount = K9.DEFAULT_VISIBLE_LIMIT
|
||||
|
|
|
@ -11,6 +11,8 @@ import android.os.StrictMode
|
|||
import com.fsck.k9.autocrypt.autocryptModule
|
||||
import com.fsck.k9.controller.controllerModule
|
||||
import com.fsck.k9.crypto.openPgpModule
|
||||
import com.fsck.k9.job.K9JobManager
|
||||
import com.fsck.k9.job.jobModule
|
||||
import com.fsck.k9.mail.internet.BinaryTempFileBody
|
||||
import com.fsck.k9.mail.ssl.LocalKeyStore
|
||||
import com.fsck.k9.mailstore.mailStoreModule
|
||||
|
@ -18,10 +20,8 @@ import com.fsck.k9.message.extractors.extractorModule
|
|||
import com.fsck.k9.message.html.htmlModule
|
||||
import com.fsck.k9.message.quote.quoteModule
|
||||
import com.fsck.k9.notification.coreNotificationModule
|
||||
import com.fsck.k9.power.DeviceIdleManager
|
||||
import com.fsck.k9.search.searchModule
|
||||
import com.fsck.k9.service.BootReceiver
|
||||
import com.fsck.k9.service.MailService
|
||||
import com.fsck.k9.service.ShutdownReceiver
|
||||
import com.fsck.k9.service.StorageGoneReceiver
|
||||
import org.koin.standalone.KoinComponent
|
||||
|
@ -31,8 +31,9 @@ import java.util.concurrent.SynchronousQueue
|
|||
|
||||
object Core : KoinComponent {
|
||||
private val appConfig: AppConfig by inject()
|
||||
private val jobManager: K9JobManager by inject()
|
||||
|
||||
private val componentsToDisable = listOf(BootReceiver::class.java, MailService::class.java)
|
||||
private val componentsToDisable = listOf(BootReceiver::class.java)
|
||||
|
||||
@JvmStatic
|
||||
val coreModules = listOf(
|
||||
|
@ -45,7 +46,8 @@ object Core : KoinComponent {
|
|||
htmlModule,
|
||||
quoteModule,
|
||||
coreNotificationModule,
|
||||
controllerModule
|
||||
controllerModule,
|
||||
jobModule
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -81,33 +83,12 @@ object Core : KoinComponent {
|
|||
val acctLength = Preferences.getPreferences(appContext).availableAccounts.size
|
||||
val enable = acctLength > 0
|
||||
|
||||
setServicesEnabled(appContext, enable, null)
|
||||
|
||||
updateDeviceIdleReceiver(appContext, enable)
|
||||
setServicesEnabled(appContext, enable)
|
||||
}
|
||||
|
||||
|
||||
private fun updateDeviceIdleReceiver(context: Context, enable: Boolean) {
|
||||
val deviceIdleManager = DeviceIdleManager.getInstance(context)
|
||||
if (enable) {
|
||||
deviceIdleManager.registerReceiver()
|
||||
} else {
|
||||
deviceIdleManager.unregisterReceiver()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setServicesEnabled(context: Context, enabled: Boolean, wakeLockId: Int?) {
|
||||
private fun setServicesEnabled(context: Context, enabled: Boolean) {
|
||||
val pm = context.packageManager
|
||||
|
||||
if (!enabled && pm.getComponentEnabledSetting(ComponentName(context, MailService::class.java)) ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
||||
/*
|
||||
* If no accounts now exist but the service is still enabled we're about to disable it
|
||||
* so we'll reschedule to kill off any existing alarms.
|
||||
*/
|
||||
MailService.actionReset(context, wakeLockId)
|
||||
}
|
||||
|
||||
val classes = componentsToDisable + appConfig.componentsToDisable
|
||||
for (clazz in classes) {
|
||||
val alreadyEnabled = pm.getComponentEnabledSetting(ComponentName(context, clazz)) ==
|
||||
|
@ -124,14 +105,10 @@ object Core : KoinComponent {
|
|||
}
|
||||
}
|
||||
|
||||
if (enabled && pm.getComponentEnabledSetting(ComponentName(context, MailService::class.java)) ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
||||
/*
|
||||
* And now if accounts do exist then we've just enabled the service and we want to
|
||||
* schedule alarms for the new accounts.
|
||||
*/
|
||||
MailService.actionReset(context, wakeLockId)
|
||||
if (enabled) {
|
||||
jobManager.scheduleAllMailJobs()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
@ -2403,6 +2404,25 @@ public class MessagingController {
|
|||
context.startActivity(chooserIntent);
|
||||
}
|
||||
|
||||
public void checkMailBlocking(Account account) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
checkMail(context, account, true, false, new SimpleMessagingListener() {
|
||||
@Override
|
||||
public void checkMailFinished(Context context, Account account) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
Timber.v("checkMailBlocking(%s) about to await latch release", account.getDescription());
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
Timber.v("checkMailBlocking(%s) got latch release", account.getDescription());
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "Interrupted while awaiting latch release");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks mail for one or multiple accounts. If account is null all accounts
|
||||
* are checked.
|
||||
|
@ -2862,6 +2882,10 @@ public class MessagingController {
|
|||
return pushers.values();
|
||||
}
|
||||
|
||||
public Pusher getPusher(Account account) {
|
||||
return pushers.get(account);
|
||||
}
|
||||
|
||||
public boolean setupPushing(final Account account) {
|
||||
try {
|
||||
Pusher previousPusher = pushers.remove(account);
|
||||
|
|
19
app/core/src/main/java/com/fsck/k9/job/K9JobCreator.kt
Normal file
19
app/core/src/main/java/com/fsck/k9/job/K9JobCreator.kt
Normal file
|
@ -0,0 +1,19 @@
|
|||
package com.fsck.k9.job
|
||||
|
||||
import com.evernote.android.job.Job
|
||||
import com.evernote.android.job.JobCreator
|
||||
|
||||
class K9JobCreator(
|
||||
private val mailSyncJobManager: MailSyncJobManager,
|
||||
private val pusherRefreshJobManager: PusherRefreshJobManager
|
||||
) : JobCreator {
|
||||
|
||||
override fun create(tag: String): Job? {
|
||||
return when (tag) {
|
||||
MailSyncJob.TAG -> mailSyncJobManager.getJob()
|
||||
PusherRefreshJob.TAG -> pusherRefreshJobManager.getJob()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
58
app/core/src/main/java/com/fsck/k9/job/K9JobManager.kt
Normal file
58
app/core/src/main/java/com/fsck/k9/job/K9JobManager.kt
Normal file
|
@ -0,0 +1,58 @@
|
|||
package com.fsck.k9.job
|
||||
|
||||
import com.evernote.android.job.JobManager
|
||||
import com.fsck.k9.Preferences
|
||||
import timber.log.Timber
|
||||
|
||||
class K9JobManager(
|
||||
jobCreator: K9JobCreator,
|
||||
private val jobManager: JobManager,
|
||||
private val preferences: Preferences,
|
||||
private val mailSyncJobManager: MailSyncJobManager,
|
||||
private val pusherRefreshJobManager: PusherRefreshJobManager
|
||||
) {
|
||||
|
||||
// It's recommended to initialize JobManager in Application onCreate()
|
||||
// I.e. by calling JobManager.create(this).addJobCreator(jobCreator)
|
||||
// Using this DI approach should provide a similar initialization
|
||||
init {
|
||||
jobManager.addJobCreator(jobCreator)
|
||||
}
|
||||
|
||||
fun scheduleAllMailJobs() {
|
||||
Timber.v("scheduling all jobs")
|
||||
scheduleMailSync()
|
||||
schedulePusherRefresh()
|
||||
}
|
||||
|
||||
fun scheduleMailSync() {
|
||||
cancelAllMailSyncJobs()
|
||||
|
||||
preferences.availableAccounts?.forEach { account ->
|
||||
mailSyncJobManager.scheduleJob(account)
|
||||
}
|
||||
}
|
||||
|
||||
fun schedulePusherRefresh() {
|
||||
cancelAllPusherRefreshJobs()
|
||||
|
||||
preferences.availableAccounts?.forEach { account ->
|
||||
pusherRefreshJobManager.scheduleJob(account)
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelAllMailSyncJobs() {
|
||||
Timber.v("canceling mail sync job")
|
||||
jobManager.cancelAllForTag(MailSyncJob.TAG)
|
||||
}
|
||||
|
||||
fun cancelAllPusherRefreshJobs() {
|
||||
Timber.v("canceling pusher refresh job")
|
||||
jobManager.cancelAllForTag(PusherRefreshJob.TAG)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_KEY_ACCOUNT_UUID = "param_key_account_uuid"
|
||||
}
|
||||
|
||||
}
|
12
app/core/src/main/java/com/fsck/k9/job/KoinModule.kt
Normal file
12
app/core/src/main/java/com/fsck/k9/job/KoinModule.kt
Normal file
|
@ -0,0 +1,12 @@
|
|||
package com.fsck.k9.job
|
||||
|
||||
import com.evernote.android.job.JobManager
|
||||
import org.koin.dsl.module.applicationContext
|
||||
|
||||
val jobModule = applicationContext {
|
||||
bean { JobManager.create(get()) as JobManager }
|
||||
bean { K9JobManager(get(), get(), get(), get(), get()) }
|
||||
bean { K9JobCreator(get(), get()) }
|
||||
factory { MailSyncJobManager(get(), get()) }
|
||||
factory { PusherRefreshJobManager(get(), get(), get()) }
|
||||
}
|
30
app/core/src/main/java/com/fsck/k9/job/MailSyncJob.kt
Normal file
30
app/core/src/main/java/com/fsck/k9/job/MailSyncJob.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
package com.fsck.k9.job
|
||||
|
||||
import com.evernote.android.job.Job
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.controller.MessagingController
|
||||
|
||||
|
||||
class MailSyncJob(
|
||||
private val messagingController: MessagingController,
|
||||
private val preferences: Preferences
|
||||
) : Job() {
|
||||
|
||||
override fun onRunJob(params: Params): Result {
|
||||
|
||||
params.extras.getString(K9JobManager.EXTRA_KEY_ACCOUNT_UUID, null)
|
||||
?.let { accountUuid ->
|
||||
|
||||
preferences.getAccount(accountUuid)?.let { account ->
|
||||
messagingController.checkMailBlocking(account)
|
||||
}
|
||||
}
|
||||
|
||||
return Result.SUCCESS
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "MailSyncJob"
|
||||
}
|
||||
|
||||
}
|
48
app/core/src/main/java/com/fsck/k9/job/MailSyncJobManager.kt
Normal file
48
app/core/src/main/java/com/fsck/k9/job/MailSyncJobManager.kt
Normal file
|
@ -0,0 +1,48 @@
|
|||
package com.fsck.k9.job
|
||||
|
||||
import com.evernote.android.job.JobRequest
|
||||
import com.evernote.android.job.util.support.PersistableBundleCompat
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.controller.MessagingController
|
||||
import timber.log.Timber
|
||||
|
||||
class MailSyncJobManager(
|
||||
private val messagingController: MessagingController,
|
||||
private val preferences: Preferences
|
||||
) {
|
||||
|
||||
fun getJob() = MailSyncJob(messagingController, preferences)
|
||||
|
||||
fun scheduleJob(account: Account) {
|
||||
|
||||
getSyncIntervalInMillisecondsIfEnabled(account)?.let { syncInterval ->
|
||||
|
||||
Timber.v("scheduling mail sync job for ${account.description}")
|
||||
|
||||
val extras = PersistableBundleCompat()
|
||||
extras.putString(K9JobManager.EXTRA_KEY_ACCOUNT_UUID, account.uuid)
|
||||
|
||||
val jobRequest = JobRequest.Builder(MailSyncJob.TAG)
|
||||
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
|
||||
.setRequiresStorageNotLow(true)
|
||||
.setPeriodic(syncInterval)
|
||||
.setExtras(extras)
|
||||
.setRequirementsEnforced(true)
|
||||
.build()
|
||||
|
||||
jobRequest.schedule()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSyncIntervalInMillisecondsIfEnabled(account: Account): Long? {
|
||||
val intervalMinutes = account.automaticCheckIntervalMinutes
|
||||
|
||||
if (intervalMinutes <= Account.INTERVAL_MINUTES_NEVER) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (intervalMinutes * 60 * 1000).toLong()
|
||||
}
|
||||
|
||||
}
|
45
app/core/src/main/java/com/fsck/k9/job/PusherRefreshJob.kt
Normal file
45
app/core/src/main/java/com/fsck/k9/job/PusherRefreshJob.kt
Normal file
|
@ -0,0 +1,45 @@
|
|||
package com.fsck.k9.job
|
||||
|
||||
import com.evernote.android.job.Job
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.controller.MessagingController
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
class PusherRefreshJob(
|
||||
private val messagingController: MessagingController,
|
||||
private val preferences: Preferences
|
||||
) : Job() {
|
||||
|
||||
override fun onRunJob(params: Params): Result {
|
||||
|
||||
params.extras.getString(K9JobManager.EXTRA_KEY_ACCOUNT_UUID, null)
|
||||
?.let { accountUuid ->
|
||||
|
||||
preferences.getAccount(accountUuid)?.let { account ->
|
||||
try {
|
||||
|
||||
// Refresh pushers
|
||||
Timber.i("Refreshing pusher for ${account.description}")
|
||||
messagingController.getPusher(account)?.refresh()
|
||||
|
||||
// Whenever we refresh our pushers, send any unsent messages
|
||||
Timber.d("trying to send mail in all folders!")
|
||||
messagingController.sendPendingMessages(null)
|
||||
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Exception while refreshing pushers")
|
||||
return Result.RESCHEDULE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.SUCCESS
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "PusherRefreshJob"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.fsck.k9.job
|
||||
|
||||
import android.content.Context
|
||||
import com.evernote.android.job.JobRequest
|
||||
import com.evernote.android.job.util.support.PersistableBundleCompat
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.controller.MessagingController
|
||||
import timber.log.Timber
|
||||
|
||||
class PusherRefreshJobManager(
|
||||
private val context: Context,
|
||||
private val messagingController: MessagingController,
|
||||
private val preferences: Preferences
|
||||
) {
|
||||
|
||||
fun getJob() = PusherRefreshJob(messagingController, preferences)
|
||||
|
||||
fun scheduleJob(account: Account) {
|
||||
|
||||
if (!isPushEnabled(account)) {
|
||||
return
|
||||
}
|
||||
|
||||
getPushIntervalInMillisecondsIfEnabled(account)?.let { syncInterval ->
|
||||
|
||||
Timber.v("scheduling pusher refresh job for ${account.description}")
|
||||
|
||||
val extras = PersistableBundleCompat()
|
||||
extras.putString(K9JobManager.EXTRA_KEY_ACCOUNT_UUID, account.uuid)
|
||||
|
||||
val jobRequest = JobRequest.Builder(PusherRefreshJob.TAG)
|
||||
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
|
||||
.setRequiresStorageNotLow(true)
|
||||
.setPeriodic(syncInterval)
|
||||
.setExtras(extras)
|
||||
.setRequirementsEnforced(true)
|
||||
.build()
|
||||
|
||||
jobRequest.scheduleAsync()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getPushIntervalInMillisecondsIfEnabled(account: Account): Long? {
|
||||
val intervalMinutes = account.idleRefreshMinutes
|
||||
|
||||
if (intervalMinutes <= Account.INTERVAL_MINUTES_NEVER) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (intervalMinutes * 60 * 1000).toLong()
|
||||
}
|
||||
|
||||
private fun isPushEnabled(account: Account): Boolean {
|
||||
if (account.isEnabled && account.isAvailable(context)) {
|
||||
Timber.i("Setting up pushers for account %s", account.description)
|
||||
return messagingController.setupPushing(account)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package com.fsck.k9.power;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public abstract class DeviceIdleManager {
|
||||
private static DeviceIdleManager instance;
|
||||
|
||||
|
||||
public static synchronized DeviceIdleManager getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
DozeChecker dozeChecker = new DozeChecker(context);
|
||||
if (dozeChecker.isDeviceIdleModeSupported() && !dozeChecker.isAppWhitelisted()) {
|
||||
instance = RealDeviceIdleManager.newInstance(context);
|
||||
} else {
|
||||
instance = new NoOpDeviceIdleManager();
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private DeviceIdleManager() {
|
||||
}
|
||||
|
||||
public abstract void registerReceiver();
|
||||
public abstract void unregisterReceiver();
|
||||
|
||||
|
||||
static class NoOpDeviceIdleManager extends DeviceIdleManager {
|
||||
@Override
|
||||
public void registerReceiver() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterReceiver() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
static class RealDeviceIdleManager extends DeviceIdleManager {
|
||||
private final Context context;
|
||||
private final DeviceIdleReceiver deviceIdleReceiver;
|
||||
private final IntentFilter intentFilter;
|
||||
private boolean registered;
|
||||
|
||||
|
||||
static RealDeviceIdleManager newInstance(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
return new RealDeviceIdleManager(appContext);
|
||||
}
|
||||
|
||||
private RealDeviceIdleManager(Context context) {
|
||||
this.context = context;
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
deviceIdleReceiver = new DeviceIdleReceiver(powerManager);
|
||||
intentFilter = new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerReceiver() {
|
||||
Timber.v("Registering DeviceIdleReceiver");
|
||||
registered = true;
|
||||
context.registerReceiver(deviceIdleReceiver, intentFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterReceiver() {
|
||||
Timber.v("Unregistering DeviceIdleReceiver");
|
||||
if (registered) {
|
||||
context.unregisterReceiver(deviceIdleReceiver);
|
||||
registered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package com.fsck.k9.power;
|
||||
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import com.fsck.k9.service.MailService;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
class DeviceIdleReceiver extends BroadcastReceiver {
|
||||
private final PowerManager powerManager;
|
||||
|
||||
|
||||
DeviceIdleReceiver(PowerManager powerManager) {
|
||||
this.powerManager = powerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
boolean deviceInIdleMode = powerManager.isDeviceIdleMode();
|
||||
Timber.v("Device idle mode changed. Idle: %b", deviceInIdleMode);
|
||||
|
||||
if (!deviceInIdleMode) {
|
||||
MailService.actionReset(context, null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
|
||||
package com.fsck.k9.service;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
import timber.log.Timber;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.helper.K9AlarmManager;
|
||||
|
||||
public class BootReceiver extends CoreReceiver {
|
||||
|
||||
public static final String FIRE_INTENT = "com.fsck.k9.service.BroadcastReceiver.fireIntent";
|
||||
public static final String SCHEDULE_INTENT = "com.fsck.k9.service.BroadcastReceiver.scheduleIntent";
|
||||
public static final String CANCEL_INTENT = "com.fsck.k9.service.BroadcastReceiver.cancelIntent";
|
||||
|
||||
public static final String ALARMED_INTENT = "com.fsck.k9.service.BroadcastReceiver.pendingIntent";
|
||||
public static final String AT_TIME = "com.fsck.k9.service.BroadcastReceiver.atTime";
|
||||
|
||||
@Override
|
||||
public Integer receive(Context context, Intent intent, Integer tmpWakeLockId) {
|
||||
Timber.i("BootReceiver.onReceive %s", intent);
|
||||
|
||||
final String action = intent.getAction();
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
|
||||
//K9.setServicesEnabled(context, tmpWakeLockId);
|
||||
//tmpWakeLockId = null;
|
||||
} else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
|
||||
MailService.actionCancel(context, tmpWakeLockId);
|
||||
tmpWakeLockId = null;
|
||||
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
|
||||
MailService.actionReset(context, tmpWakeLockId);
|
||||
tmpWakeLockId = null;
|
||||
} else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
|
||||
MailService.connectivityChange(context, tmpWakeLockId);
|
||||
tmpWakeLockId = null;
|
||||
} else if ("com.android.sync.SYNC_CONN_STATUS_CHANGED".equals(action)) {
|
||||
K9.BACKGROUND_OPS bOps = K9.getBackgroundOps();
|
||||
if (bOps == K9.BACKGROUND_OPS.WHEN_CHECKED_AUTO_SYNC) {
|
||||
MailService.actionReset(context, tmpWakeLockId);
|
||||
tmpWakeLockId = null;
|
||||
}
|
||||
} else if (FIRE_INTENT.equals(action)) {
|
||||
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
|
||||
String alarmedAction = alarmedIntent.getAction();
|
||||
Timber.i("BootReceiver Got alarm to fire alarmedIntent %s", alarmedAction);
|
||||
alarmedIntent.putExtra(WAKE_LOCK_ID, tmpWakeLockId);
|
||||
tmpWakeLockId = null;
|
||||
context.startService(alarmedIntent);
|
||||
} else if (SCHEDULE_INTENT.equals(action)) {
|
||||
long atTime = intent.getLongExtra(AT_TIME, -1);
|
||||
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
|
||||
Timber.i("BootReceiver Scheduling intent %s for %tc", alarmedIntent, atTime);
|
||||
|
||||
PendingIntent pi = buildPendingIntent(context, intent);
|
||||
K9AlarmManager alarmMgr = K9AlarmManager.getAlarmManager(context);
|
||||
|
||||
alarmMgr.set(AlarmManager.RTC_WAKEUP, atTime, pi);
|
||||
} else if (CANCEL_INTENT.equals(action)) {
|
||||
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
|
||||
Timber.i("BootReceiver Canceling alarmedIntent %s", alarmedIntent);
|
||||
|
||||
PendingIntent pi = buildPendingIntent(context, intent);
|
||||
|
||||
K9AlarmManager alarmMgr = K9AlarmManager.getAlarmManager(context);
|
||||
alarmMgr.cancel(pi);
|
||||
}
|
||||
|
||||
|
||||
return tmpWakeLockId;
|
||||
}
|
||||
|
||||
private PendingIntent buildPendingIntent(Context context, Intent intent) {
|
||||
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
|
||||
String alarmedAction = alarmedIntent.getAction();
|
||||
|
||||
Intent i = new Intent(context, BootReceiver.class);
|
||||
i.setAction(FIRE_INTENT);
|
||||
i.putExtra(ALARMED_INTENT, alarmedIntent);
|
||||
Uri uri = Uri.parse("action://" + alarmedAction);
|
||||
i.setData(uri);
|
||||
return PendingIntent.getBroadcast(context, 0, i, 0);
|
||||
}
|
||||
|
||||
public static void scheduleIntent(Context context, long atTime, Intent alarmedIntent) {
|
||||
Timber.i("BootReceiver Got request to schedule alarmedIntent %s", alarmedIntent.getAction());
|
||||
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, BootReceiver.class);
|
||||
i.setAction(SCHEDULE_INTENT);
|
||||
i.putExtra(ALARMED_INTENT, alarmedIntent);
|
||||
i.putExtra(AT_TIME, atTime);
|
||||
context.sendBroadcast(i);
|
||||
}
|
||||
|
||||
public static void cancelIntent(Context context, Intent alarmedIntent) {
|
||||
Timber.i("BootReceiver Got request to cancel alarmedIntent %s", alarmedIntent.getAction());
|
||||
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, BootReceiver.class);
|
||||
i.setAction(CANCEL_INTENT);
|
||||
i.putExtra(ALARMED_INTENT, alarmedIntent);
|
||||
context.sendBroadcast(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any scheduled alarm.
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public static void purgeSchedule(final Context context) {
|
||||
final K9AlarmManager alarmService = K9AlarmManager.getAlarmManager(context);
|
||||
alarmService.cancel(PendingIntent.getBroadcast(context, 0, new Intent() {
|
||||
@Override
|
||||
public boolean filterEquals(final Intent other) {
|
||||
// we want to match all intents
|
||||
return true;
|
||||
}
|
||||
}, 0));
|
||||
}
|
||||
|
||||
}
|
103
app/core/src/main/java/com/fsck/k9/service/BootReceiver.kt
Normal file
103
app/core/src/main/java/com/fsck/k9/service/BootReceiver.kt
Normal file
|
@ -0,0 +1,103 @@
|
|||
package com.fsck.k9.service
|
||||
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.fsck.k9.K9
|
||||
import com.fsck.k9.helper.K9AlarmManager
|
||||
import com.fsck.k9.job.K9JobManager
|
||||
import org.koin.standalone.KoinComponent
|
||||
import org.koin.standalone.inject
|
||||
import timber.log.Timber
|
||||
|
||||
class BootReceiver : CoreReceiver(), KoinComponent {
|
||||
|
||||
private val jobManager: K9JobManager by inject()
|
||||
|
||||
override fun receive(context: Context, intent: Intent, _tmpWakeLockId: Int?): Int? {
|
||||
var tmpWakeLockId = _tmpWakeLockId
|
||||
Timber.i("BootReceiver.onReceive %s", intent)
|
||||
|
||||
val action = intent.action
|
||||
if (Intent.ACTION_BOOT_COMPLETED == action) {
|
||||
//K9.setServicesEnabled(context, tmpWakeLockId);
|
||||
//tmpWakeLockId = null;
|
||||
} else if ("com.android.sync.SYNC_CONN_STATUS_CHANGED" == action) {
|
||||
val bOps = K9.getBackgroundOps()
|
||||
if (bOps == K9.BACKGROUND_OPS.WHEN_CHECKED_AUTO_SYNC) {
|
||||
jobManager.scheduleAllMailJobs()
|
||||
}
|
||||
} else if (FIRE_INTENT == action) {
|
||||
val alarmedIntent = intent.getParcelableExtra<Intent>(ALARMED_INTENT)
|
||||
val alarmedAction = alarmedIntent.action
|
||||
Timber.i("BootReceiver Got alarm to fire alarmedIntent %s", alarmedAction)
|
||||
alarmedIntent.putExtra(CoreReceiver.WAKE_LOCK_ID, tmpWakeLockId)
|
||||
tmpWakeLockId = null
|
||||
context.startService(alarmedIntent)
|
||||
} else if (SCHEDULE_INTENT == action) {
|
||||
val atTime = intent.getLongExtra(AT_TIME, -1)
|
||||
val alarmedIntent = intent.getParcelableExtra<Intent>(ALARMED_INTENT)
|
||||
Timber.i("BootReceiver Scheduling intent %s for %tc", alarmedIntent, atTime)
|
||||
|
||||
val pi = buildPendingIntent(context, intent)
|
||||
val alarmMgr = K9AlarmManager.getAlarmManager(context)
|
||||
|
||||
alarmMgr.set(AlarmManager.RTC_WAKEUP, atTime, pi)
|
||||
}
|
||||
|
||||
|
||||
return tmpWakeLockId
|
||||
}
|
||||
|
||||
private fun buildPendingIntent(context: Context, intent: Intent): PendingIntent {
|
||||
val alarmedIntent = intent.getParcelableExtra<Intent>(ALARMED_INTENT)
|
||||
val alarmedAction = alarmedIntent.action
|
||||
|
||||
val i = Intent(context, BootReceiver::class.java)
|
||||
i.action = FIRE_INTENT
|
||||
i.putExtra(ALARMED_INTENT, alarmedIntent)
|
||||
val uri = Uri.parse("action://" + alarmedAction!!)
|
||||
i.data = uri
|
||||
return PendingIntent.getBroadcast(context, 0, i, 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val FIRE_INTENT = "com.fsck.k9.service.BroadcastReceiver.fireIntent"
|
||||
const val SCHEDULE_INTENT = "com.fsck.k9.service.BroadcastReceiver.scheduleIntent"
|
||||
const val ALARMED_INTENT = "com.fsck.k9.service.BroadcastReceiver.pendingIntent"
|
||||
const val AT_TIME = "com.fsck.k9.service.BroadcastReceiver.atTime"
|
||||
|
||||
@JvmStatic
|
||||
fun scheduleIntent(context: Context, atTime: Long, alarmedIntent: Intent) {
|
||||
Timber.i("BootReceiver Got request to schedule alarmedIntent %s", alarmedIntent.action)
|
||||
|
||||
val i = Intent()
|
||||
i.setClass(context, BootReceiver::class.java)
|
||||
i.action = SCHEDULE_INTENT
|
||||
i.putExtra(ALARMED_INTENT, alarmedIntent)
|
||||
i.putExtra(AT_TIME, atTime)
|
||||
context.sendBroadcast(i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any scheduled alarm.
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@JvmStatic
|
||||
fun purgeSchedule(context: Context) {
|
||||
val alarmService = K9AlarmManager.getAlarmManager(context)
|
||||
alarmService.cancel(PendingIntent.getBroadcast(context, 0, object : Intent() {
|
||||
override fun filterEquals(other: Intent): Boolean {
|
||||
// we want to match all intents
|
||||
return true
|
||||
}
|
||||
}, 0))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,21 +1,27 @@
|
|||
package com.fsck.k9.service;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Service;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import com.fsck.k9.DI;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.power.TracingPowerManager;
|
||||
import com.fsck.k9.power.TracingPowerManager.TracingWakeLock;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import timber.log.Timber;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.power.TracingPowerManager;
|
||||
import com.fsck.k9.power.TracingPowerManager.TracingWakeLock;
|
||||
|
||||
/**
|
||||
* {@code CoreService} is the base class for all K-9 Services.
|
||||
|
@ -117,7 +123,7 @@ public abstract class CoreService extends Service {
|
|||
* lock is created, registered, and added to {@code intent}.
|
||||
*/
|
||||
protected static void addWakeLockId(Context context, Intent intent, Integer wakeLockId,
|
||||
boolean createIfNotExists) {
|
||||
boolean createIfNotExists) {
|
||||
|
||||
if (wakeLockId != null) {
|
||||
intent.putExtra(BootReceiver.WAKE_LOCK_ID, wakeLockId);
|
||||
|
@ -125,7 +131,7 @@ public abstract class CoreService extends Service {
|
|||
}
|
||||
|
||||
if (createIfNotExists) {
|
||||
addWakeLock(context,intent);
|
||||
addWakeLock(context,intent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,8 +284,8 @@ public abstract class CoreService extends Service {
|
|||
* If this parameter is {@code null} you need to call {@code setAutoShutdown(false)}
|
||||
* otherwise the auto shutdown code will stop the service.
|
||||
*/
|
||||
public void execute(Context context, final Runnable runner, int wakeLockTime,
|
||||
final Integer startId) {
|
||||
public void execute(final Context context, final Runnable runner, int wakeLockTime,
|
||||
final Integer startId) {
|
||||
|
||||
boolean serviceShutdownScheduled = false;
|
||||
final boolean autoShutdown = mAutoShutdown;
|
||||
|
@ -293,8 +299,7 @@ public abstract class CoreService extends Service {
|
|||
Runnable myRunner = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Get the sync status
|
||||
boolean oldIsSyncDisabled = MailService.isSyncDisabled();
|
||||
boolean oldIsSyncDisabled = CoreService.isMailSyncDisabled(context);
|
||||
|
||||
Timber.d("CoreService (%s) running Runnable %d with startId %d",
|
||||
className, runner.hashCode(), startId);
|
||||
|
@ -304,8 +309,9 @@ public abstract class CoreService extends Service {
|
|||
|
||||
// If the sync status changed while runner was executing, notify
|
||||
// MessagingController
|
||||
if (MailService.isSyncDisabled() != oldIsSyncDisabled) {
|
||||
MessagingController.getInstance(getApplication()).systemStatusChanged();
|
||||
if (CoreService.isMailSyncDisabled(context) != oldIsSyncDisabled) {
|
||||
MessagingController messagingController = DI.get(MessagingController.class);
|
||||
messagingController.systemStatusChanged();
|
||||
}
|
||||
} finally {
|
||||
// Making absolutely sure stopSelf() will be called
|
||||
|
@ -404,4 +410,28 @@ public abstract class CoreService extends Service {
|
|||
// Unused
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isMailSyncDisabled(Context context){
|
||||
|
||||
final boolean hasConnectivity = Utility.hasConnectivity(context);
|
||||
@SuppressLint("MissingPermission")
|
||||
final boolean autoSync = ContentResolver.getMasterSyncAutomatically();
|
||||
boolean doBackground = true;
|
||||
K9.BACKGROUND_OPS bOps = K9.getBackgroundOps();
|
||||
|
||||
switch (bOps) {
|
||||
case NEVER:
|
||||
doBackground = false;
|
||||
break;
|
||||
case ALWAYS:
|
||||
doBackground = true;
|
||||
break;
|
||||
case WHEN_CHECKED_AUTO_SYNC:
|
||||
doBackground = autoSync;
|
||||
break;
|
||||
}
|
||||
|
||||
return !(doBackground && hasConnectivity);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,429 +0,0 @@
|
|||
|
||||
package com.fsck.k9.service;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Account.FolderMode;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.Pusher;
|
||||
import com.fsck.k9.preferences.Storage;
|
||||
import com.fsck.k9.preferences.StorageEditor;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class MailService extends CoreService {
|
||||
private static final String ACTION_CHECK_MAIL = "com.fsck.k9.intent.action.MAIL_SERVICE_WAKEUP";
|
||||
private static final String ACTION_RESET = "com.fsck.k9.intent.action.MAIL_SERVICE_RESET";
|
||||
private static final String ACTION_RESCHEDULE_POLL = "com.fsck.k9.intent.action.MAIL_SERVICE_RESCHEDULE_POLL";
|
||||
private static final String ACTION_CANCEL = "com.fsck.k9.intent.action.MAIL_SERVICE_CANCEL";
|
||||
private static final String ACTION_REFRESH_PUSHERS = "com.fsck.k9.intent.action.MAIL_SERVICE_REFRESH_PUSHERS";
|
||||
private static final String ACTION_RESTART_PUSHERS = "com.fsck.k9.intent.action.MAIL_SERVICE_RESTART_PUSHERS";
|
||||
private static final String CONNECTIVITY_CHANGE = "com.fsck.k9.intent.action.MAIL_SERVICE_CONNECTIVITY_CHANGE";
|
||||
private static final String CANCEL_CONNECTIVITY_NOTICE = "com.fsck.k9.intent.action.MAIL_SERVICE_CANCEL_CONNECTIVITY_NOTICE";
|
||||
|
||||
private static long nextCheck = -1;
|
||||
private static boolean pushingRequested = false;
|
||||
private static boolean pollingRequested = false;
|
||||
private static boolean syncNoBackground = false;
|
||||
private static boolean syncNoConnectivity = false;
|
||||
private static boolean syncBlocked = false;
|
||||
|
||||
public static void actionReset(Context context, Integer wakeLockId) {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, MailService.class);
|
||||
i.setAction(MailService.ACTION_RESET);
|
||||
addWakeLockId(context, i, wakeLockId, true);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
public static void actionRestartPushers(Context context, Integer wakeLockId) {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, MailService.class);
|
||||
i.setAction(MailService.ACTION_RESTART_PUSHERS);
|
||||
addWakeLockId(context, i, wakeLockId, true);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
public static void actionReschedulePoll(Context context, Integer wakeLockId) {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, MailService.class);
|
||||
i.setAction(MailService.ACTION_RESCHEDULE_POLL);
|
||||
addWakeLockId(context, i, wakeLockId, true);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
public static void actionCancel(Context context, Integer wakeLockId) {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, MailService.class);
|
||||
i.setAction(MailService.ACTION_CANCEL);
|
||||
addWakeLockId(context, i, wakeLockId, false); // CK:Q: why should we not create a wake lock if one is not already existing like for example in actionReschedulePoll?
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
public static void connectivityChange(Context context, Integer wakeLockId) {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, MailService.class);
|
||||
i.setAction(MailService.CONNECTIVITY_CHANGE);
|
||||
addWakeLockId(context, i, wakeLockId, false); // CK:Q: why should we not create a wake lock if one is not already existing like for example in actionReschedulePoll?
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Timber.v("***** MailService *****: onCreate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int startService(Intent intent, int startId) {
|
||||
long startTime = SystemClock.elapsedRealtime();
|
||||
boolean oldIsSyncDisabled = isSyncDisabled();
|
||||
boolean doBackground = true;
|
||||
|
||||
final boolean hasConnectivity = Utility.hasConnectivity(getApplication());
|
||||
boolean autoSync = ContentResolver.getMasterSyncAutomatically();
|
||||
|
||||
K9.BACKGROUND_OPS bOps = K9.getBackgroundOps();
|
||||
|
||||
switch (bOps) {
|
||||
case NEVER:
|
||||
doBackground = false;
|
||||
break;
|
||||
case ALWAYS:
|
||||
doBackground = true;
|
||||
break;
|
||||
case WHEN_CHECKED_AUTO_SYNC:
|
||||
doBackground = autoSync;
|
||||
break;
|
||||
}
|
||||
|
||||
syncNoBackground = !doBackground;
|
||||
syncNoConnectivity = !hasConnectivity;
|
||||
syncBlocked = !(doBackground && hasConnectivity);
|
||||
|
||||
Timber.i("MailService.onStart(%s, %d), hasConnectivity = %s, doBackground = %s",
|
||||
intent, startId, hasConnectivity, doBackground);
|
||||
|
||||
// MessagingController.getInstance(getApplication()).addListener(mListener);
|
||||
if (ACTION_CHECK_MAIL.equals(intent.getAction())) {
|
||||
Timber.i("***** MailService *****: checking mail");
|
||||
if (hasConnectivity && doBackground) {
|
||||
PollService.startService(this);
|
||||
}
|
||||
reschedulePollInBackground(hasConnectivity, doBackground, startId, false);
|
||||
} else if (ACTION_CANCEL.equals(intent.getAction())) {
|
||||
Timber.v("***** MailService *****: cancel");
|
||||
cancel();
|
||||
} else if (ACTION_RESET.equals(intent.getAction())) {
|
||||
Timber.v("***** MailService *****: reschedule");
|
||||
rescheduleAllInBackground(hasConnectivity, doBackground, startId);
|
||||
} else if (ACTION_RESTART_PUSHERS.equals(intent.getAction())) {
|
||||
Timber.v("***** MailService *****: restarting pushers");
|
||||
reschedulePushersInBackground(hasConnectivity, doBackground, startId);
|
||||
} else if (ACTION_RESCHEDULE_POLL.equals(intent.getAction())) {
|
||||
Timber.v("***** MailService *****: rescheduling poll");
|
||||
reschedulePollInBackground(hasConnectivity, doBackground, startId, true);
|
||||
} else if (ACTION_REFRESH_PUSHERS.equals(intent.getAction())) {
|
||||
refreshPushersInBackground(hasConnectivity, doBackground, startId);
|
||||
} else if (CONNECTIVITY_CHANGE.equals(intent.getAction())) {
|
||||
rescheduleAllInBackground(hasConnectivity, doBackground, startId);
|
||||
Timber.i("Got connectivity action with hasConnectivity = %s, doBackground = %s",
|
||||
hasConnectivity, doBackground);
|
||||
} else if (CANCEL_CONNECTIVITY_NOTICE.equals(intent.getAction())) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
if (isSyncDisabled() != oldIsSyncDisabled) {
|
||||
MessagingController.getInstance(getApplication()).systemStatusChanged();
|
||||
}
|
||||
|
||||
Timber.i("MailService.onStart took %d ms", SystemClock.elapsedRealtime() - startTime);
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Timber.v("***** MailService *****: onDestroy()");
|
||||
super.onDestroy();
|
||||
// MessagingController.getInstance(getApplication()).removeListener(mListener);
|
||||
}
|
||||
|
||||
private void cancel() {
|
||||
Intent i = new Intent(this, MailService.class);
|
||||
i.setAction(ACTION_CHECK_MAIL);
|
||||
BootReceiver.cancelIntent(this, i);
|
||||
}
|
||||
|
||||
private final static String PREVIOUS_INTERVAL = "MailService.previousInterval";
|
||||
private final static String LAST_CHECK_END = "MailService.lastCheckEnd";
|
||||
|
||||
public static void saveLastCheckEnd(Context context) {
|
||||
long lastCheckEnd = System.currentTimeMillis();
|
||||
Timber.i("Saving lastCheckEnd = %tc", lastCheckEnd);
|
||||
|
||||
Preferences prefs = Preferences.getPreferences(context);
|
||||
Storage storage = prefs.getStorage();
|
||||
StorageEditor editor = storage.edit();
|
||||
editor.putLong(LAST_CHECK_END, lastCheckEnd);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
private void rescheduleAllInBackground(final boolean hasConnectivity,
|
||||
final boolean doBackground, Integer startId) {
|
||||
|
||||
execute(getApplication(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reschedulePoll(hasConnectivity, doBackground, true);
|
||||
reschedulePushers(hasConnectivity, doBackground);
|
||||
}
|
||||
}, K9.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
|
||||
}
|
||||
|
||||
private void reschedulePollInBackground(final boolean hasConnectivity,
|
||||
final boolean doBackground, Integer startId, final boolean considerLastCheckEnd) {
|
||||
|
||||
execute(getApplication(), new Runnable() {
|
||||
public void run() {
|
||||
reschedulePoll(hasConnectivity, doBackground, considerLastCheckEnd);
|
||||
}
|
||||
}, K9.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
|
||||
}
|
||||
|
||||
private void reschedulePushersInBackground(final boolean hasConnectivity,
|
||||
final boolean doBackground, Integer startId) {
|
||||
|
||||
execute(getApplication(), new Runnable() {
|
||||
public void run() {
|
||||
reschedulePushers(hasConnectivity, doBackground);
|
||||
}
|
||||
}, K9.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
|
||||
}
|
||||
|
||||
private void refreshPushersInBackground(boolean hasConnectivity, boolean doBackground,
|
||||
Integer startId) {
|
||||
|
||||
if (hasConnectivity && doBackground) {
|
||||
execute(getApplication(), new Runnable() {
|
||||
public void run() {
|
||||
refreshPushers();
|
||||
schedulePushers();
|
||||
}
|
||||
}, K9.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
|
||||
}
|
||||
}
|
||||
|
||||
private void reschedulePoll(final boolean hasConnectivity, final boolean doBackground,
|
||||
boolean considerLastCheckEnd) {
|
||||
|
||||
if (!(hasConnectivity && doBackground)) {
|
||||
Timber.i("No connectivity, canceling check for %s", getApplication().getPackageName());
|
||||
|
||||
nextCheck = -1;
|
||||
cancel();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Preferences prefs = Preferences.getPreferences(MailService.this);
|
||||
Storage storage = prefs.getStorage();
|
||||
int previousInterval = storage.getInt(PREVIOUS_INTERVAL, -1);
|
||||
long lastCheckEnd = storage.getLong(LAST_CHECK_END, -1);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
if (lastCheckEnd > now) {
|
||||
Timber.i("The database claims that the last time mail was checked was in the future (%tc). To try to get " +
|
||||
"things back to normal, the last check time has been reset to: %tc", lastCheckEnd, now);
|
||||
|
||||
lastCheckEnd = now;
|
||||
}
|
||||
|
||||
int shortestInterval = -1;
|
||||
for (Account account : prefs.getAvailableAccounts()) {
|
||||
if (account.getAutomaticCheckIntervalMinutes() != -1 &&
|
||||
account.getFolderSyncMode() != FolderMode.NONE &&
|
||||
(account.getAutomaticCheckIntervalMinutes() < shortestInterval ||
|
||||
shortestInterval == -1)) {
|
||||
shortestInterval = account.getAutomaticCheckIntervalMinutes();
|
||||
}
|
||||
}
|
||||
StorageEditor editor = storage.edit();
|
||||
editor.putInt(PREVIOUS_INTERVAL, shortestInterval);
|
||||
editor.commit();
|
||||
|
||||
if (shortestInterval == -1) {
|
||||
Timber.i("No next check scheduled for package %s", getApplication().getPackageName());
|
||||
|
||||
nextCheck = -1;
|
||||
pollingRequested = false;
|
||||
cancel();
|
||||
} else {
|
||||
long delay = (shortestInterval * (60 * 1000));
|
||||
long base = (previousInterval == -1 || lastCheckEnd == -1 ||
|
||||
!considerLastCheckEnd ? System.currentTimeMillis() : lastCheckEnd);
|
||||
long nextTime = base + delay;
|
||||
|
||||
Timber.i("previousInterval = %d, shortestInterval = %d, lastCheckEnd = %tc, considerLastCheckEnd = %b",
|
||||
previousInterval,
|
||||
shortestInterval,
|
||||
lastCheckEnd,
|
||||
considerLastCheckEnd);
|
||||
|
||||
nextCheck = nextTime;
|
||||
pollingRequested = true;
|
||||
|
||||
try {
|
||||
Timber.i("Next check for package %s scheduled for %tc", getApplication().getPackageName(), nextTime);
|
||||
} catch (Exception e) {
|
||||
// I once got a NullPointerException deep in new Date();
|
||||
Timber.e(e, "Exception while logging");
|
||||
}
|
||||
|
||||
Intent i = new Intent(this, MailService.class);
|
||||
i.setAction(ACTION_CHECK_MAIL);
|
||||
BootReceiver.scheduleIntent(MailService.this, nextTime, i);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSyncDisabled() {
|
||||
return syncBlocked || (!pollingRequested && !pushingRequested);
|
||||
}
|
||||
|
||||
public static boolean hasNoConnectivity() {
|
||||
return syncNoConnectivity;
|
||||
}
|
||||
|
||||
public static boolean isSyncNoBackground() {
|
||||
return syncNoBackground;
|
||||
}
|
||||
|
||||
public static boolean isSyncBlocked() {
|
||||
return syncBlocked;
|
||||
}
|
||||
|
||||
public static boolean isPollAndPushDisabled() {
|
||||
return (!pollingRequested && !pushingRequested);
|
||||
}
|
||||
|
||||
private void stopPushers() {
|
||||
MessagingController.getInstance(getApplication()).stopAllPushing();
|
||||
PushService.stopService(MailService.this);
|
||||
}
|
||||
|
||||
private void reschedulePushers(boolean hasConnectivity, boolean doBackground) {
|
||||
Timber.i("Rescheduling pushers");
|
||||
|
||||
stopPushers();
|
||||
|
||||
if (!(hasConnectivity && doBackground)) {
|
||||
Timber.i("Not scheduling pushers: connectivity? %s -- doBackground? %s", hasConnectivity, doBackground);
|
||||
return;
|
||||
}
|
||||
|
||||
setupPushers();
|
||||
schedulePushers();
|
||||
}
|
||||
|
||||
|
||||
private void setupPushers() {
|
||||
boolean pushing = false;
|
||||
for (Account account : Preferences.getPreferences(MailService.this).getAccounts()) {
|
||||
Timber.i("Setting up pushers for account %s", account.getDescription());
|
||||
|
||||
if (account.isEnabled() && account.isAvailable(getApplicationContext())) {
|
||||
pushing |= MessagingController.getInstance(getApplication()).setupPushing(account);
|
||||
} else {
|
||||
//TODO: setupPushing of unavailable accounts when they become available (sd-card inserted)
|
||||
}
|
||||
}
|
||||
if (pushing) {
|
||||
PushService.startService(MailService.this);
|
||||
}
|
||||
pushingRequested = pushing;
|
||||
}
|
||||
|
||||
private void refreshPushers() {
|
||||
try {
|
||||
long nowTime = System.currentTimeMillis();
|
||||
Timber.i("Refreshing pushers");
|
||||
|
||||
Collection<Pusher> pushers = MessagingController.getInstance(getApplication()).getPushers();
|
||||
for (Pusher pusher : pushers) {
|
||||
long lastRefresh = pusher.getLastRefresh();
|
||||
int refreshInterval = pusher.getRefreshInterval();
|
||||
long sinceLast = nowTime - lastRefresh;
|
||||
if (sinceLast + 10000 > refreshInterval) { // Add 10 seconds to keep pushers in sync, avoid drift
|
||||
Timber.d("PUSHREFRESH: refreshing lastRefresh = %d, interval = %d, nowTime = %d, " +
|
||||
"sinceLast = %d",
|
||||
lastRefresh,
|
||||
refreshInterval,
|
||||
nowTime,
|
||||
sinceLast);
|
||||
|
||||
pusher.refresh();
|
||||
pusher.setLastRefresh(nowTime);
|
||||
} else {
|
||||
Timber.d("PUSHREFRESH: NOT refreshing lastRefresh = %d, interval = %d, nowTime = %d, " +
|
||||
"sinceLast = %d",
|
||||
lastRefresh,
|
||||
refreshInterval,
|
||||
nowTime,
|
||||
sinceLast);
|
||||
}
|
||||
}
|
||||
// Whenever we refresh our pushers, send any unsent messages
|
||||
Timber.d("PUSHREFRESH: trying to send mail in all folders!");
|
||||
|
||||
MessagingController.getInstance(getApplication()).sendPendingMessages(null);
|
||||
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "Exception while refreshing pushers");
|
||||
}
|
||||
}
|
||||
|
||||
private void schedulePushers() {
|
||||
int minInterval = -1;
|
||||
|
||||
Collection<Pusher> pushers = MessagingController.getInstance(getApplication()).getPushers();
|
||||
for (Pusher pusher : pushers) {
|
||||
int interval = pusher.getRefreshInterval();
|
||||
if (interval > 0 && (interval < minInterval || minInterval == -1)) {
|
||||
minInterval = interval;
|
||||
}
|
||||
}
|
||||
|
||||
Timber.v("Pusher refresh interval = %d", minInterval);
|
||||
|
||||
if (minInterval > 0) {
|
||||
long nextTime = System.currentTimeMillis() + minInterval;
|
||||
Timber.d("Next pusher refresh scheduled for %tc", nextTime);
|
||||
|
||||
Intent i = new Intent(this, MailService.class);
|
||||
i.setAction(ACTION_REFRESH_PUSHERS);
|
||||
BootReceiver.scheduleIntent(MailService.this, nextTime, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// Unused
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long getNextPollTime() {
|
||||
return nextCheck;
|
||||
}
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
package com.fsck.k9.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import timber.log.Timber;
|
||||
import com.fsck.k9.*;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.SimpleMessagingListener;
|
||||
import com.fsck.k9.power.TracingPowerManager;
|
||||
import com.fsck.k9.power.TracingPowerManager.TracingWakeLock;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PollService extends CoreService {
|
||||
private static final String START_SERVICE = "com.fsck.k9.service.PollService.startService";
|
||||
private static final String STOP_SERVICE = "com.fsck.k9.service.PollService.stopService";
|
||||
|
||||
private Listener mListener = new Listener();
|
||||
|
||||
public static void startService(Context context) {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, PollService.class);
|
||||
i.setAction(PollService.START_SERVICE);
|
||||
addWakeLock(context, i);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
public static void stopService(Context context) {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, PollService.class);
|
||||
i.setAction(PollService.STOP_SERVICE);
|
||||
addWakeLock(context, i);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
setAutoShutdown(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int startService(Intent intent, int startId) {
|
||||
if (START_SERVICE.equals(intent.getAction())) {
|
||||
Timber.i("PollService started with startId = %d", startId);
|
||||
|
||||
MessagingController controller = MessagingController.getInstance(getApplication());
|
||||
Listener listener = (Listener)controller.getCheckMailListener();
|
||||
if (listener == null) {
|
||||
Timber.i("***** PollService *****: starting new check");
|
||||
mListener.setStartId(startId);
|
||||
mListener.wakeLockAcquire();
|
||||
controller.setCheckMailListener(mListener);
|
||||
controller.checkMail(this, null, false, false, mListener);
|
||||
} else {
|
||||
Timber.i("***** PollService *****: renewing WakeLock");
|
||||
listener.setStartId(startId);
|
||||
listener.wakeLockAcquire();
|
||||
}
|
||||
} else if (STOP_SERVICE.equals(intent.getAction())) {
|
||||
Timber.i("PollService stopping");
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
class Listener extends SimpleMessagingListener {
|
||||
Map<String, Integer> accountsChecked = new HashMap<>();
|
||||
private TracingWakeLock wakeLock = null;
|
||||
private int startId = -1;
|
||||
|
||||
// wakelock strategy is to be very conservative. If there is any reason to release, then release
|
||||
// don't want to take the chance of running wild
|
||||
public synchronized void wakeLockAcquire() {
|
||||
TracingWakeLock oldWakeLock = wakeLock;
|
||||
|
||||
TracingPowerManager pm = TracingPowerManager.getPowerManager(PollService.this);
|
||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PollService wakeLockAcquire");
|
||||
wakeLock.setReferenceCounted(false);
|
||||
wakeLock.acquire(K9.WAKE_LOCK_TIMEOUT);
|
||||
|
||||
if (oldWakeLock != null) {
|
||||
oldWakeLock.release();
|
||||
}
|
||||
|
||||
}
|
||||
public synchronized void wakeLockRelease() {
|
||||
if (wakeLock != null) {
|
||||
wakeLock.release();
|
||||
wakeLock = null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void checkMailStarted(Context context, Account account) {
|
||||
accountsChecked.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void synchronizeMailboxFinished(
|
||||
Account account,
|
||||
String folderServerId,
|
||||
int totalMessagesInMailbox,
|
||||
int numNewMessages) {
|
||||
if (account.isNotifyNewMail()) {
|
||||
Integer existingNewMessages = accountsChecked.get(account.getUuid());
|
||||
if (existingNewMessages == null) {
|
||||
existingNewMessages = 0;
|
||||
}
|
||||
accountsChecked.put(account.getUuid(), existingNewMessages + numNewMessages);
|
||||
}
|
||||
}
|
||||
|
||||
private void release() {
|
||||
|
||||
MessagingController controller = MessagingController.getInstance(getApplication());
|
||||
controller.setCheckMailListener(null);
|
||||
MailService.saveLastCheckEnd(getApplication());
|
||||
|
||||
MailService.actionReschedulePoll(PollService.this, null);
|
||||
wakeLockRelease();
|
||||
|
||||
Timber.i("PollService stopping with startId = %d", startId);
|
||||
stopSelf(startId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkMailFinished(Context context, Account account) {
|
||||
Timber.v("***** PollService *****: checkMailFinished");
|
||||
release();
|
||||
}
|
||||
public int getStartId() {
|
||||
return startId;
|
||||
}
|
||||
public void setStartId(int startId) {
|
||||
this.startId = startId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -331,15 +331,6 @@
|
|||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DEVICE_STORAGE_LOW"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DEVICE_STORAGE_OK"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"/>
|
||||
</intent-filter>
|
||||
|
@ -417,10 +408,6 @@
|
|||
android:enabled="true"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<service
|
||||
android:name=".service.MailService"
|
||||
android:enabled="true"/>
|
||||
|
||||
<service
|
||||
android:name=".notification.NotificationActionService"
|
||||
android:enabled="true"/>
|
||||
|
@ -429,10 +416,6 @@
|
|||
android:name=".service.PushService"
|
||||
android:enabled="true"/>
|
||||
|
||||
<service
|
||||
android:name=".service.PollService"
|
||||
android:enabled="true"/>
|
||||
|
||||
<service
|
||||
android:name=".external.remotecontrol.RemoteControlService"
|
||||
android:enabled="true"
|
||||
|
@ -460,11 +443,11 @@
|
|||
android:authorities="${applicationId}.attachmentprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
|
||||
|
||||
<meta-data
|
||||
android:name="de.cketti.safecontentresolver.ALLOW_INTERNAL_ACCESS"
|
||||
android:value="true" />
|
||||
|
||||
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
package com.fsck.k9.external.remotecontrol;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Account.FolderMode;
|
||||
import com.fsck.k9.DI;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.K9.BACKGROUND_OPS;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.job.K9JobManager;
|
||||
import com.fsck.k9.preferences.Storage;
|
||||
import com.fsck.k9.preferences.StorageEditor;
|
||||
import com.fsck.k9.service.BootReceiver;
|
||||
import com.fsck.k9.service.CoreService;
|
||||
import com.fsck.k9.service.MailService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import static com.fsck.k9.external.remotecontrol.K9RemoteControl.K9_ACCOUNT_UUID;
|
||||
|
@ -37,6 +39,9 @@ public class RemoteControlService extends CoreService {
|
|||
|
||||
private final static String SET_ACTION = "com.fsck.k9.service.RemoteControlService.SET_ACTION";
|
||||
|
||||
private final Preferences preferences = DI.get(Preferences.class);
|
||||
private final K9JobManager jobManager = DI.get(K9JobManager.class);
|
||||
|
||||
public static void set(Context context, Intent i, Integer wakeLockId) {
|
||||
// Intent i = new Intent();
|
||||
i.setClass(context, RemoteControlService.class);
|
||||
|
@ -50,15 +55,14 @@ public class RemoteControlService extends CoreService {
|
|||
@Override
|
||||
public int startService(final Intent intent, final int startId) {
|
||||
Timber.i("RemoteControlService started with startId = %d", startId);
|
||||
final Preferences preferences = Preferences.getPreferences(this);
|
||||
|
||||
if (RESCHEDULE_ACTION.equals(intent.getAction())) {
|
||||
Timber.i("RemoteControlService requesting MailService poll reschedule");
|
||||
MailService.actionReschedulePoll(this, null);
|
||||
Timber.i("RemoteControlService requesting jobmanager mail poll reschedule");
|
||||
jobManager.scheduleMailSync();
|
||||
}
|
||||
if (PUSH_RESTART_ACTION.equals(intent.getAction())) {
|
||||
Timber.i("RemoteControlService requesting MailService push restart");
|
||||
MailService.actionRestartPushers(this, null);
|
||||
Timber.i("RemoteControlService requesting jobmanager push restart");
|
||||
jobManager.schedulePusherRefresh();
|
||||
} else if (RemoteControlService.SET_ACTION.equals(intent.getAction())) {
|
||||
Timber.i("RemoteControlService got request to change settings");
|
||||
execute(getApplication(), new Runnable() {
|
||||
|
|
|
@ -5,14 +5,13 @@ import android.content.BroadcastReceiver;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.AccountStats;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.ui.R;
|
||||
import com.fsck.k9.controller.SimpleMessagingListener;
|
||||
import com.fsck.k9.service.MailService;
|
||||
import com.fsck.k9.service.CoreService;
|
||||
import com.fsck.k9.ui.R;
|
||||
|
||||
import net.jcip.annotations.GuardedBy;
|
||||
|
||||
|
||||
|
@ -49,24 +48,7 @@ public class ActivityListener extends SimpleMessagingListener {
|
|||
}
|
||||
}
|
||||
|
||||
long nextPollTime = MailService.getNextPollTime();
|
||||
if (nextPollTime != -1) {
|
||||
CharSequence relativeTimeSpanString = DateUtils.getRelativeTimeSpanString(
|
||||
nextPollTime, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 0);
|
||||
return context.getString(R.string.status_next_poll, relativeTimeSpanString);
|
||||
} else if (K9.isDebug() && MailService.isSyncDisabled()) {
|
||||
if (MailService.hasNoConnectivity()) {
|
||||
return context.getString(R.string.status_no_network);
|
||||
} else if (MailService.isSyncNoBackground()) {
|
||||
return context.getString(R.string.status_no_background);
|
||||
} else if (MailService.isSyncBlocked()) {
|
||||
return context.getString(R.string.status_syncing_blocked);
|
||||
} else if (MailService.isPollAndPushDisabled()) {
|
||||
return context.getString(R.string.status_poll_and_push_disabled);
|
||||
} else {
|
||||
return context.getString(R.string.status_syncing_off);
|
||||
}
|
||||
} else if (MailService.isSyncDisabled()) {
|
||||
if (CoreService.isMailSyncDisabled(context)) {
|
||||
return context.getString(R.string.status_syncing_off);
|
||||
} else {
|
||||
return "";
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
package com.fsck.k9.activity;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -51,17 +45,24 @@ import com.fsck.k9.activity.setup.FolderSettings;
|
|||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.controller.SimpleMessagingListener;
|
||||
import com.fsck.k9.ui.helper.SizeFormatter;
|
||||
import com.fsck.k9.job.K9JobManager;
|
||||
import com.fsck.k9.mail.Folder;
|
||||
import com.fsck.k9.mailstore.LocalFolder;
|
||||
import com.fsck.k9.power.TracingPowerManager;
|
||||
import com.fsck.k9.power.TracingPowerManager.TracingWakeLock;
|
||||
import com.fsck.k9.mailstore.LocalFolder;
|
||||
import com.fsck.k9.search.LocalSearch;
|
||||
import com.fsck.k9.search.SearchSpecification.Attribute;
|
||||
import com.fsck.k9.search.SearchSpecification.SearchField;
|
||||
import com.fsck.k9.service.MailService;
|
||||
import com.fsck.k9.ui.helper.SizeFormatter;
|
||||
import com.fsck.k9.ui.settings.SettingsActivity;
|
||||
import com.fsck.k9.view.ColorChip;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.cketti.library.changelog.ChangeLog;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
@ -78,6 +79,7 @@ public class FolderList extends K9ListActivity {
|
|||
private static final boolean REFRESH_REMOTE = true;
|
||||
|
||||
private final ColorChipProvider colorChipProvider = DI.get(ColorChipProvider.class);
|
||||
private final K9JobManager jobManager = DI.get(K9JobManager.class);
|
||||
|
||||
private ListView listView;
|
||||
|
||||
|
@ -423,7 +425,7 @@ public class FolderList extends K9ListActivity {
|
|||
account.setFolderDisplayMode(newMode);
|
||||
Preferences.getPreferences(getApplicationContext()).saveAccount(account);
|
||||
if (account.getFolderPushMode() != FolderMode.NONE) {
|
||||
MailService.actionRestartPushers(this, null);
|
||||
jobManager.schedulePusherRefresh();
|
||||
}
|
||||
adapter.getFilter().filter(null);
|
||||
onRefresh(false);
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
package com.fsck.k9.activity.setup;
|
||||
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -32,14 +27,13 @@ import com.fsck.k9.Account.FolderMode;
|
|||
import com.fsck.k9.DI;
|
||||
import com.fsck.k9.LocalKeyStoreManager;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.backend.BackendManager;
|
||||
import com.fsck.k9.preferences.Protocols;
|
||||
import com.fsck.k9.ui.R;
|
||||
import com.fsck.k9.account.AccountCreator;
|
||||
import com.fsck.k9.activity.K9Activity;
|
||||
import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
|
||||
import com.fsck.k9.backend.BackendManager;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.job.K9JobManager;
|
||||
import com.fsck.k9.mail.AuthType;
|
||||
import com.fsck.k9.mail.ConnectionSecurity;
|
||||
import com.fsck.k9.mail.MailServerDirection;
|
||||
|
@ -47,9 +41,16 @@ import com.fsck.k9.mail.NetworkType;
|
|||
import com.fsck.k9.mail.ServerSettings;
|
||||
import com.fsck.k9.mail.store.imap.ImapStoreSettings;
|
||||
import com.fsck.k9.mail.store.webdav.WebDavStoreSettings;
|
||||
import com.fsck.k9.service.MailService;
|
||||
import com.fsck.k9.preferences.Protocols;
|
||||
import com.fsck.k9.ui.R;
|
||||
import com.fsck.k9.view.ClientCertificateSpinner;
|
||||
import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class AccountSetupIncoming extends K9Activity implements OnClickListener {
|
||||
|
@ -60,6 +61,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
|||
|
||||
private final MessagingController messagingController = DI.get(MessagingController.class);
|
||||
private final BackendManager backendManager = DI.get(BackendManager.class);
|
||||
private final K9JobManager jobManager = DI.get(K9JobManager.class);
|
||||
|
||||
private String mStoreType;
|
||||
private EditText mUsernameView;
|
||||
|
@ -514,7 +516,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
|
|||
if (Intent.ACTION_EDIT.equals(getIntent().getAction())) {
|
||||
boolean isPushCapable = messagingController.isPushCapable(mAccount);
|
||||
if (isPushCapable && mAccount.getFolderPushMode() != FolderMode.NONE) {
|
||||
MailService.actionRestartPushers(this, null);
|
||||
jobManager.schedulePusherRefresh();
|
||||
}
|
||||
Preferences.getPreferences(getApplicationContext()).saveAccount(mAccount);
|
||||
finish();
|
||||
|
|
|
@ -17,12 +17,13 @@ import com.fsck.k9.ui.R;
|
|||
import com.fsck.k9.activity.FolderInfoHolder;
|
||||
import com.fsck.k9.activity.K9PreferenceActivity;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.job.K9JobManager;
|
||||
import com.fsck.k9.mail.Folder;
|
||||
import com.fsck.k9.mail.Folder.FolderClass;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mailstore.LocalFolder;
|
||||
import com.fsck.k9.mailstore.LocalStore;
|
||||
import com.fsck.k9.service.MailService;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class FolderSettings extends K9PreferenceActivity {
|
||||
|
@ -39,6 +40,7 @@ public class FolderSettings extends K9PreferenceActivity {
|
|||
private static final String PREFERENCE_INTEGRATE = "folder_settings_include_in_integrated_inbox";
|
||||
|
||||
private final MessagingController messagingController = DI.get(MessagingController.class);
|
||||
private final K9JobManager jobManager = DI.get(K9JobManager.class);
|
||||
|
||||
private LocalFolder mFolder;
|
||||
|
||||
|
@ -160,7 +162,7 @@ public class FolderSettings extends K9PreferenceActivity {
|
|||
|
||||
if (oldPushClass != newPushClass
|
||||
|| (newPushClass != FolderClass.NO_CLASS && oldDisplayClass != newDisplayClass)) {
|
||||
MailService.actionRestartPushers(getApplication(), null);
|
||||
jobManager.schedulePusherRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
package com.fsck.k9.ui.settings.account
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v7.preference.PreferenceDataStore
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Account.SpecialFolderSelection
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.service.MailService
|
||||
import com.fsck.k9.job.K9JobManager
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
class AccountSettingsDataStore(
|
||||
private val context: Context,
|
||||
private val preferences: Preferences,
|
||||
private val executorService: ExecutorService,
|
||||
private val account: Account
|
||||
private val account: Account,
|
||||
private val jobManager: K9JobManager
|
||||
) : PreferenceDataStore() {
|
||||
|
||||
override fun getBoolean(key: String, defValue: Boolean): Boolean {
|
||||
|
@ -216,11 +215,11 @@ class AccountSettingsDataStore(
|
|||
}
|
||||
|
||||
private fun reschedulePoll() {
|
||||
MailService.actionReschedulePoll(context, null)
|
||||
jobManager.scheduleMailSync()
|
||||
}
|
||||
|
||||
private fun restartPushers() {
|
||||
MailService.actionRestartPushers(context, null)
|
||||
jobManager.schedulePusherRefresh()
|
||||
}
|
||||
|
||||
private fun extractFolderName(preferenceValue: String): String? {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package com.fsck.k9.ui.settings.account
|
||||
|
||||
import android.content.Context
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.job.K9JobManager
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
class AccountSettingsDataStoreFactory(
|
||||
private val context: Context,
|
||||
private val preferences: Preferences,
|
||||
private val jobManager: K9JobManager,
|
||||
private val executorService: ExecutorService
|
||||
) {
|
||||
fun create(account: Account): AccountSettingsDataStore {
|
||||
return AccountSettingsDataStore(context, preferences, executorService, account)
|
||||
return AccountSettingsDataStore(preferences, executorService, account, jobManager)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
package com.fsck.k9.ui.settings.general
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import android.support.v7.preference.PreferenceDataStore
|
||||
import com.fsck.k9.K9
|
||||
import com.fsck.k9.K9.Theme
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.service.MailService
|
||||
import com.fsck.k9.job.K9JobManager
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
class GeneralSettingsDataStore(
|
||||
private val context: Context,
|
||||
private val preferences: Preferences,
|
||||
private val jobManager: K9JobManager,
|
||||
private val executorService: ExecutorService
|
||||
) : PreferenceDataStore() {
|
||||
var activity: FragmentActivity? = null
|
||||
|
@ -241,14 +240,10 @@ class GeneralSettingsDataStore(
|
|||
val newBackgroundOps = K9.BACKGROUND_OPS.valueOf(value)
|
||||
if (newBackgroundOps != K9.getBackgroundOps()) {
|
||||
K9.setBackgroundOps(value)
|
||||
resetMailService()
|
||||
jobManager.scheduleAllMailJobs()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetMailService() {
|
||||
MailService.actionReset(context, null)
|
||||
}
|
||||
|
||||
private fun recreateActivity() {
|
||||
activity?.recreate()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue