Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt

328 lines
12 KiB
Kotlin
Raw Normal View History

2016-07-02 05:54:53 +02:00
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.app
import android.app.Application
import android.content.*
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.content.pm.PackageManager
2017-03-23 03:41:04 +01:00
import android.content.res.Configuration
2016-07-02 05:54:53 +02:00
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.net.ConnectivityManager
2016-07-02 05:54:53 +02:00
import android.os.AsyncTask
import android.support.multidex.MultiDex
2017-03-01 15:12:25 +01:00
import com.bumptech.glide.Glide
2016-08-23 09:53:32 +02:00
import nl.komponents.kovenant.android.startKovenant
import nl.komponents.kovenant.android.stopKovenant
2016-09-09 05:58:26 +02:00
import nl.komponents.kovenant.task
2017-03-01 09:27:45 +01:00
import okhttp3.Dns
2016-09-09 05:58:26 +02:00
import org.mariotaku.kpreferences.KPreferences
2016-12-14 09:02:50 +01:00
import org.mariotaku.kpreferences.get
import org.mariotaku.kpreferences.set
2017-03-23 03:41:04 +01:00
import org.mariotaku.ktextension.setLayoutDirectionCompat
import org.mariotaku.mediaviewer.library.MediaDownloader
2016-09-09 05:58:26 +02:00
import org.mariotaku.restfu.http.RestHttpClient
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants
2016-12-15 06:11:32 +01:00
import org.mariotaku.twidere.Constants.KEY_USAGE_STATISTICS
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.AssistLauncherActivity
import org.mariotaku.twidere.activity.MainActivity
import org.mariotaku.twidere.activity.MainHondaJOJOActivity
2017-03-13 08:13:39 +01:00
import org.mariotaku.twidere.constant.*
2016-09-09 05:58:26 +02:00
import org.mariotaku.twidere.model.DefaultFeatures
import org.mariotaku.twidere.receiver.ConnectivityStateReceiver
2017-03-13 08:13:39 +01:00
import org.mariotaku.twidere.service.StreamingService
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper
2017-04-16 15:09:56 +02:00
import org.mariotaku.twidere.util.dagger.GeneralComponent
2017-03-07 15:13:59 +01:00
import org.mariotaku.twidere.util.media.MediaPreloader
import org.mariotaku.twidere.util.media.ThumborWrapper
2016-09-09 05:58:26 +02:00
import org.mariotaku.twidere.util.net.TwidereDns
2017-02-01 07:04:14 +01:00
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
2017-01-05 14:08:49 +01:00
import org.mariotaku.twidere.util.refresh.AutoRefreshController
2017-04-13 18:57:14 +02:00
import org.mariotaku.twidere.util.sync.DataSyncProvider
import org.mariotaku.twidere.util.sync.SyncController
2016-12-15 06:11:32 +01:00
import java.util.*
2016-09-09 05:58:26 +02:00
import java.util.concurrent.TimeUnit
import javax.inject.Inject
2016-07-02 05:54:53 +02:00
class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeListener {
2016-09-09 05:58:26 +02:00
@Inject
lateinit internal var activityTracker: ActivityTracker
@Inject
lateinit internal var restHttpClient: RestHttpClient
@Inject
2017-03-01 09:27:45 +01:00
lateinit internal var dns: Dns
2016-09-09 05:58:26 +02:00
@Inject
lateinit internal var mediaDownloader: MediaDownloader
@Inject
2016-09-09 05:58:26 +02:00
lateinit internal var defaultFeatures: DefaultFeatures
@Inject
lateinit internal var externalThemeManager: ExternalThemeManager
@Inject
lateinit internal var kPreferences: KPreferences
2016-12-17 16:05:02 +01:00
@Inject
lateinit internal var autoRefreshController: AutoRefreshController
@Inject
lateinit internal var syncController: SyncController
2017-02-01 07:04:14 +01:00
@Inject
lateinit internal var extraFeaturesService: ExtraFeaturesService
2017-02-02 11:18:34 +01:00
@Inject
lateinit internal var mediaPreloader: MediaPreloader
2017-02-17 15:27:53 +01:00
@Inject
lateinit internal var contentNotificationManager: ContentNotificationManager
2017-03-07 15:13:59 +01:00
@Inject
lateinit internal var thumbor: ThumborWrapper
2016-09-09 05:58:26 +02:00
2016-07-02 05:54:53 +02:00
val sqLiteDatabase: SQLiteDatabase by lazy {
StrictModeUtils.checkDiskIO()
sqLiteOpenHelper.writableDatabase
}
val sqLiteOpenHelper: SQLiteOpenHelper by lazy {
TwidereSQLiteOpenHelper(this, Constants.DATABASES_NAME, Constants.DATABASES_VERSION)
}
2017-03-23 03:41:04 +01:00
private val sharedPreferences: SharedPreferences by lazy {
val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
prefs.registerOnSharedPreferenceChangeListener(this)
return@lazy prefs
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
2016-07-02 05:54:53 +02:00
override fun onCreate() {
instance = this
if (BuildConfig.DEBUG) {
StrictModeUtils.detectAllVmPolicy()
}
super.onCreate()
2017-03-23 03:41:04 +01:00
applyLanguageSettings()
2016-08-23 09:53:32 +02:00
startKovenant()
2016-09-09 05:58:26 +02:00
initializeAsyncTask()
initDebugMode()
initBugReport()
updateEasterEggIcon()
migrateUsageStatisticsPreferences()
2017-04-16 15:09:56 +02:00
GeneralComponent.get(this).inject(this)
2016-09-09 05:58:26 +02:00
2016-12-17 16:05:02 +01:00
autoRefreshController.appStarted()
syncController.appStarted()
2017-02-01 07:04:14 +01:00
extraFeaturesService.appStarted()
2016-12-17 16:05:02 +01:00
2016-09-09 05:58:26 +02:00
registerActivityLifecycleCallbacks(activityTracker)
registerReceiver(ConnectivityStateReceiver(), IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
2016-09-09 05:58:26 +02:00
listenExternalThemeChange()
loadDefaultFeatures()
2017-03-21 03:33:27 +01:00
Analyzer.preferencesChanged(sharedPreferences)
2017-04-13 18:57:14 +02:00
DataSyncProvider.Factory.notifyUpdate(this)
2016-09-09 05:58:26 +02:00
}
2017-03-23 03:41:04 +01:00
override fun onConfigurationChanged(newConfig: Configuration?) {
applyLanguageSettings()
super.onConfigurationChanged(newConfig)
}
override fun onTrimMemory(level: Int) {
Glide.with(this).onTrimMemory(level)
super.onTrimMemory(level)
}
override fun onLowMemory() {
Glide.with(this).onLowMemory()
super.onLowMemory()
}
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
when (key) {
KEY_REFRESH_INTERVAL -> {
autoRefreshController.rescheduleAll()
}
KEY_ENABLE_PROXY, KEY_PROXY_HOST, KEY_PROXY_PORT, KEY_PROXY_TYPE, KEY_PROXY_USERNAME,
KEY_PROXY_PASSWORD, KEY_CONNECTION_TIMEOUT, KEY_RETRY_ON_NETWORK_ISSUE -> {
HttpClientFactory.reloadConnectivitySettings(this)
}
KEY_DNS_SERVER, KEY_TCP_DNS_QUERY, KEY_BUILTIN_DNS_RESOLVER -> {
reloadDnsSettings()
}
2017-04-09 11:13:00 +02:00
KEY_CREDENTIALS_TYPE, KEY_API_URL_FORMAT, KEY_CONSUMER_KEY, KEY_CONSUMER_SECRET,
KEY_SAME_OAUTH_SIGNING_URL -> {
2017-03-23 03:41:04 +01:00
preferences[apiLastChangeKey] = System.currentTimeMillis()
}
KEY_EMOJI_SUPPORT -> {
externalThemeManager.reloadEmojiPreferences()
}
2017-04-09 11:13:00 +02:00
KEY_THUMBOR_ENABLED, KEY_THUMBOR_ADDRESS, KEY_THUMBOR_SECURITY_KEY -> {
2017-03-23 03:41:04 +01:00
thumbor.reloadSettings(preferences)
}
KEY_MEDIA_PRELOAD, KEY_PRELOAD_WIFI_ONLY -> {
mediaPreloader.reloadOptions(preferences)
}
KEY_NAME_FIRST, KEY_I_WANT_MY_STARS_BACK -> {
contentNotificationManager.updatePreferences()
}
streamingEnabledKey.key, streamingPowerSavingKey.key,
streamingNonMeteredNetworkKey.key -> {
val streamingIntent = Intent(this, StreamingService::class.java)
if (activityTracker.isHomeActivityLaunched) {
startService(streamingIntent)
} else {
stopService(streamingIntent)
}
}
}
Analyzer.preferencesChanged(preferences)
}
override fun onTerminate() {
super.onTerminate()
stopKovenant()
}
@Suppress("DEPRECATION")
private fun applyLanguageSettings() {
val locale = sharedPreferences[overrideLanguageKey] ?: return
Locale.setDefault(locale)
val config = resources.configuration
config.locale = locale
config.setLayoutDirectionCompat(locale)
resources.updateConfiguration(config, resources.displayMetrics)
}
2016-09-09 05:58:26 +02:00
private fun loadDefaultFeatures() {
val lastUpdated = kPreferences[defaultFeatureLastUpdated]
if (lastUpdated > 0 && TimeUnit.MILLISECONDS.toHours(System.currentTimeMillis() - lastUpdated) < 12) {
return
}
task {
defaultFeatures.loadRemoteSettings(restHttpClient)
}.success {
2016-11-25 14:21:51 +01:00
defaultFeatures.save(sharedPreferences)
2017-01-26 16:15:05 +01:00
DebugLog.d(LOGTAG, "Loaded remote features")
2016-09-09 05:58:26 +02:00
}.fail {
2017-01-26 16:15:05 +01:00
DebugLog.w(LOGTAG, "Unable to load remote features", it)
2016-09-09 05:58:26 +02:00
}.always {
kPreferences[defaultFeatureLastUpdated] = System.currentTimeMillis()
}
}
private fun listenExternalThemeChange() {
val packageFilter = IntentFilter()
packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED)
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED)
packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
packageFilter.addAction(Intent.ACTION_PACKAGE_REPLACED)
registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
val packages = packageManager.getPackagesForUid(uid)
val manager = externalThemeManager
2017-04-07 06:12:34 +02:00
if (manager.emojiPackageName in packages) {
2016-09-09 05:58:26 +02:00
manager.reloadEmojiPreferences()
}
}
}, packageFilter)
}
private fun updateEasterEggIcon() {
val pm = packageManager
val main = ComponentName(this, MainActivity::class.java)
val main2 = ComponentName(this, MainHondaJOJOActivity::class.java)
val mainDisabled = pm.getComponentEnabledSetting(main) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED
val main2Disabled = pm.getComponentEnabledSetting(main2) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED
val noEntry = mainDisabled && main2Disabled
if (noEntry) {
pm.setComponentEnabledSetting(main, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP)
} else if (!mainDisabled) {
pm.setComponentEnabledSetting(main2, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP)
}
if (!Utils.isComposeNowSupported(this)) {
val assist = ComponentName(this, AssistLauncherActivity::class.java)
pm.setComponentEnabledSetting(assist, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP)
}
}
2016-07-02 05:54:53 +02:00
private fun initDebugMode() {
DebugModeUtils.initForApplication(this)
}
private fun initBugReport() {
2016-12-14 09:02:50 +01:00
if (!sharedPreferences[bugReportsKey]) return
2016-12-15 06:11:32 +01:00
Analyzer.implementation = ServiceLoader.load(Analyzer::class.java).firstOrNull()
Analyzer.init(this)
2016-07-02 05:54:53 +02:00
}
private fun migrateUsageStatisticsPreferences() {
val preferences = sharedPreferences
2016-12-15 06:11:32 +01:00
val hasUsageStatistics = preferences.contains(KEY_USAGE_STATISTICS)
2016-07-02 05:54:53 +02:00
if (hasUsageStatistics) return
if (preferences.contains(KEY_UCD_DATA_PROFILING) || preferences.contains(KEY_SPICE_DATA_PROFILING)) {
val prevUsageEnabled = preferences.getBoolean(KEY_UCD_DATA_PROFILING, false) || preferences.getBoolean(KEY_SPICE_DATA_PROFILING, false)
val editor = preferences.edit()
2016-12-15 06:11:32 +01:00
editor.putBoolean(KEY_USAGE_STATISTICS, prevUsageEnabled)
2016-07-02 05:54:53 +02:00
editor.remove(KEY_UCD_DATA_PROFILING)
editor.remove(KEY_SPICE_DATA_PROFILING)
editor.apply()
}
}
private fun reloadDnsSettings() {
2017-03-01 09:27:45 +01:00
(dns as? TwidereDns)?.reloadDnsSettings()
2016-07-02 05:54:53 +02:00
}
private fun initializeAsyncTask() {
// AsyncTask class needs to be loaded in UI thread.
// So we load it here to comply the rule.
try {
Class.forName(AsyncTask::class.java.name)
} catch (ignore: ClassNotFoundException) {
}
}
companion object {
private val KEY_UCD_DATA_PROFILING = "ucd_data_profiling"
private val KEY_SPICE_DATA_PROFILING = "spice_data_profiling"
private val KEY_KEYBOARD_SHORTCUT_INITIALIZED = "keyboard_shortcut_initialized"
var instance: TwidereApplication? = null
private set
fun getInstance(context: Context): TwidereApplication {
return context.applicationContext as TwidereApplication
}
}
}