From 3abce4c597bc74b95d9cbdb88e2bf3671047c811 Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Tue, 18 Aug 2015 17:38:51 +0200 Subject: [PATCH] Load feed media size on demand --- app/build.gradle | 7 ++ .../java/de/danoeh/antennapod/PodcastApp.java | 2 - .../antennapod/adapter/AdapterUtils.java | 21 +++++- .../adapter/AllEpisodesListAdapter.java | 16 ++++- .../adapter/FeedItemlistAdapter.java | 21 ++---- .../antennapod/adapter/QueueListAdapter.java | 15 +++- build.gradle | 3 +- core/build.gradle | 6 +- core/src/main/AndroidManifest.xml | 3 - .../core/service/FeedMediaSizeService.java | 64 ----------------- .../antennapod/core/storage/DBReader.java | 23 ------- .../antennapod/core/storage/DBTasks.java | 8 --- .../antennapod/core/storage/PodDBAdapter.java | 7 -- .../antennapod/core/util/NetworkUtils.java | 68 +++++++++++++++++++ 14 files changed, 133 insertions(+), 131 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/service/FeedMediaSizeService.java diff --git a/app/build.gradle b/app/build.gradle index cd6fbd354..77a1cebba 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ import org.apache.tools.ant.filters.ReplaceTokens apply plugin: 'com.android.application' +apply plugin: 'me.tatarka.retrolambda' repositories { mavenCentral() @@ -22,6 +23,7 @@ dependencies { compile 'com.squareup.okio:okio:1.2.0' compile 'de.greenrobot:eventbus:2.4.0' compile 'com.joanzapata.android:android-iconify:1.0.9' + compile 'io.reactivex:rxandroid:1.0.1' compile project(':core') compile project(':library:drag-sort-listview') @@ -108,6 +110,11 @@ android { lintOptions { abortOnError false } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } // about.html is templatized so that we can automatically insert diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java index e7283d860..026e3b087 100644 --- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java +++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java @@ -44,8 +44,6 @@ public class PodcastApp extends Application { EventDistributor.getInstance(); SPAUtil.sendSPAppsQueryFeedsIntent(this); - - // startService(new Intent(this, FeedMediaSizeService.class)); } public static float getLogicalDensity() { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java index d3ee08546..e03a4cc7a 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java @@ -1,19 +1,23 @@ package de.danoeh.antennapod.adapter; -import android.content.res.Resources; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; +import com.joanzapata.android.iconify.Iconify; + import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.NetworkUtils; /** * Utility methods for adapters */ public class AdapterUtils { + private static final String TAG = AdapterUtils.class.getSimpleName(); + private AdapterUtils() { } @@ -21,7 +25,7 @@ public class AdapterUtils { /** * Updates the contents of the TextView that shows the current playback position and the ProgressBar. */ - public static void updateEpisodePlaybackProgress(FeedItem item, Resources res, TextView txtvPos, ProgressBar episodeProgress) { + public static void updateEpisodePlaybackProgress(FeedItem item, TextView txtvPos, ProgressBar episodeProgress) { FeedMedia media = item.getMedia(); episodeProgress.setVisibility(View.GONE); if (media == null) { @@ -42,8 +46,19 @@ public class AdapterUtils { - media.getPosition())); } } else if (!media.isDownloaded()) { - if(media.getSize() > 0) { + if (media.getSize() > 0) { txtvPos.setText(Converter.byteToString(media.getSize())); + } else if(media.getSize() > Integer.MIN_VALUE) { + txtvPos.setText("{fa-spinner}"); + Iconify.addIcons(txtvPos); + NetworkUtils.getFeedMediaSizeObservable(media) + .subscribe(size -> { + if (size > 0) { + txtvPos.setText(Converter.byteToString(size)); + } else { + txtvPos.setText(""); + } + }); } else { txtvPos.setText(""); } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java index 4b6ee8f91..274a4652c 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java @@ -14,10 +14,10 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.GlideDrawableImageViewTarget; +import com.joanzapata.android.iconify.Iconify; import java.lang.ref.WeakReference; @@ -27,12 +27,15 @@ import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.NetworkUtils; /** * List adapter for the list of new episodes */ public class AllEpisodesListAdapter extends BaseAdapter { + private static final String TAG = AllEpisodesListAdapter.class.getSimpleName(); + private final Context context; private final ItemAccess itemAccess; private final ActionButtonCallback actionButtonCallback; @@ -117,6 +120,17 @@ public class AllEpisodesListAdapter extends BaseAdapter { holder.txtvDuration.setText(Converter.getDurationStringLong(media.getDuration())); } else if (media.getSize() > 0) { holder.txtvDuration.setText(Converter.byteToString(media.getSize())); + } else if(media.getSize() > Integer.MIN_VALUE) { + holder.txtvDuration.setText("{fa-spinner}"); + Iconify.addIcons(holder.txtvDuration); + NetworkUtils.getFeedMediaSizeObservable(media) + .subscribe(size -> { + if (size > 0) { + holder.txtvDuration.setText(Converter.byteToString(size)); + } else { + holder.txtvDuration.setText(""); + } + }); } else { holder.txtvDuration.setText(""); } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java index 56e2bb1bd..507d1adbc 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -91,7 +91,7 @@ public class FeedItemlistAdapter extends BaseAdapter { holder.inPlaylist = (ImageView) convertView .findViewById(R.id.imgvInPlaylist); holder.type = (ImageView) convertView.findViewById(R.id.imgvType); - holder.statusUnread = (View) convertView + holder.statusUnread = convertView .findViewById(R.id.statusUnread); holder.episodeProgress = (ProgressBar) convertView .findViewById(R.id.pbar_episode_progress); @@ -100,6 +100,7 @@ public class FeedItemlistAdapter extends BaseAdapter { } else { holder = (Holder) convertView.getTag(); } + if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) { convertView.setVisibility(View.VISIBLE); if (position == selectedItemIndex) { @@ -139,18 +140,17 @@ public class FeedItemlistAdapter extends BaseAdapter { holder.lenSize.setVisibility(View.INVISIBLE); } else { - AdapterUtils.updateEpisodePlaybackProgress(item, context.getResources(), holder.lenSize, holder.episodeProgress); + AdapterUtils.updateEpisodePlaybackProgress(item, holder.lenSize, holder.episodeProgress); - if (((ItemAccess) itemAccess).isInQueue(item)) { + if (itemAccess.isInQueue(item)) { holder.inPlaylist.setVisibility(View.VISIBLE); } else { holder.inPlaylist.setVisibility(View.INVISIBLE); } - if (DownloadRequester.getInstance().isDownloadingFile( - item.getMedia())) { + if (DownloadRequester.getInstance().isDownloadingFile(item.getMedia())) { holder.episodeProgress.setVisibility(View.VISIBLE); - holder.episodeProgress.setProgress(((ItemAccess) itemAccess).getItemDownloadProgressPercent(item)); + holder.episodeProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item)); } else { if(media.getPosition() == 0) { holder.episodeProgress.setVisibility(View.GONE); @@ -206,15 +206,6 @@ public class FeedItemlistAdapter extends BaseAdapter { ProgressBar episodeProgress; } - public int getSelectedItemIndex() { - return selectedItemIndex; - } - - public void setSelectedItemIndex(int selectedItemIndex) { - this.selectedItemIndex = selectedItemIndex; - notifyDataSetChanged(); - } - public interface ItemAccess { boolean isInQueue(FeedItem item); diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java index 60c125fda..ac52c7674 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java @@ -4,7 +4,6 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.format.DateUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,10 +14,10 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.GlideDrawableImageViewTarget; +import com.joanzapata.android.iconify.Iconify; import java.lang.ref.WeakReference; @@ -29,6 +28,7 @@ import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.NetworkUtils; /** * List adapter for the queue. @@ -143,6 +143,17 @@ public class QueueListAdapter extends BaseAdapter { } else { if(media.getSize() > 0) { holder.progressLeft.setText(Converter.byteToString(media.getSize())); + } else if(media.getSize() > Integer.MIN_VALUE) { + holder.progressLeft.setText("{fa-spinner}"); + Iconify.addIcons(holder.progressLeft); + NetworkUtils.getFeedMediaSizeObservable(media) + .subscribe(size -> { + if (size > 0) { + holder.progressLeft.setText(Converter.byteToString(size)); + } else { + holder.progressLeft.setText(""); + } + }); } else { holder.progressLeft.setText(""); } diff --git a/build.gradle b/build.gradle index 363f02283..9f8861d13 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,8 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'me.tatarka:gradle-retrolambda:3.2.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/core/build.gradle b/core/build.gradle index 5e721bbc3..14667ba37 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.library' +apply plugin: 'me.tatarka.retrolambda' android { compileSdkVersion 21 @@ -25,8 +26,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } } @@ -49,4 +50,5 @@ dependencies { compile 'com.squareup.okio:okio:1.2.0' compile 'com.nineoldandroids:library:2.4.0' compile 'de.greenrobot:eventbus:2.4.0' + compile 'io.reactivex:rxandroid:1.0.1' } diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index 17dcb4ad8..3ec519844 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -23,9 +23,6 @@ - list = DBReader.getFeedMediaUnknownSize(this); -// for (FeedMedia media : list) { -// Log.d(TAG, "Getting size currently " + media.getSize() + " for " + media.getDownload_url()); -// if(false == NetworkUtils.isDownloadAllowed()) { -// return; -// } -// long size = Integer.MIN_VALUE; -// if (media.isDownloaded()) { -// File mediaFile = new File(media.getLocalMediaUrl()); -// if(mediaFile.exists()) { -// size = mediaFile.length(); -// } -// } else if (false == media.checkedOnSizeButUnknown()) { -// // only query the network if we haven't already checked -// HttpURLConnection conn = null; -// try { -// URL url = new URL(media.getDownload_url()); -// conn = (HttpURLConnection) url.openConnection(); -// conn.setRequestProperty("Accept-Encoding", ""); -// conn.setRequestMethod("HEAD"); -// size = conn.getContentLength(); -// } catch (IOException e) { -// Log.d(TAG, media.getDownload_url()); -// e.printStackTrace(); -// } finally { -// if (conn != null) { -// conn.disconnect(); -// } -// } -// } -// if (size <= 0) { -// // they didn't tell us the size, but we don't want to keep querying on it -// media.setCheckedOnSizeButUnknown(); -// } else { -// media.setSize(size); -// } -// Log.d(TAG, "Size now: " + media.getSize()); -// DBWriter.setFeedMedia(this, media); -// EventBus.getDefault().post(FeedMediaEvent.update(media)); -// } - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 5ed0a6ee3..86e788c7a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -521,29 +521,6 @@ public final class DBReader { return itemIds; } - /** - * Loads FeedMedia whose file size is unknown - * - * @param context A context that is used for opening a database connection. - * @return A list of FeedMedia items whose size is 0 (unknown and never tried to - * determine the correct size) - */ - public static List getFeedMediaUnknownSize(Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor cursor = adapter.getFeedMediaUnknownSizeCursor(); - List result = new ArrayList<>(cursor.getCount()); - if (cursor.moveToFirst()) { - do { - FeedMedia media = extractFeedMediaFromCursorRow(cursor); - result.add(media); - } while (cursor.moveToNext()); - } - cursor.close(); - return result; - } - - /** * Loads a list of FeedItems sorted by pubDate in descending order. * diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index 6ced03c0e..5a3822a81 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -5,9 +5,6 @@ import android.content.Intent; import android.database.Cursor; import android.util.Log; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -28,11 +25,8 @@ import de.danoeh.antennapod.core.asynctask.FlattrClickWorker; import de.danoeh.antennapod.core.asynctask.FlattrStatusFetcher; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.feed.FeedImage; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.service.FeedMediaSizeService; import de.danoeh.antennapod.core.service.GpodnetSyncService; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.service.playback.PlaybackService; @@ -578,8 +572,6 @@ public final class DBTasks { EventDistributor.getInstance().sendFeedUpdateBroadcast(); - // context.startService(new Intent(context, FeedMediaSizeService.class)); - return resultFeeds; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index edb7598ab..c14365911 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -1110,13 +1110,6 @@ public class PodDBAdapter { return db.rawQuery(query, null); } - public final Cursor getFeedMediaUnknownSizeCursor() { - final String query = "SELECT * " - + " FROM " + TABLE_NAME_FEED_MEDIA - + " WHERE " + KEY_SIZE + "<= 0"; - return db.rawQuery(query, null); - } - /** * Returns a cursor which contains all items of a feed that are considered new. * The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection. diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java index 9296039f0..1b57baa11 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java @@ -7,10 +7,23 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.util.Log; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.List; +import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; +import de.danoeh.antennapod.core.storage.DBWriter; +import rx.Observable; +import rx.Subscriber; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; public class NetworkUtils { @@ -78,4 +91,59 @@ public class NetworkUtils { return mWifi.isConnected(); } + public static Observable getFeedMediaSizeObservable(FeedMedia media) { + return Observable.create(new Observable.OnSubscribe() { + @Override + public void call(Subscriber subscriber) { + if (false == NetworkUtils.isDownloadAllowed()) { + subscriber.onNext(0L); + subscriber.onCompleted(); + return; + } + long size = Integer.MIN_VALUE; + if (media.isDownloaded()) { + File mediaFile = new File(media.getLocalMediaUrl()); + if (mediaFile.exists()) { + size = mediaFile.length(); + } + } else if (false == media.checkedOnSizeButUnknown()) { + // only query the network if we haven't already checked + OkHttpClient client = AntennapodHttpClient.getHttpClient(); + Request.Builder httpReq = new Request.Builder() + .url(media.getDownload_url()) + .header("Accept-Encoding", "identity") + .head(); + try { + Response response = client.newCall(httpReq.build()).execute(); + if (response.isSuccessful()) { + String contentLength = response.header("Content-Length"); + try { + size = Integer.parseInt(contentLength); + } catch (NumberFormatException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } + } + } catch (IOException e) { + subscriber.onNext(0L); + subscriber.onCompleted(); + Log.e(TAG, Log.getStackTraceString(e)); + return; // better luck next time + } + } + Log.d(TAG, "new size: " + size); + if (size <= 0) { + // they didn't tell us the size, but we don't want to keep querying on it + media.setCheckedOnSizeButUnknown(); + } else { + media.setSize(size); + } + subscriber.onNext(size); + subscriber.onCompleted(); + DBWriter.setFeedMedia(context, media); + } + }) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()); + } + }