Move functionality from classes DI and K9 to new Core class

This commit is contained in:
cketti 2018-06-22 15:13:59 +02:00
parent e0abd9e07f
commit 89ae84e693
9 changed files with 208 additions and 184 deletions

View file

@ -0,0 +1,168 @@
package com.fsck.k9
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Handler
import android.os.Looper
import android.os.StrictMode
import com.fsck.k9.activity.MessageCompose
import com.fsck.k9.autocrypt.autocryptModule
import com.fsck.k9.backend.backendModule
import com.fsck.k9.crypto.openPgpModule
import com.fsck.k9.mailstore.mailStoreModule
import com.fsck.k9.message.extractors.extractorModule
import com.fsck.k9.message.html.htmlModule
import com.fsck.k9.power.DeviceIdleManager
import com.fsck.k9.remotecontrol.K9RemoteControl
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 com.fsck.k9.ui.endtoend.endToEndUiModule
import com.fsck.k9.ui.settings.settingsUiModule
import com.fsck.k9.widget.unread.unreadWidgetModule
import timber.log.Timber
import java.util.concurrent.SynchronousQueue
object Core {
@JvmStatic
val coreModules = listOf(
mainModule,
settingsUiModule,
unreadWidgetModule,
endToEndUiModule,
openPgpModule,
autocryptModule,
mailStoreModule,
backendModule,
extractorModule,
htmlModule
)
/**
* This needs to be called from [Application#onCreate][android.app.Application#onCreate] before calling through
* to the super class's `onCreate` implementation and before initializing the dependency injection library.
*/
@JvmStatic
fun earlyInit(context: Context) {
if (K9.DEVELOPER_MODE) {
StrictMode.enableDefaults()
}
PRNGFixes.apply()
val packageName = context.packageName
K9RemoteControl.init(packageName)
K9.Intents.init(packageName)
}
/**
* Called throughout the application when the number of accounts has changed. This method
* enables or disables the Compose activity, the boot receiver and the service based on
* whether any accounts are configured.
*/
@JvmStatic
fun setServicesEnabled(context: Context) {
val appContext = context.applicationContext
val acctLength = Preferences.getPreferences(appContext).availableAccounts.size
val enable = acctLength > 0
setServicesEnabled(appContext, enable, null)
updateDeviceIdleReceiver(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?) {
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 = arrayOf(
MessageCompose::class.java,
BootReceiver::class.java,
MailService::class.java
)
for (clazz in classes) {
val alreadyEnabled = pm.getComponentEnabledSetting(ComponentName(context, clazz)) ==
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
if (enabled != alreadyEnabled) {
pm.setComponentEnabledSetting(
ComponentName(context, clazz),
if (enabled)
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
else
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP)
}
}
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)
}
}
/**
* Register BroadcastReceivers programmatically because doing it from manifest
* would make K-9 auto-start. We don't want auto-start because the initialization
* sequence isn't safe while some events occur (SD card unmount).
*/
@JvmStatic
fun registerReceivers(context: Context) {
val receiver = StorageGoneReceiver()
val filter = IntentFilter()
filter.addAction(Intent.ACTION_MEDIA_EJECT)
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED)
filter.addDataScheme("file")
val queue = SynchronousQueue<Handler>()
// starting a new thread to handle unmount events
Thread(Runnable {
Looper.prepare()
try {
queue.put(Handler())
} catch (e: InterruptedException) {
Timber.e(e)
}
Looper.loop()
}, "Unmount-thread").start()
try {
val storageGoneHandler = queue.take()
context.registerReceiver(receiver, filter, null, storageGoneHandler)
Timber.i("Registered: unmount receiver")
} catch (e: InterruptedException) {
Timber.e(e, "Unable to register unmount receiver")
}
context.registerReceiver(ShutdownReceiver(), IntentFilter(Intent.ACTION_SHUTDOWN))
Timber.i("Registered: shutdown receiver")
}
}

View file

@ -1,61 +1,22 @@
package com.fsck.k9
import android.app.Application
import android.content.Context
import com.fsck.k9.autocrypt.autocryptModule
import com.fsck.k9.backend.backendModule
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.core.BuildConfig
import com.fsck.k9.crypto.openPgpModule
import com.fsck.k9.mail.TransportProvider
import com.fsck.k9.mail.power.PowerManager
import com.fsck.k9.mailstore.StorageManager
import com.fsck.k9.mailstore.mailStoreModule
import com.fsck.k9.message.extractors.extractorModule
import com.fsck.k9.message.html.htmlModule
import com.fsck.k9.power.TracingPowerManager
import com.fsck.k9.ui.endtoend.endToEndUiModule
import com.fsck.k9.ui.folders.FolderNameFormatter
import com.fsck.k9.ui.settings.settingsUiModule
import com.fsck.k9.widget.unread.unreadWidgetModule
import org.koin.Koin
import org.koin.KoinContext
import org.koin.android.ext.koin.with
import org.koin.android.logger.AndroidLogger
import org.koin.core.parameter.Parameters
import org.koin.dsl.module.applicationContext
import org.koin.dsl.module.Module
import org.koin.log.EmptyLogger
import org.koin.standalone.StandAloneContext
object DI {
private val mainModule = applicationContext {
bean { Preferences.getPreferences(get()) }
bean { MessagingController.getInstance(get()) }
bean { TransportProvider() }
bean { get<Context>().resources }
bean { StorageManager.getInstance(get()) }
bean { FolderNameFormatter(get()) }
bean { TracingPowerManager.getPowerManager(get()) as PowerManager }
}
val appModules = listOf(
mainModule,
settingsUiModule,
unreadWidgetModule,
endToEndUiModule,
openPgpModule,
autocryptModule,
mailStoreModule,
backendModule,
extractorModule,
htmlModule
)
@JvmStatic fun start(application: Application) {
@JvmStatic fun start(application: Application, modules: List<Module>) {
@Suppress("ConstantConditionIf")
Koin.logger = if (BuildConfig.DEBUG) AndroidLogger() else EmptyLogger()
StandAloneContext.startKoin(appModules) with application
StandAloneContext.startKoin(modules) with application
}
@JvmOverloads

View file

@ -5,26 +5,16 @@ package com.fsck.k9;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.StrictMode;
import com.fsck.k9.Account.SortType;
import com.fsck.k9.activity.MessageCompose;
import com.fsck.k9.activity.UpgradeDatabases;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.SimpleMessagingListener;
@ -36,15 +26,9 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.internet.BinaryTempFileBody;
import com.fsck.k9.mail.ssl.LocalKeyStore;
import com.fsck.k9.mailstore.LocalStore;
import com.fsck.k9.power.DeviceIdleManager;
import com.fsck.k9.preferences.Storage;
import com.fsck.k9.preferences.StorageEditor;
import com.fsck.k9.provider.MessageProvider;
import com.fsck.k9.remotecontrol.K9RemoteControl;
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 com.fsck.k9.widget.list.MessageListWidgetProvider;
import com.fsck.k9.widget.unread.UnreadWidgetUpdater;
import timber.log.Timber;
@ -321,110 +305,6 @@ public class K9 extends Application {
}
}
/**
* Called throughout the application when the number of accounts has changed. This method
* enables or disables the Compose activity, the boot receiver and the service based on
* whether any accounts are configured.
*/
public static void setServicesEnabled(Context context) {
Context appContext = context.getApplicationContext();
int acctLength = Preferences.getPreferences(appContext).getAvailableAccounts().size();
boolean enable = acctLength > 0;
setServicesEnabled(appContext, enable, null);
updateDeviceIdleReceiver(appContext, enable);
}
private static void updateDeviceIdleReceiver(Context context, boolean enable) {
DeviceIdleManager deviceIdleManager = DeviceIdleManager.getInstance(context);
if (enable) {
deviceIdleManager.registerReceiver();
} else {
deviceIdleManager.unregisterReceiver();
}
}
private static void setServicesEnabled(Context context, boolean enabled, Integer wakeLockId) {
PackageManager pm = context.getPackageManager();
if (!enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
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);
}
Class<?>[] classes = { MessageCompose.class, BootReceiver.class, MailService.class };
for (Class<?> clazz : classes) {
boolean alreadyEnabled = pm.getComponentEnabledSetting(new ComponentName(context, clazz)) ==
PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
if (enabled != alreadyEnabled) {
pm.setComponentEnabledSetting(
new ComponentName(context, clazz),
enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
if (enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
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);
}
}
/**
* Register BroadcastReceivers programmatically because doing it from manifest
* would make K-9 auto-start. We don't want auto-start because the initialization
* sequence isn't safe while some events occur (SD card unmount).
*/
protected void registerReceivers() {
final StorageGoneReceiver receiver = new StorageGoneReceiver();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_EJECT);
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
filter.addDataScheme("file");
final BlockingQueue<Handler> queue = new SynchronousQueue<Handler>();
// starting a new thread to handle unmount events
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
try {
queue.put(new Handler());
} catch (InterruptedException e) {
Timber.e(e);
}
Looper.loop();
}
}, "Unmount-thread").start();
try {
final Handler storageGoneHandler = queue.take();
registerReceiver(receiver, filter, null, storageGoneHandler);
Timber.i("Registered: unmount receiver");
} catch (InterruptedException e) {
Timber.e(e, "Unable to register unmount receiver");
}
registerReceiver(new ShutdownReceiver(), new IntentFilter(Intent.ACTION_SHUTDOWN));
Timber.i("Registered: shutdown receiver");
}
public static void save(StorageEditor editor) {
editor.putBoolean("enableDebugLogging", K9.DEBUG);
editor.putBoolean("enableSensitiveLogging", K9.DEBUG_SENSITIVE);
@ -500,18 +380,10 @@ public class K9 extends Application {
@Override
public void onCreate() {
if (K9.DEVELOPER_MODE) {
StrictMode.enableDefaults();
}
PRNGFixes.apply();
String packageName = getPackageName();
K9RemoteControl.init(packageName);
Intents.init(packageName);
Core.earlyInit(this);
super.onCreate();
DI.start(this);
DI.start(this, Core.getCoreModules());
K9MailLib.setDebugStatus(new K9MailLib.DebugStatus() {
@Override public boolean enabled() {
@ -540,8 +412,8 @@ public class K9 extends Application {
* Enable background sync of messages
*/
setServicesEnabled(this);
registerReceivers();
Core.setServicesEnabled(this);
Core.registerReceivers(this);
MessagingController.getInstance(this).addListener(new SimpleMessagingListener() {
private UnreadWidgetUpdater unreadWidgetUpdater = DI.get(UnreadWidgetUpdater.class);

View file

@ -0,0 +1,20 @@
package com.fsck.k9
import android.content.Context
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.mail.TransportProvider
import com.fsck.k9.mail.power.PowerManager
import com.fsck.k9.mailstore.StorageManager
import com.fsck.k9.power.TracingPowerManager
import com.fsck.k9.ui.folders.FolderNameFormatter
import org.koin.dsl.module.applicationContext
val mainModule = applicationContext {
bean { Preferences.getPreferences(get()) }
bean { MessagingController.getInstance(get()) }
bean { TransportProvider() }
bean { get<Context>().resources }
bean { StorageManager.getInstance(get()) }
bean { FolderNameFormatter(get()) }
bean { TracingPowerManager.getPowerManager(get()) as PowerManager }
}

View file

@ -61,6 +61,7 @@ import android.widget.Toast;
import com.fsck.k9.Account;
import com.fsck.k9.AccountStats;
import com.fsck.k9.BaseAccount;
import com.fsck.k9.Core;
import com.fsck.k9.FontSizes;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
@ -984,7 +985,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
mAccount.save(Preferences.getPreferences(mContext));
// Start services if necessary
K9.setServicesEnabled(mContext);
Core.setServicesEnabled(mContext);
// Get list of folders from remote server
MessagingController.getInstance(mApplication).listFolders(mAccount, true, null);
@ -1050,7 +1051,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
.deleteAccount(realAccount);
Preferences.getPreferences(Accounts.this)
.deleteAccount(realAccount);
K9.setServicesEnabled(Accounts.this);
Core.setServicesEnabled(Accounts.this);
refresh();
}
}

View file

@ -25,8 +25,8 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import com.fsck.k9.Account;
import com.fsck.k9.Core;
import com.fsck.k9.EmailAddressValidator;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.core.R;
import com.fsck.k9.account.AccountCreator;
@ -373,7 +373,7 @@ public class AccountSetupBasics extends K9Activity
//We've successfully checked outgoing as well.
mAccount.setDescription(mAccount.getEmail());
mAccount.save(Preferences.getPreferences(this));
K9.setServicesEnabled(this);
Core.setServicesEnabled(this);
AccountSetupNames.actionSetNames(this, mAccount);
finish();
}

View file

@ -12,8 +12,8 @@ import android.widget.CheckBox;
import android.widget.Spinner;
import com.fsck.k9.Account;
import com.fsck.k9.Core;
import com.fsck.k9.DI;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.core.R;
import com.fsck.k9.activity.K9Activity;
@ -148,7 +148,7 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false)) {
Preferences.getPreferences(this).setDefaultAccount(mAccount);
}
K9.setServicesEnabled(this);
Core.setServicesEnabled(this);
AccountSetupNames.actionSetNames(this, mAccount);
finish();
}

View file

@ -15,9 +15,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import com.fsck.k9.Core;
import timber.log.Timber;
import com.fsck.k9.K9;
import com.fsck.k9.core.R;
/**
@ -661,7 +662,7 @@ public class StorageManager {
sync.unmounting = false;
sync.writeLock.unlock();
K9.setServicesEnabled(context);
Core.setServicesEnabled(context);
}
/**
@ -687,7 +688,7 @@ public class StorageManager {
}
// XXX we should reset mail service ONLY if there are accounts using the storage (this is not done in a regular listener because it has to be invoked afterward)
K9.setServicesEnabled(context);
Core.setServicesEnabled(context);
}
/**

View file

@ -18,6 +18,7 @@ import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import com.fsck.k9.Account;
import com.fsck.k9.Core;
import com.fsck.k9.Identity;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
@ -268,7 +269,7 @@ public class SettingsImporter {
preferences.loadAccounts();
K9.loadPrefs(preferences);
K9.setServicesEnabled(context);
Core.setServicesEnabled(context);
return new ImportResults(globalSettingsImported, importedAccounts, erroneousAccounts);