diff --git a/News-Android-App/build.gradle b/News-Android-App/build.gradle index 48422cda8..1d9105f1d 100644 --- a/News-Android-App/build.gradle +++ b/News-Android-App/build.gradle @@ -150,6 +150,7 @@ dependencies { implementation "com.github.bumptech.glide:glide:${GLIDE_VERSION}" ksp "com.github.bumptech.glide:ksp:${GLIDE_VERSION}" + implementation "com.github.bumptech.glide:okhttp3-integration:4.16.0" debugImplementation "com.github.technoir42:glide-debug-indicator:0.9.1" implementation 'com.caverock:androidsvg-aar:1.4' diff --git a/News-Android-App/proguard-rules.pro b/News-Android-App/proguard-rules.pro index fd1312a43..fd136bd9f 100644 --- a/News-Android-App/proguard-rules.pro +++ b/News-Android-App/proguard-rules.pro @@ -112,6 +112,8 @@ -keep,allowobfuscation,allowshrinking class io.reactivex.rxjava3.core.Observable -keep,allowobfuscation,allowshrinking class io.reactivex.rxjava3.core.Single +# glide +-keep class com.bumptech.glide.integration.okhttp.OkHttpGlideModule diff --git a/News-Android-App/src/main/AndroidManifest.xml b/News-Android-App/src/main/AndroidManifest.xml index 48d8e7368..d56a9d6f7 100644 --- a/News-Android-App/src/main/AndroidManifest.xml +++ b/News-Android-App/src/main/AndroidManifest.xml @@ -29,10 +29,15 @@ android:usesCleartextTraffic="true" tools:replace="android:icon, android:label, android:theme, android:name"> - - + + { String stringValue = value.toString(); - if (preference instanceof ListPreference) { + if (preference instanceof ListPreference listPreference) { // For list preferences, look up the correct display value in // the preference's 'entries' list. - ListPreference listPreference = (ListPreference) preference; int index = listPreference.findIndexOfValue(stringValue); // Set the summary to reflect the new value. @@ -158,8 +161,7 @@ else if(PREF_SYNC_SETTINGS.equals(preference.getKey())) { }; private static final Preference.OnPreferenceChangeListener sBindPreferenceBooleanToValueListener = (preference, newValue) -> { - if(preference instanceof CheckBoxPreference) { //For legacy Android support - CheckBoxPreference cbPreference = ((CheckBoxPreference) preference); + if(preference instanceof CheckBoxPreference cbPreference) { //For legacy Android support cbPreference.setChecked((Boolean) newValue); } else { TwoStatePreference twoStatePreference = ((TwoStatePreference) preference); @@ -262,12 +264,10 @@ private void migrateSyncIntervalValue() { // the list will show the default sync interval value of 15min // whereas the user may have configured some other value // once the user selects a value, this new value is actually used; and no more impact is expected - } private void bindDataSyncPreferences(final PreferenceFragmentCompat prefFrag) { - // handle the sync interval list: bindPreferenceSummaryToValue(prefFrag.findPreference(PREF_SYNC_SETTINGS)); @@ -317,13 +317,10 @@ private void bindPodcastPreferences(PreferenceFragmentCompat prefFrag) public void checkForUnsycedChangesInDatabaseAndResetDatabase(final Context context) { DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(context); - boolean resetDatabase = true; - if(dbConn.areThereAnyUnsavedChangesInDatabase()) { - resetDatabase = false; - } + boolean resetDatabase = !dbConn.areThereAnyUnsavedChangesInDatabase(); if(resetDatabase) { - new ResetDatabaseAsyncTask(context).execute(); + new ResetDatabaseAsyncTask(context, mOkHttpClient).execute(); } else { new AlertDialog.Builder(context) .setTitle(context.getString(R.string.warning)) @@ -335,7 +332,7 @@ public void onClick(DialogInterface dialog, int which) { PostDelayHandler pDelayHandler = new PostDelayHandler(context); pDelayHandler.stopRunningPostDelayHandler(); - new ResetDatabaseAsyncTask(context).execute(); + new ResetDatabaseAsyncTask(context, mOkHttpClient).execute(); } }) .setNegativeButton(context.getString(android.R.string.no), null) @@ -379,11 +376,7 @@ private void openBugReport() { } } - try { - body = URLEncoder.encode(debugInfo,"UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } + body = URLEncoder.encode(debugInfo, StandardCharsets.UTF_8); Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/nextcloud/news-android/issues/new?title=" + title + "&body=" + body)); startActivity(browserIntent); } @@ -418,8 +411,11 @@ public static class ResetDatabaseAsyncTask extends AsyncTask { private ProgressDialog pd; private final Context context; - public ResetDatabaseAsyncTask(Context context) { + private final OkHttpClient okHttpClient; + + public ResetDatabaseAsyncTask(Context context, OkHttpClient okHttpClient) { this.context = context; + this.okHttpClient = okHttpClient; } @Override @@ -440,7 +436,8 @@ protected Void doInBackground(Void... params) { DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(context); dbConn.resetDatabase(); - ImageHandler.clearCache(context); + ImageHandler.clearGlideCache(context); + ImageHandler.clearOkHttpCache(okHttpClient); NewsFileUtils.clearWebArchiveCache(context); NewsFileUtils.clearPodcastCache(context); return null; @@ -453,8 +450,7 @@ protected void onPostExecute(Void result) { pd.dismiss(); Toast.makeText(context, context.getString(R.string.cache_is_cleared), Toast.LENGTH_SHORT).show(); - if(context instanceof SettingsActivity) { - SettingsActivity sa = (SettingsActivity) context; + if(context instanceof SettingsActivity sa) { sa.resultIntent.putExtra(SettingsActivity.RI_CACHE_CLEARED, true); } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineThumbnailViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineThumbnailViewHolder.java index cba73b7d6..b26d4bb68 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineThumbnailViewHolder.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemHeadlineThumbnailViewHolder.java @@ -13,7 +13,6 @@ import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import com.bumptech.glide.load.MultiTransformation; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; @@ -94,7 +93,7 @@ public void bind(@NonNull RssItem rssItem) { mGlide .load(mediaThumbnail) - .diskCacheStrategy(DiskCacheStrategy.DATA) + // .diskCacheStrategy(DiskCacheStrategy.DATA) // use okhttp caching .placeholder(feedIcon) .error(feedIcon) .transform(new MultiTransformation<>(new CenterCrop(), new RoundedCorners(60))) diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java index 62225e5a3..19c4c40cf 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/adapter/RssItemThumbnailViewHolder.java @@ -15,7 +15,6 @@ import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import com.bumptech.glide.load.MultiTransformation; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; @@ -93,7 +92,7 @@ public void bind(@NonNull RssItem rssItem) { mGlide .load(mediaThumbnail) - .diskCacheStrategy(DiskCacheStrategy.DATA) + // .diskCacheStrategy(DiskCacheStrategy.DATA) // use okhttp caching .placeholder(feedIcon) .error(feedIcon) .transform(new MultiTransformation<>(new CenterCrop(), new RoundedCorners(60))) diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/DownloadImageHandler.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/DownloadImageHandler.java index 8def1ad4b..a2050888b 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/DownloadImageHandler.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/DownloadImageHandler.java @@ -25,7 +25,6 @@ import android.util.Log; import com.bumptech.glide.RequestManager; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import java.net.URL; import java.util.concurrent.ExecutionException; @@ -51,7 +50,7 @@ public void preloadSync(RequestManager glide) { Bitmap bm = glide .asBitmap() .load(mImageUrl.toString()) - .diskCacheStrategy(DiskCacheStrategy.DATA) + // .diskCacheStrategy(DiskCacheStrategy.DATA) // use okhttp cache .submit() .get(); NotifyDownloadFinished(bm); diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/RssItemToHtmlTask.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/RssItemToHtmlTask.java index a202b38d9..ec01a7d7a 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/RssItemToHtmlTask.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/async_tasks/RssItemToHtmlTask.java @@ -290,9 +290,10 @@ private static String getDescriptionWithCachedImages(RequestManager glide, Strin try { File file = null; try { + // TODO!!!! THIS CODE BELOW DOESN'T WORK WITH OKHTTP!! file = glide .asFile() - .diskCacheStrategy(DiskCacheStrategy.DATA) + // .diskCacheStrategy(DiskCacheStrategy.DATA) // TODO!! NOT WORKING .onlyRetrieveFromCache(true) // .listener(rl) .load(link) @@ -313,7 +314,7 @@ private static String getDescriptionWithCachedImages(RequestManager glide, Strin return text; } - private static RequestListener rl = new RequestListener<>() { + private static final RequestListener rl = new RequestListener<>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { // Log the GlideException here (locally or with a remote logging framework): diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiModule.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiModule.java index 1c62a6e51..3d86a39d1 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiModule.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiModule.java @@ -1,5 +1,8 @@ package de.luhmer.owncloudnewsreader.di; +import static de.luhmer.owncloudnewsreader.helper.NextcloudGlideModuleKt.CACHE_SIZE; +import static de.luhmer.owncloudnewsreader.helper.NextcloudGlideModuleKt.MB; + import android.app.Application; import android.content.Context; import android.content.SharedPreferences; @@ -13,6 +16,7 @@ import dagger.Module; import dagger.Provides; +import de.luhmer.owncloudnewsreader.SettingsActivity; import de.luhmer.owncloudnewsreader.helper.PostDelayHandler; import de.luhmer.owncloudnewsreader.helper.ThemeChooser; import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager; @@ -85,18 +89,36 @@ Gson provideGson() { @Provides @Singleton - OkHttpClient provideOkHttpClient(Cache cache) { - // setCache(cache); - return new OkHttpClient(); + PostDelayHandler providePostDelayHandler() { + return new PostDelayHandler(mApplication); } + @Provides @Singleton - PostDelayHandler providePostDelayHandler() { - return new PostDelayHandler(mApplication); + OkHttpClient provideOkHttpClient(SharedPreferences prefs) { + String cacheSize = prefs.getString(SettingsActivity.SP_MAX_CACHE_SIZE, String.valueOf(CACHE_SIZE)); + Long diskCacheSizeBytes = Long.valueOf(cacheSize) * MB; + + OkHttpClient.Builder client = new OkHttpClient.Builder() + .cache(new Cache(mApplication.getApplicationContext().getCacheDir(), diskCacheSizeBytes)); + /* + .addInterceptor(Interceptor { chain: Interceptor.Chain -> + val response = chain.proceed(chain.request()) + if (response.cacheResponse != null) { + Log.d("NextcloudGlideModule", "cached response: " + response.request.url) + } else if (response.networkResponse != null) { + Log.d("NextcloudGlideModule", "network response: " + response.request.url) + for (h in response.request.headers) { + Log.d("NextcloudGlideModule", "request headers: $h") + } + } + response + }) + */ + return client.build(); } - /* @Provides @Singleton diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/ImageHandler.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/ImageHandler.java index 2cd3a4ffe..090b46c59 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/ImageHandler.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/ImageHandler.java @@ -26,6 +26,7 @@ import com.bumptech.glide.Glide; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -33,6 +34,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import okhttp3.OkHttpClient; + public class ImageHandler { private static final String TAG = "[ImageHandler]"; private static final Pattern patternImg = Pattern.compile("]*>"); @@ -192,18 +195,27 @@ private static String sliceLastPathOfUrl(String url) { private static String getFileName(String url) { int idx = url.lastIndexOf("/"); int countOfSlashes = url.split("/").length - 1; - if(idx > 0) { + if (idx > 0) { return url.substring(idx); } else { return url; } } - public static void clearCache(Context context) - { + public static void clearGlideCache(Context context) { + Glide.get(context).clearMemory(); // needs to run on main thread new Thread(() -> { - Glide.get(context).clearMemory(); Glide.get(context).clearDiskCache(); }).start(); } + + public static void clearOkHttpCache(OkHttpClient okHttpClient) { + new Thread(() -> { + try { + okHttpClient.cache().evictAll(); + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/NextcloudGlideModule.kt b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/NextcloudGlideModule.kt index 2f4d264ad..710e86fd4 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/NextcloudGlideModule.kt +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/helper/NextcloudGlideModule.kt @@ -7,35 +7,51 @@ import com.bumptech.glide.Glide import com.bumptech.glide.GlideBuilder import com.bumptech.glide.Registry import com.bumptech.glide.annotation.GlideModule +import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader +import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory +import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.module.AppGlideModule +import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.samples.svg.SvgDecoder import com.bumptech.glide.samples.svg.SvgDrawableTranscoder import com.caverock.androidsvg.SVG import de.luhmer.owncloudnewsreader.NewsReaderApplication -import de.luhmer.owncloudnewsreader.SettingsActivity import de.luhmer.owncloudnewsreader.di.ApiProvider +import okhttp3.OkHttpClient import java.io.InputStream import javax.inject.Inject -private const val CACHE_SIZE = 500 +const val CACHE_SIZE = 500 -private const val KB = 1024 -private const val MB = 1024 * KB +const val KB = 1024 +const val MB = 1024 * KB @GlideModule class NextcloudGlideModule : AppGlideModule() { @Inject - lateinit var mApi: ApiProvider + lateinit var api: ApiProvider @Inject - lateinit var mPrefs: SharedPreferences + lateinit var prefs: SharedPreferences + + @Inject + lateinit var okHttpClient: OkHttpClient override fun applyOptions(context: Context, builder: GlideBuilder) { super.applyOptions(context, builder) (context.applicationContext as NewsReaderApplication).appComponent.injectGlideModule(this) - val cacheSize = mPrefs.getString(SettingsActivity.SP_MAX_CACHE_SIZE, CACHE_SIZE.toString()) + builder.setDefaultRequestOptions( + // caching is handled by OkHttp + RequestOptions().diskCacheStrategy(DiskCacheStrategy.NONE) + ) + + // glide cache is only used for favicons - thus is should only be around 10MB in size + builder.setDiskCache(InternalCacheDiskCacheFactory(context, (10 * MB).toLong())) + + /* + val cacheSize = prefs.getString(SettingsActivity.SP_MAX_CACHE_SIZE, CACHE_SIZE.toString()) val diskCacheSizeBytes = (cacheSize?.toInt() ?: CACHE_SIZE) * MB // Glide uses DiskLruCacheWrapper as the default DiskCache. DiskLruCacheWrapper is a fixed @@ -54,6 +70,7 @@ class NextcloudGlideModule : AppGlideModule() { // Drawable::class.java, // DrawableTransitionOptions.with(DebugIndicatorTransitionFactory.DEFAULT) // ) + */ } override fun registerComponents(context: Context, glide: Glide, registry: Registry) { @@ -61,5 +78,11 @@ class NextcloudGlideModule : AppGlideModule() { registry .register(SVG::class.java, PictureDrawable::class.java, SvgDrawableTranscoder()) .append(InputStream::class.java, SVG::class.java, SvgDecoder()) + + registry.replace( + GlideUrl::class.java, + InputStream::class.java, + OkHttpUrlLoader.Factory(okHttpClient) + ) } }