Fix some StrictMode warnings

pull/26/head
Koitharu 6 years ago
parent 908baebb62
commit 03dbd86363

@ -3,6 +3,7 @@ package org.koitharu.kotatsu.core.network
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.core.qualifier.named
import org.koin.dsl.module import org.koin.dsl.module
import org.koitharu.kotatsu.core.network.cookies.PersistentCookieJar import org.koitharu.kotatsu.core.network.cookies.PersistentCookieJar
import org.koitharu.kotatsu.core.network.cookies.cache.SetCookieCache import org.koitharu.kotatsu.core.network.cookies.cache.SetCookieCache
@ -18,13 +19,14 @@ val networkModule
SharedPrefsCookiePersistor(androidContext()) SharedPrefsCookiePersistor(androidContext())
) )
} }
single(named(CacheUtils.QUALIFIER_HTTP)) { CacheUtils.createHttpCache(androidContext()) }
single { single {
OkHttpClient.Builder().apply { OkHttpClient.Builder().apply {
connectTimeout(20, TimeUnit.SECONDS) connectTimeout(20, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS) readTimeout(60, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS) writeTimeout(20, TimeUnit.SECONDS)
cookieJar(get()) cookieJar(get())
cache(CacheUtils.createHttpCache(androidContext())) cache(get(named(CacheUtils.QUALIFIER_HTTP)))
addInterceptor(UserAgentInterceptor()) addInterceptor(UserAgentInterceptor())
addInterceptor(CloudFlareInterceptor()) addInterceptor(CloudFlareInterceptor())
}.build() }.build()

@ -20,24 +20,29 @@ import okhttp3.HttpUrl
import org.koitharu.kotatsu.core.network.cookies.cache.CookieCache import org.koitharu.kotatsu.core.network.cookies.cache.CookieCache
import org.koitharu.kotatsu.core.network.cookies.persistence.CookiePersistor import org.koitharu.kotatsu.core.network.cookies.persistence.CookiePersistor
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
class PersistentCookieJar( class PersistentCookieJar(
private val cache: CookieCache, private val cache: CookieCache,
private val persistor: CookiePersistor private val persistor: CookiePersistor
) : ClearableCookieJar { ) : ClearableCookieJar {
init { private var isLoaded = AtomicBoolean(false)
cache.addAll(persistor.loadAll())
}
@Synchronized @Synchronized
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) { override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
if (isLoaded.compareAndSet(false, true)) {
cache.addAll(persistor.loadAll())
}
cache.addAll(cookies) cache.addAll(cookies)
persistor.saveAll(filterPersistentCookies(cookies)) persistor.saveAll(filterPersistentCookies(cookies))
} }
@Synchronized @Synchronized
override fun loadForRequest(url: HttpUrl): List<Cookie> { override fun loadForRequest(url: HttpUrl): List<Cookie> {
if (isLoaded.compareAndSet(false, true)) {
cache.addAll(persistor.loadAll())
}
val cookiesToRemove: MutableList<Cookie> = ArrayList() val cookiesToRemove: MutableList<Cookie> = ArrayList()
val validCookies: MutableList<Cookie> = ArrayList() val validCookies: MutableList<Cookie> = ArrayList()
val it = cache.iterator() val it = cache.iterator()

@ -15,22 +15,15 @@
*/ */
package org.koitharu.kotatsu.core.network.cookies.persistence package org.koitharu.kotatsu.core.network.cookies.persistence
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import okhttp3.Cookie import okhttp3.Cookie
import java.util.* import java.util.*
@SuppressLint("CommitPrefEdits") class SharedPrefsCookiePersistor(context: Context) : CookiePersistor {
class SharedPrefsCookiePersistor(private val sharedPreferences: SharedPreferences) :
CookiePersistor {
constructor(context: Context) : this( private val sharedPreferences by lazy {
context.getSharedPreferences( context.getSharedPreferences("cookies", Context.MODE_PRIVATE)
"cookies", }
Context.MODE_PRIVATE
)
)
override fun loadAll(): List<Cookie> { override fun loadAll(): List<Cookie> {
val cookies: MutableList<Cookie> = ArrayList(sharedPreferences.all.size) val cookies: MutableList<Cookie> = ArrayList(sharedPreferences.all.size)

@ -16,6 +16,7 @@ import okhttp3.Request
import okio.IOException import okio.IOException
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koin.core.context.GlobalContext
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.local.PagesCache import org.koitharu.kotatsu.core.local.PagesCache
@ -231,7 +232,7 @@ class DownloadService : BaseService() {
private fun confirmDataTransfer(context: Context, callback: () -> Unit) { private fun confirmDataTransfer(context: Context, callback: () -> Unit) {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val settings = AppSettings(context) val settings = GlobalContext.get().get<AppSettings>()
if (cm.isActiveNetworkMetered && settings.isTrafficWarningEnabled) { if (cm.isActiveNetworkMetered && settings.isTrafficWarningEnabled) {
CheckBoxAlertDialog.Builder(context) CheckBoxAlertDialog.Builder(context)
.setTitle(R.string.warning) .setTitle(R.string.warning)

@ -12,6 +12,10 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.cursoradapter.widget.CursorAdapter import androidx.cursoradapter.widget.CursorAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@ -50,27 +54,35 @@ class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.MangaSuggestionsProvider" private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.MangaSuggestionsProvider"
private const val MODE = DATABASE_MODE_QUERIES private const val MODE = DATABASE_MODE_QUERIES
@JvmStatic
private val uri = Uri.Builder() private val uri = Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT) .scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY) .authority(AUTHORITY)
.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY) .appendPath(SearchManager.SUGGEST_URI_PATH_QUERY)
.build() .build()
@JvmStatic
private val projection = arrayOf("_id", SearchManager.SUGGEST_COLUMN_QUERY) private val projection = arrayOf("_id", SearchManager.SUGGEST_COLUMN_QUERY)
@JvmStatic fun saveQueryAsync(context: Context, query: String) {
GlobalScope.launch(Dispatchers.IO) {
saveQuery(context, query)
}
}
fun saveQuery(context: Context, query: String) { fun saveQuery(context: Context, query: String) {
runCatching {
SearchRecentSuggestions( SearchRecentSuggestions(
context, context,
AUTHORITY, AUTHORITY,
MODE MODE
).saveRecentQuery(query, null) ).saveRecentQuery(query, null)
}.onFailure {
if (BuildConfig.DEBUG) {
it.printStackTrace()
}
}
} }
@JvmStatic suspend fun clearHistory(context: Context) = withContext(Dispatchers.IO) {
fun clearHistory(context: Context) {
SearchRecentSuggestions( SearchRecentSuggestions(
context, context,
AUTHORITY, AUTHORITY,
@ -78,15 +90,15 @@ class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
).clearHistory() ).clearHistory()
} }
@JvmStatic suspend fun getItemsCount(context: Context) = withContext(Dispatchers.IO) {
fun getItemsCount(context: Context) = getCursor(context)?.use { it.count } ?: 0 getCursor(context)?.use { it.count } ?: 0
}
@JvmStatic
private fun getCursor(context: Context): Cursor? { private fun getCursor(context: Context): Cursor? {
return context.contentResolver?.query(uri, projection, null, arrayOf(""), null) return context.contentResolver?.query(uri, projection, null, arrayOf(""), null)
} }
@JvmStatic @Deprecated("Need async implementation")
fun getSuggestionAdapter(context: Context): CursorAdapter? = getCursor( fun getSuggestionAdapter(context: Context): CursorAdapter? = getCursor(
context context
)?.let { cursor -> )?.let { cursor ->
@ -102,6 +114,5 @@ class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
} }
} }
} }
} }
} }

@ -50,7 +50,7 @@ class SearchActivity : BaseActivity(), SearchView.OnQueryTextListener {
.replace(R.id.container, SearchFragment.newInstance(source, query)) .replace(R.id.container, SearchFragment.newInstance(source, query))
.commit() .commit()
searchView.clearFocus() searchView.clearFocus()
MangaSuggestionsProvider.saveQuery(this, query) MangaSuggestionsProvider.saveQueryAsync(applicationContext, query)
true true
} else false } else false
} }

@ -30,7 +30,7 @@ object SearchHelper {
override fun onQueryTextSubmit(query: String?): Boolean { override fun onQueryTextSubmit(query: String?): Boolean {
return if (!query.isNullOrBlank()) { return if (!query.isNullOrBlank()) {
context.startActivity(GlobalSearchActivity.newIntent(context, query.trim())) context.startActivity(GlobalSearchActivity.newIntent(context, query.trim()))
MangaSuggestionsProvider.saveQuery(context, query) MangaSuggestionsProvider.saveQueryAsync(context.applicationContext, query)
true true
} else false } else false
} }

@ -45,14 +45,18 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
pref.summary = FileSizeUtils.formatBytes(pref.context, size) pref.summary = FileSizeUtils.formatBytes(pref.context, size)
} }
} }
findPreference<Preference>(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { p -> findPreference<Preference>(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref ->
val items = MangaSuggestionsProvider.getItemsCount(p.context) viewLifecycleScope.launchWhenResumed {
p.summary = p.context.resources.getQuantityString(R.plurals.items, items, items) val items = MangaSuggestionsProvider.getItemsCount(pref.context)
pref.summary =
pref.context.resources.getQuantityString(R.plurals.items, items, items)
}
} }
findPreference<Preference>(AppSettings.KEY_UPDATES_FEED_CLEAR)?.let { p -> findPreference<Preference>(AppSettings.KEY_UPDATES_FEED_CLEAR)?.let { pref ->
viewLifecycleScope.launchWhenResumed { viewLifecycleScope.launchWhenResumed {
val items = trackerRepo.count() val items = trackerRepo.count()
p.summary = p.context.resources.getQuantityString(R.plurals.items, items, items) pref.summary =
pref.context.resources.getQuantityString(R.plurals.items, items, items)
} }
} }
} }
@ -68,14 +72,16 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
true true
} }
AppSettings.KEY_SEARCH_HISTORY_CLEAR -> { AppSettings.KEY_SEARCH_HISTORY_CLEAR -> {
viewLifecycleScope.launch {
MangaSuggestionsProvider.clearHistory(preference.context) MangaSuggestionsProvider.clearHistory(preference.context)
preference.summary = preference.context.resources preference.summary = preference.context.resources
.getQuantityString(R.plurals.items, 0, 0) .getQuantityString(R.plurals.items, 0, 0)
Snackbar.make( Snackbar.make(
view ?: return true, view ?: return@launch,
R.string.search_history_cleared, R.string.search_history_cleared,
Snackbar.LENGTH_SHORT Snackbar.LENGTH_SHORT
).show() ).show()
}
true true
} }
AppSettings.KEY_UPDATES_FEED_CLEAR -> { AppSettings.KEY_UPDATES_FEED_CLEAR -> {

@ -12,6 +12,8 @@ import java.io.File
object CacheUtils { object CacheUtils {
const val QUALIFIER_HTTP = "cache_http"
val CONTROL_DISABLED = CacheControl.Builder() val CONTROL_DISABLED = CacheControl.Builder()
.noStore() .noStore()
.build() .build()
@ -30,6 +32,7 @@ object CacheUtils {
.map { it.sub(name) } .map { it.sub(name) }
.forEach { it.deleteRecursively() } .forEach { it.deleteRecursively() }
// FIXME need async implementation
fun createHttpCache(context: Context): Cache { fun createHttpCache(context: Context): Cache {
val directory = (context.externalCacheDir ?: context.cacheDir).sub("http") val directory = (context.externalCacheDir ?: context.cacheDir).sub("http")
directory.mkdirs() directory.mkdirs()

@ -4,16 +4,18 @@ import android.content.Context
import android.view.View import android.view.View
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.utils.ext.measureWidth import org.koitharu.kotatsu.utils.ext.measureWidth
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.roundToInt import kotlin.math.roundToInt
object UiUtils { object UiUtils : KoinComponent {
fun resolveGridSpanCount(context: Context, width: Int = 0): Int { fun resolveGridSpanCount(context: Context, width: Int = 0): Int {
val scaleFactor = AppSettings(context).gridSize / 100f val scaleFactor = get<AppSettings>().gridSize / 100f
val cellWidth = context.resources.getDimension(R.dimen.preferred_grid_width) * scaleFactor val cellWidth = context.resources.getDimension(R.dimen.preferred_grid_width) * scaleFactor
val screenWidth = (if (width <= 0) { val screenWidth = (if (width <= 0) {
context.resources.displayMetrics.widthPixels context.resources.displayMetrics.widthPixels

Loading…
Cancel
Save