From 26e47b9efd5e82a02e2ea80ee16f0c0180be37ae Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 15 Sep 2019 23:47:57 +0200 Subject: Converted FeedInfo Activity to fragment --- app/src/main/AndroidManifest.xml | 5 - .../antennapod/activity/FeedInfoActivity.java | 225 -------------------- .../antennapod/fragment/FeedInfoFragment.java | 231 +++++++++++++++++++++ .../antennapod/fragment/FeedItemlistFragment.java | 6 +- 4 files changed, 232 insertions(+), 235 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java create mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 73af654e9..8e5c4c921 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -105,11 +105,6 @@ android:value="de.danoeh.antennapod.activity.MainActivity"/> - - - ) emitter -> { - Feed feed = DBReader.getFeed(feedId); - if (feed != null) { - emitter.onSuccess(feed); - } else { - emitter.onComplete(); - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - feed = result; - Log.d(TAG, "Language is " + feed.getLanguage()); - Log.d(TAG, "Author is " + feed.getAuthor()); - Log.d(TAG, "URL is " + feed.getDownload_url()); - Glide.with(FeedInfoActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(imgvCover); - Glide.with(FeedInfoActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.image_readability_tint) - .error(R.color.image_readability_tint) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .transform(new FastBlurTransformation()) - .dontAnimate()) - .into(imgvBackground); - - txtvTitle.setText(feed.getTitle()); - - String description = feed.getDescription(); - if(description != null) { - if(Feed.TYPE_ATOM1.equals(feed.getType())) { - HtmlToPlainText formatter = new HtmlToPlainText(); - Document feedDescription = Jsoup.parse(feed.getDescription()); - description = StringUtils.trim(formatter.getPlainText(feedDescription)); - } - } else { - description = ""; - } - txtvDescription.setText(description); - - if (!TextUtils.isEmpty(feed.getAuthor())) { - txtvAuthor.setText(feed.getAuthor()); - txtvAuthorHeader.setText(feed.getAuthor()); - } else { - lblAuthor.setVisibility(View.GONE); - txtvAuthor.setVisibility(View.GONE); - } - if (!TextUtils.isEmpty(feed.getLanguage())) { - txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage())); - } else { - lblLanguage.setVisibility(View.GONE); - txtvLanguage.setVisibility(View.GONE); - } - txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}"); - Iconify.addIcons(txtvUrl); - - supportInvalidateOptionsMenu(); - }, error -> { - Log.d(TAG, Log.getStackTraceString(error)); - finish(); - }, () -> { - Log.e(TAG, "Activity was started with invalid arguments"); - finish(); - }); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (disposable != null) { - disposable.dispose(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.feedinfo, menu); - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null); - menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null && - IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink())))); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - default: - try { - return FeedMenuHandler.onOptionsItemClicked(this, item, feed); - } catch (DownloadRequestException e) { - e.printStackTrace(); - DownloadRequestErrorDialogCreator.newRequestErrorDialog(this, - e.getMessage()); - } - return super.onOptionsItemSelected(item); - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java new file mode 100644 index 000000000..c9f044aa6 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java @@ -0,0 +1,231 @@ +package de.danoeh.antennapod.fragment; + +import android.content.ClipData; +import android.content.Context; +import android.content.Intent; +import android.graphics.LightingColorFilter; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.joanzapata.iconify.Iconify; + +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.glide.ApGlideSettings; +import de.danoeh.antennapod.core.glide.FastBlurTransformation; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DownloadRequestException; +import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.LangUtils; +import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; +import de.danoeh.antennapod.menuhandler.FeedMenuHandler; +import io.reactivex.Maybe; +import io.reactivex.MaybeOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * Displays information about a feed. + */ +public class FeedInfoFragment extends Fragment { + + private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; + private static final String TAG = "FeedInfoActivity"; + private Feed feed; + + private ImageView imgvCover; + private TextView txtvTitle; + private TextView txtvDescription; + private TextView lblLanguage; + private TextView txtvLanguage; + private TextView lblAuthor; + private TextView txtvAuthor; + private TextView txtvUrl; + private TextView txtvAuthorHeader; + private ImageView imgvBackground; + + private Disposable disposable; + + public static FeedInfoFragment newInstance(Feed feed) { + FeedInfoFragment fragment = new FeedInfoFragment(); + Bundle arguments = new Bundle(); + arguments.putLong(EXTRA_FEED_ID, feed.getId()); + fragment.setArguments(arguments); + return fragment; + } + + private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() { + @Override + public void onClick(View v) { + if(feed != null && feed.getDownload_url() != null) { + String url = feed.getDownload_url(); + ClipData clipData = ClipData.newPlainText(url, url); + android.content.ClipboardManager cm = (android.content.ClipboardManager) getContext() + .getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(clipData); + Toast t = Toast.makeText(getContext(), R.string.copied_url_msg, Toast.LENGTH_SHORT); + t.show(); + } + } + }; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.feedinfo, null); + long feedId = getArguments().getLong(EXTRA_FEED_ID, -1); + setHasOptionsMenu(true); + + imgvCover = root.findViewById(R.id.imgvCover); + txtvTitle = root.findViewById(R.id.txtvTitle); + txtvAuthorHeader = root.findViewById(R.id.txtvAuthor); + imgvBackground = root.findViewById(R.id.imgvBackground); + root.findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE); + root.findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE); + // https://github.com/bumptech/glide/issues/529 + imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000)); + + + txtvDescription = root.findViewById(R.id.txtvDescription); + lblLanguage = root.findViewById(R.id.lblLanguage); + txtvLanguage = root.findViewById(R.id.txtvLanguage); + lblAuthor = root.findViewById(R.id.lblAuthor); + txtvAuthor = root.findViewById(R.id.txtvDetailsAuthor); + txtvUrl = root.findViewById(R.id.txtvUrl); + + txtvUrl.setOnClickListener(copyUrlToClipboard); + + disposable = Maybe.create((MaybeOnSubscribe) emitter -> { + Feed feed = DBReader.getFeed(feedId); + if (feed != null) { + emitter.onSuccess(feed); + } else { + emitter.onComplete(); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + feed = result; + showFeed(); + }, error -> { + Log.d(TAG, Log.getStackTraceString(error)); + }, () -> { + Log.e(TAG, "Activity was started with invalid arguments"); + }); + + return root; + } + + private void showFeed() { + Log.d(TAG, "Language is " + feed.getLanguage()); + Log.d(TAG, "Author is " + feed.getAuthor()); + Log.d(TAG, "URL is " + feed.getDownload_url()); + Glide.with(getContext()) + .load(feed.getImageLocation()) + .apply(new RequestOptions() + .placeholder(R.color.light_gray) + .error(R.color.light_gray) + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .fitCenter() + .dontAnimate()) + .into(imgvCover); + Glide.with(getContext()) + .load(feed.getImageLocation()) + .apply(new RequestOptions() + .placeholder(R.color.image_readability_tint) + .error(R.color.image_readability_tint) + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .transform(new FastBlurTransformation()) + .dontAnimate()) + .into(imgvBackground); + + txtvTitle.setText(feed.getTitle()); + + String description = feed.getDescription(); + if(description != null) { + if(Feed.TYPE_ATOM1.equals(feed.getType())) { + HtmlToPlainText formatter = new HtmlToPlainText(); + Document feedDescription = Jsoup.parse(feed.getDescription()); + description = StringUtils.trim(formatter.getPlainText(feedDescription)); + } + } else { + description = ""; + } + txtvDescription.setText(description); + + if (!TextUtils.isEmpty(feed.getAuthor())) { + txtvAuthor.setText(feed.getAuthor()); + txtvAuthorHeader.setText(feed.getAuthor()); + } else { + lblAuthor.setVisibility(View.GONE); + txtvAuthor.setVisibility(View.GONE); + } + if (!TextUtils.isEmpty(feed.getLanguage())) { + txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage())); + } else { + lblLanguage.setVisibility(View.GONE); + txtvLanguage.setVisibility(View.GONE); + } + txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}"); + Iconify.addIcons(txtvUrl); + + getActivity().invalidateOptionsMenu(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (disposable != null) { + disposable.dispose(); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.feedinfo, menu); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null); + menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null && + IntentUtils.isCallable(getContext(), new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink())))); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + boolean handled = false; + try { + handled = FeedMenuHandler.onOptionsItemClicked(getContext(), item, feed); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(getContext(), e.getMessage()); + } + return handled || super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 4e4b40096..93a026669 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -37,7 +37,6 @@ import org.greenrobot.eventbus.ThreadMode; import java.util.List; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.FeedInfoActivity; import de.danoeh.antennapod.activity.FeedSettingsActivity; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.FeedItemlistAdapter; @@ -517,10 +516,7 @@ public class FeedItemlistFragment extends ListFragment { private void showFeedInfo() { if (feed != null) { - Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); - startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, - feed.getId()); - startActivity(startIntent); + ((MainActivity) getActivity()).loadChildFragment(FeedInfoFragment.newInstance(feed)); } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From f17737e9872a5382771879f21a88eb7ecb8f83f6 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Mon, 16 Sep 2019 00:07:35 +0200 Subject: Added card flip animation to feed info fragment --- .../danoeh/antennapod/activity/MainActivity.java | 26 ++++++++++++++++++---- .../antennapod/fragment/FeedItemlistFragment.java | 3 ++- .../antennapod/fragment/TransitionEffect.java | 5 +++++ app/src/main/res/anim/card_flip_left_in.xml | 25 +++++++++++++++++++++ app/src/main/res/anim/card_flip_left_out.xml | 18 +++++++++++++++ app/src/main/res/anim/card_flip_right_in.xml | 25 +++++++++++++++++++++ app/src/main/res/anim/card_flip_right_out.xml | 18 +++++++++++++++ app/src/main/res/values/integers.xml | 5 +++++ 8 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java create mode 100644 app/src/main/res/anim/card_flip_left_in.xml create mode 100644 app/src/main/res/anim/card_flip_left_out.xml create mode 100644 app/src/main/res/anim/card_flip_right_in.xml create mode 100644 app/src/main/res/anim/card_flip_right_out.xml create mode 100644 app/src/main/res/values/integers.xml diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java index 339ce01c2..a35c0eaad 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -32,6 +32,7 @@ import android.widget.Toast; import com.bumptech.glide.Glide; +import de.danoeh.antennapod.fragment.TransitionEffect; import de.danoeh.antennapod.preferences.PreferenceUpgrader; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.Validate; @@ -368,15 +369,32 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi } } - public void loadChildFragment(Fragment fragment) { + public void loadChildFragment(Fragment fragment, TransitionEffect transition) { Validate.notNull(fragment); - FragmentManager fm = getSupportFragmentManager(); - fm.beginTransaction() - .replace(R.id.main_view, fragment, "main") + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + + switch (transition) { + case FADE: + transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); + break; + case FLIP: + transaction.setCustomAnimations( + R.anim.card_flip_right_in, + R.anim.card_flip_right_out, + R.anim.card_flip_left_in, + R.anim.card_flip_left_out); + break; + } + + transaction.replace(R.id.main_view, fragment, "main") .addToBackStack(null) .commit(); } + public void loadChildFragment(Fragment fragment) { + loadChildFragment(fragment, TransitionEffect.NONE); + } + public void dismissChildFragment() { getSupportFragmentManager().popBackStack(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 93a026669..ad08cfb23 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -516,7 +516,8 @@ public class FeedItemlistFragment extends ListFragment { private void showFeedInfo() { if (feed != null) { - ((MainActivity) getActivity()).loadChildFragment(FeedInfoFragment.newInstance(feed)); + FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed); + ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java new file mode 100644 index 000000000..461fa9da3 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java @@ -0,0 +1,5 @@ +package de.danoeh.antennapod.fragment; + +public enum TransitionEffect { + NONE, FLIP, FADE +} diff --git a/app/src/main/res/anim/card_flip_left_in.xml b/app/src/main/res/anim/card_flip_left_in.xml new file mode 100644 index 000000000..0ffc85aec --- /dev/null +++ b/app/src/main/res/anim/card_flip_left_in.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/card_flip_left_out.xml b/app/src/main/res/anim/card_flip_left_out.xml new file mode 100644 index 000000000..817f0d3fc --- /dev/null +++ b/app/src/main/res/anim/card_flip_left_out.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/card_flip_right_in.xml b/app/src/main/res/anim/card_flip_right_in.xml new file mode 100644 index 000000000..31ff1dde5 --- /dev/null +++ b/app/src/main/res/anim/card_flip_right_in.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/card_flip_right_out.xml b/app/src/main/res/anim/card_flip_right_out.xml new file mode 100644 index 000000000..b57113fea --- /dev/null +++ b/app/src/main/res/anim/card_flip_right_out.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml new file mode 100644 index 000000000..8c444ee8b --- /dev/null +++ b/app/src/main/res/values/integers.xml @@ -0,0 +1,5 @@ + + + 400 + 200 + \ No newline at end of file -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From e89f1733267124c26b6f998d5fb6c759fd999fbb Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Mon, 16 Sep 2019 00:11:33 +0200 Subject: Setting title --- .../main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java index c9f044aa6..c37d1e3eb 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java @@ -25,6 +25,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import com.joanzapata.iconify.Iconify; +import de.danoeh.antennapod.activity.MainActivity; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -91,6 +92,12 @@ public class FeedInfoFragment extends Fragment { } }; + @Override + public void onResume() { + super.onResume(); + ((MainActivity)getActivity()).getSupportActionBar().setTitle(R.string.feed_info_label); + } + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 667be71e0f34c4c93ccb5a7559d7026b1e5b0fe5 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 24 Sep 2019 18:07:43 +0200 Subject: Speed up circleci by allowing different flavours to build in parallel --- .circleci/config.yml | 74 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a4db1befd..b6a6ba78e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,49 +1,77 @@ version: 2 jobs: - test: + test-debug: docker: - image: circleci/android:api-28 - working_directory: ~/AntennaPod - environment: GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx1536m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError"' _JAVA_OPTIONS: "-Xms256m -Xmx1280m" - steps: - checkout - - restore_cache: keys: - v1-android-{{ checksum "build.gradle" }} - # fallback to using the latest cache if no exact match is found - v1-android- - - - run: - name: Create temporary release keystore - command: keytool -noprompt -genkey -v -keystore "app/keystore" -alias alias -storepass password -keypass password -keyalg RSA -validity 10 -dname "CN=antennapod.org, OU=dummy, O=dummy, L=dummy, S=dummy, C=US" - - run: name: Build debug command: ./gradlew assembleDebug -PdisablePreDex + - run: + name: Execute debug unit tests + command: ./gradlew :core:testPlayDebugUnitTest -PdisablePreDex + - save_cache: + paths: + - ~/.android + - ~/.gradle + - ~/android + key: v1-android-{{ checksum "build.gradle" }} + test-release: + docker: + - image: circleci/android:api-28 + working_directory: ~/AntennaPod + environment: + GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx1536m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError"' + _JAVA_OPTIONS: "-Xms256m -Xmx1280m" + steps: + - checkout + - restore_cache: + keys: + - v1-android-{{ checksum "build.gradle" }} + - v1-android- + - run: + name: Create temporary release keystore + command: keytool -noprompt -genkey -v -keystore "app/keystore" -alias alias -storepass password -keypass password -keyalg RSA -validity 10 -dname "CN=antennapod.org, OU=dummy, O=dummy, L=dummy, S=dummy, C=US" - run: name: Build release command: ./gradlew assembleRelease -PdisablePreDex - - run: - name: Execute unit tests + name: Execute release unit tests command: ./gradlew :core:testPlayReleaseUnitTest -PdisablePreDex + - save_cache: + paths: + - ~/.android + - ~/.gradle + - ~/android + key: v1-android-{{ checksum "build.gradle" }} + build-androidtest: + docker: + - image: circleci/android:api-28 + working_directory: ~/AntennaPod + environment: + GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx1536m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError"' + _JAVA_OPTIONS: "-Xms256m -Xmx1280m" + steps: + - checkout + - restore_cache: + keys: + - v1-android-{{ checksum "build.gradle" }} + - v1-android- - run: name: Build integration tests command: ./gradlew :app:assemblePlayDebugAndroidTest -PdisablePreDex - - - store_artifacts: - path: app/build/outputs/apk - destination: apks - - save_cache: paths: - ~/.android @@ -55,10 +83,8 @@ jobs: docker: - image: circleci/android:api-28 working_directory: ~/AntennaPod - steps: - checkout - - run: name: Checkstyle command: ./gradlew checkstyle @@ -66,10 +92,12 @@ jobs: workflows: version: 2 - test: + unit-tests: jobs: - - test + - test-debug + - test-release + - build-androidtest - checkstyle: + static-analysis: jobs: - checkstyle -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 907867652f94cdaad11d02a54cd39da8996ba213 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 31 Aug 2019 16:10:07 -0700 Subject: Refactor automatic feed update - remove extra threads no longer necessary. --- .../core/receiver/FeedUpdateReceiver.java | 6 ++-- .../antennapod/core/service/FeedUpdateWorker.java | 26 +++++++++++++--- .../antennapod/core/util/FeedUpdateUtils.java | 36 ---------------------- .../core/util/download/AutoUpdateManager.java | 24 +++++++++++++-- 4 files changed, 46 insertions(+), 46 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java index 126f12247..cc5f49dc1 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java @@ -6,8 +6,7 @@ import android.content.Intent; import android.util.Log; import de.danoeh.antennapod.core.ClientConfig; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.util.FeedUpdateUtils; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; /** * Refreshes all feeds when it receives an intent @@ -20,7 +19,8 @@ public class FeedUpdateReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.d(TAG, "Received intent"); ClientConfig.initialize(context); - FeedUpdateUtils.startAutoUpdate(context, null); + + AutoUpdateManager.runImmediate(); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java index efdb96dc1..f551ffa39 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java @@ -2,17 +2,26 @@ package de.danoeh.antennapod.core.service; import android.content.Context; import android.support.annotation.NonNull; +import android.util.Log; + import androidx.work.Worker; import androidx.work.WorkerParameters; -import de.danoeh.antennapod.core.ClientConfig; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.util.FeedUpdateUtils; + import org.awaitility.Awaitility; import java.util.concurrent.atomic.AtomicBoolean; +import de.danoeh.antennapod.core.ClientConfig; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.storage.DBTasks; +import de.danoeh.antennapod.core.util.NetworkUtils; + public class FeedUpdateWorker extends Worker { + private static final String TAG = "FeedUpdateWorker"; + + public static final String PARAM_RUN_IMMEDIATE = "runImmediate"; + public FeedUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @@ -20,13 +29,20 @@ public class FeedUpdateWorker extends Worker { @Override @NonNull public Result doWork() { + final boolean isImmediate = getInputData() != null ? + getInputData().getBoolean(PARAM_RUN_IMMEDIATE, false) : false; + Log.d(TAG, "doWork() : isImmediate = " + isImmediate); ClientConfig.initialize(getApplicationContext()); AtomicBoolean finished = new AtomicBoolean(false); - FeedUpdateUtils.startAutoUpdate(getApplicationContext(), () -> finished.set(true)); + if (NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed()) { + DBTasks.refreshAllFeeds(getApplicationContext(), null, () -> finished.set(true)); + } else { + Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); + } Awaitility.await().until(finished::get); - if (UserPreferences.isAutoUpdateTimeOfDay()) { + if (!isImmediate && UserPreferences.isAutoUpdateTimeOfDay()) { // WorkManager does not allow to set specific time for repeated tasks. // We repeatedly schedule a OneTimeWorkRequest instead. UserPreferences.restartUpdateAlarm(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java deleted file mode 100644 index b425687ae..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import android.content.Context; -import android.util.Log; - -import org.awaitility.core.ConditionTimeoutException; - -import java.util.concurrent.TimeUnit; - -import de.danoeh.antennapod.core.storage.DBTasks; - -import static org.awaitility.Awaitility.with; - -public class FeedUpdateUtils { - private static final String TAG = "FeedUpdateUtils"; - - private FeedUpdateUtils() {} - - public static void startAutoUpdate(Context context, Runnable callback) { - // the network check is blocking for possibly a long time: so run the logic - // in a separate thread to prevent the code blocking the callers - final Runnable runnable = () -> { - try { - with().pollInterval(1, TimeUnit.SECONDS) - .await() - .atMost(10, TimeUnit.SECONDS) - .until(() -> NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed()); - DBTasks.refreshAllFeeds(context, null, callback); - } catch (ConditionTimeoutException ignore) { - Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); - } - }; - new Thread(runnable).start(); - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java index 412b150fa..6bf3631e7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java @@ -1,21 +1,25 @@ package de.danoeh.antennapod.core.util.download; import android.util.Log; + import androidx.work.Constraints; +import androidx.work.Data; import androidx.work.ExistingPeriodicWorkPolicy; import androidx.work.ExistingWorkPolicy; import androidx.work.NetworkType; import androidx.work.OneTimeWorkRequest; import androidx.work.PeriodicWorkRequest; import androidx.work.WorkManager; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.service.FeedUpdateWorker; import java.util.Calendar; import java.util.concurrent.TimeUnit; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.FeedUpdateWorker; + public class AutoUpdateManager { private static final String WORK_ID_FEED_UPDATE = FeedUpdateWorker.class.getName(); + private static final String WORK_ID_FEED_UPDATE_IMMEDIATE = FeedUpdateWorker.class.getName() +"Immediate"; private static final String TAG = "AutoUpdateManager"; private AutoUpdateManager() { @@ -60,6 +64,22 @@ public class AutoUpdateManager { WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE, ExistingWorkPolicy.REPLACE, workRequest); } + public static void runImmediate() { + Log.d(TAG, "Run auto update immediately."); + + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class) + .setConstraints(getConstraints()) + .setInitialDelay(0L, TimeUnit.MILLISECONDS) + .setInputData(new Data.Builder() + .putBoolean(FeedUpdateWorker.PARAM_RUN_IMMEDIATE, true) + .build() + ) + .build(); + + WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE_IMMEDIATE, ExistingWorkPolicy.REPLACE, workRequest); + + } + public static void disableAutoUpdate() { WorkManager.getInstance().cancelUniqueWork(WORK_ID_FEED_UPDATE); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 366146d22e1d29ea51e6a275d9c7cf8bd351a429 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sun, 1 Sep 2019 09:46:25 -0700 Subject: prevent deadlock in case auto feed update is blocked per review. --- .../main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java index f551ffa39..da3bfe734 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java @@ -34,13 +34,13 @@ public class FeedUpdateWorker extends Worker { Log.d(TAG, "doWork() : isImmediate = " + isImmediate); ClientConfig.initialize(getApplicationContext()); - AtomicBoolean finished = new AtomicBoolean(false); if (NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed()) { + AtomicBoolean finished = new AtomicBoolean(false); DBTasks.refreshAllFeeds(getApplicationContext(), null, () -> finished.set(true)); + Awaitility.await().until(finished::get); } else { Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); } - Awaitility.await().until(finished::get); if (!isImmediate && UserPreferences.isAutoUpdateTimeOfDay()) { // WorkManager does not allow to set specific time for repeated tasks. -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From ce96eeafb6a8945536cecb2476173e7991126754 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sun, 1 Sep 2019 09:51:31 -0700 Subject: simplify param logic (getInputData() is @NonNull) --- .../main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java index da3bfe734..364e3c638 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java @@ -29,8 +29,7 @@ public class FeedUpdateWorker extends Worker { @Override @NonNull public Result doWork() { - final boolean isImmediate = getInputData() != null ? - getInputData().getBoolean(PARAM_RUN_IMMEDIATE, false) : false; + final boolean isImmediate = getInputData().getBoolean(PARAM_RUN_IMMEDIATE, false); Log.d(TAG, "doWork() : isImmediate = " + isImmediate); ClientConfig.initialize(getApplicationContext()); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 608b874057df09571e8ea93b75ca07f1a41edb00 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sun, 1 Sep 2019 10:02:36 -0700 Subject: Make feed update work IDs not dependent on classname to avoid accidental changing of IDs due to class refactoring. --- .../de/danoeh/antennapod/core/util/download/AutoUpdateManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java index 6bf3631e7..a92c4b740 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java @@ -18,8 +18,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.FeedUpdateWorker; public class AutoUpdateManager { - private static final String WORK_ID_FEED_UPDATE = FeedUpdateWorker.class.getName(); - private static final String WORK_ID_FEED_UPDATE_IMMEDIATE = FeedUpdateWorker.class.getName() +"Immediate"; + private static final String WORK_ID_FEED_UPDATE = "de.danoeh.antennapod.core.service.FeedUpdateWorker"; + private static final String WORK_ID_FEED_UPDATE_IMMEDIATE = WORK_ID_FEED_UPDATE + "Immediate"; private static final String TAG = "AutoUpdateManager"; private AutoUpdateManager() { -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 0ddda3a0d2719d4bae701ff8106501ade8bf4984 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sun, 1 Sep 2019 10:56:42 -0700 Subject: remove unnecessary thread DBTasks.refreshAllFeeds(): it is invoked by FeedUpdateWorker in background only. --- app/build.gradle | 1 - .../antennapod/fragment/EpisodesListFragment.java | 8 +--- .../danoeh/antennapod/fragment/QueueFragment.java | 8 +--- core/build.gradle | 2 +- .../antennapod/core/service/FeedUpdateWorker.java | 8 +--- .../de/danoeh/antennapod/core/storage/DBTasks.java | 56 ++++++++-------------- 6 files changed, 26 insertions(+), 57 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f9ef8a7ef..21dcf454b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -173,7 +173,6 @@ dependencies { implementation 'com.github.mfietz:fyydlin:v0.4.2' implementation 'com.github.ByteHamster:SearchPreference:v1.3.0' - implementation "org.awaitility:awaitility:$awaitilityVersion" androidTestImplementation 'com.nanohttpd:nanohttpd-webserver:2.1.1' androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion" diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 799f45eba..201832062 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -39,17 +39,16 @@ import de.danoeh.antennapod.core.event.DownloadEvent; import de.danoeh.antennapod.core.event.DownloaderUpdate; import de.danoeh.antennapod.core.event.FeedItemEvent; import de.danoeh.antennapod.core.feed.EventDistributor; -import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.service.download.DownloadRequest; import de.danoeh.antennapod.core.service.download.DownloadService; import de.danoeh.antennapod.core.service.download.Downloader; -import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.LongList; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.MenuItemUtils; import de.danoeh.antennapod.view.EmptyViewHandler; @@ -197,10 +196,7 @@ public abstract class EpisodesListFragment extends Fragment { if (!super.onOptionsItemSelected(item)) { switch (item.getItemId()) { case R.id.refresh_item: - List feeds = ((MainActivity) getActivity()).getFeeds(); - if (feeds != null) { - DBTasks.refreshAllFeeds(getActivity(), feeds); - } + AutoUpdateManager.runImmediate(); return true; case R.id.mark_all_read_item: ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(), diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index d461dbc5d..e33bf752f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -41,14 +41,12 @@ import de.danoeh.antennapod.core.event.DownloaderUpdate; import de.danoeh.antennapod.core.event.FeedItemEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; -import de.danoeh.antennapod.core.feed.Feed; 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.download.DownloadService; import de.danoeh.antennapod.core.service.download.Downloader; import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Converter; @@ -56,6 +54,7 @@ import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.QueueSorter; import de.danoeh.antennapod.core.util.SortOrder; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.MenuItemUtils; @@ -305,10 +304,7 @@ public class QueueFragment extends Fragment { toggleQueueLock(); return true; case R.id.refresh_item: - List feeds = ((MainActivity) getActivity()).getFeeds(); - if (feeds != null) { - DBTasks.refreshAllFeeds(getActivity(), feeds); - } + AutoUpdateManager.runImmediate(); return true; case R.id.clear_queue: // make sure the user really wants to clear the queue diff --git a/core/build.gradle b/core/build.gradle index 133f1b262..8614d5589 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -76,7 +76,6 @@ dependencies { annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbusVersion" implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion" implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion" - implementation "org.awaitility:awaitility:$awaitilityVersion" implementation "com.google.android.exoplayer:exoplayer:$exoPlayerVersion" implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion" @@ -92,6 +91,7 @@ dependencies { System.out.println("core: free build hack, skipping some dependencies") } + testImplementation "org.awaitility:awaitility:$awaitilityVersion" testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:1.10.19' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java index 364e3c638..27f3c310a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java @@ -7,10 +7,6 @@ import android.util.Log; import androidx.work.Worker; import androidx.work.WorkerParameters; -import org.awaitility.Awaitility; - -import java.util.concurrent.atomic.AtomicBoolean; - import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBTasks; @@ -34,9 +30,7 @@ public class FeedUpdateWorker extends Worker { ClientConfig.initialize(getApplicationContext()); if (NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed()) { - AtomicBoolean finished = new AtomicBoolean(false); - DBTasks.refreshAllFeeds(getApplicationContext(), null, () -> finished.set(true)); - Awaitility.await().until(finished::get); + DBTasks.refreshAllFeeds(getApplicationContext()); } else { Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); } 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 0fb181299..cd5a83f48 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 @@ -3,7 +3,7 @@ package de.danoeh.antennapod.core.storage; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; -import android.support.annotation.Nullable; +import android.os.Looper; import android.util.Log; import java.util.ArrayList; @@ -144,53 +144,37 @@ public final class DBTasks { private static final AtomicBoolean isRefreshing = new AtomicBoolean(false); /** - * Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still + * Refreshes all feeds. + * It must not be from the main thread. + * This method might ignore subsequent calls if it is still * enqueuing Feeds for download from a previous call * * @param context Might be used for accessing the database - * @param feeds List of Feeds that should be refreshed. */ - public static void refreshAllFeeds(final Context context, final List feeds) { - refreshAllFeeds(context, feeds, null); - } - - /** - * Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still - * enqueuing Feeds for download from a previous call - * - * @param context Might be used for accessing the database - * @param feeds List of Feeds that should be refreshed. - * @param callback Called after everything was added enqueued for download. Might be null. - */ - public static void refreshAllFeeds(final Context context, final List feeds, @Nullable Runnable callback) { + public static void refreshAllFeeds(final Context context) { if (!isRefreshing.compareAndSet(false, true)) { Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked"); return; } - new Thread(() -> { - if (feeds != null) { - refreshFeeds(context, feeds); - } else { - refreshFeeds(context, DBReader.getFeedList()); - } - isRefreshing.set(false); + if (Looper.myLooper() == Looper.getMainLooper()) { + Log.wtf(TAG, "DBTasks.refreshAllFeeds() must not be called from the main thread"); + return; + } - SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); - prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); + refreshFeeds(context, DBReader.getFeedList()); + isRefreshing.set(false); - if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { - GpodnetSyncService.sendSyncIntent(context); - } - // Note: automatic download of episodes will be done but not here. - // Instead it is done after all feeds have been refreshed (asynchronously), - // in DownloadService.onDestroy() - // See Issue #2577 for the details of the rationale + SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); + prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); - if (callback != null) { - callback.run(); - } - }).start(); + if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { + GpodnetSyncService.sendSyncIntent(context); + } + // Note: automatic download of episodes will be done but not here. + // Instead it is done after all feeds have been refreshed (asynchronously), + // in DownloadService.onDestroy() + // See Issue #2577 for the details of the rationale } /** -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 8dc9939736b3b1381a8e550c05adc853de4833b5 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sun, 1 Sep 2019 13:15:02 -0700 Subject: change refreshAllFeeds() main thread call guard to exception. --- core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 cd5a83f48..4c15f5f00 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 @@ -158,8 +158,7 @@ public final class DBTasks { } if (Looper.myLooper() == Looper.getMainLooper()) { - Log.wtf(TAG, "DBTasks.refreshAllFeeds() must not be called from the main thread"); - return; + throw new IllegalStateException("DBTasks.refreshAllFeeds() must not be called from the main thread."); } refreshFeeds(context, DBReader.getFeedList()); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 33eddaa2565aef9d82da795549f780d122c9f44f Mon Sep 17 00:00:00 2001 From: orionlee Date: Tue, 24 Sep 2019 11:02:49 -0700 Subject: auto feed update - make the calls from UI use background thread rather than WorkManager to ensure the updates are immediate. --- .../antennapod/fragment/EpisodesListFragment.java | 2 +- .../danoeh/antennapod/fragment/QueueFragment.java | 2 +- .../core/receiver/FeedUpdateReceiver.java | 2 +- .../antennapod/core/service/FeedUpdateWorker.java | 8 +++--- .../core/util/download/AutoUpdateManager.java | 32 ++++++++++++++++++---- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 201832062..7c6e34d66 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -196,7 +196,7 @@ public abstract class EpisodesListFragment extends Fragment { if (!super.onOptionsItemSelected(item)) { switch (item.getItemId()) { case R.id.refresh_item: - AutoUpdateManager.runImmediate(); + AutoUpdateManager.runImmediate(requireContext()); return true; case R.id.mark_all_read_item: ConfirmationDialog markAllReadConfirmationDialog = new ConfirmationDialog(getActivity(), diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index e33bf752f..34d128cc8 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -304,7 +304,7 @@ public class QueueFragment extends Fragment { toggleQueueLock(); return true; case R.id.refresh_item: - AutoUpdateManager.runImmediate(); + AutoUpdateManager.runImmediate(requireContext()); return true; case R.id.clear_queue: // make sure the user really wants to clear the queue diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java index cc5f49dc1..af0a0d426 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java @@ -20,7 +20,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver { Log.d(TAG, "Received intent"); ClientConfig.initialize(context); - AutoUpdateManager.runImmediate(); + AutoUpdateManager.runOnce(); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java index 27f3c310a..92d43cea2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java @@ -16,7 +16,7 @@ public class FeedUpdateWorker extends Worker { private static final String TAG = "FeedUpdateWorker"; - public static final String PARAM_RUN_IMMEDIATE = "runImmediate"; + public static final String PARAM_RUN_ONCE = "runOnce"; public FeedUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); @@ -25,8 +25,8 @@ public class FeedUpdateWorker extends Worker { @Override @NonNull public Result doWork() { - final boolean isImmediate = getInputData().getBoolean(PARAM_RUN_IMMEDIATE, false); - Log.d(TAG, "doWork() : isImmediate = " + isImmediate); + final boolean isRunOnce = getInputData().getBoolean(PARAM_RUN_ONCE, false); + Log.d(TAG, "doWork() : isRunOnce = " + isRunOnce); ClientConfig.initialize(getApplicationContext()); if (NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed()) { @@ -35,7 +35,7 @@ public class FeedUpdateWorker extends Worker { Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); } - if (!isImmediate && UserPreferences.isAutoUpdateTimeOfDay()) { + if (!isRunOnce && UserPreferences.isAutoUpdateTimeOfDay()) { // WorkManager does not allow to set specific time for repeated tasks. // We repeatedly schedule a OneTimeWorkRequest instead. UserPreferences.restartUpdateAlarm(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java index a92c4b740..e3cb03077 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.util.download; +import android.content.Context; +import android.support.annotation.NonNull; import android.util.Log; import androidx.work.Constraints; @@ -16,10 +18,11 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.FeedUpdateWorker; +import de.danoeh.antennapod.core.storage.DBTasks; public class AutoUpdateManager { private static final String WORK_ID_FEED_UPDATE = "de.danoeh.antennapod.core.service.FeedUpdateWorker"; - private static final String WORK_ID_FEED_UPDATE_IMMEDIATE = WORK_ID_FEED_UPDATE + "Immediate"; + private static final String WORK_ID_FEED_UPDATE_ONCE = WORK_ID_FEED_UPDATE + "Once"; private static final String TAG = "AutoUpdateManager"; private AutoUpdateManager() { @@ -64,20 +67,39 @@ public class AutoUpdateManager { WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE, ExistingWorkPolicy.REPLACE, workRequest); } - public static void runImmediate() { - Log.d(TAG, "Run auto update immediately."); + /** + * Run auto feed refresh once in background, as soon as what OS scheduling allows. + * + * Callers from UI should use {@link #runImmediate(Context)}, as it will guarantee + * the refresh be run immediately. + */ + public static void runOnce() { + Log.d(TAG, "Run auto update once, as soon as OS allows."); OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class) .setConstraints(getConstraints()) .setInitialDelay(0L, TimeUnit.MILLISECONDS) .setInputData(new Data.Builder() - .putBoolean(FeedUpdateWorker.PARAM_RUN_IMMEDIATE, true) + .putBoolean(FeedUpdateWorker.PARAM_RUN_ONCE, true) .build() ) .build(); - WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE_IMMEDIATE, ExistingWorkPolicy.REPLACE, workRequest); + WorkManager.getInstance().enqueueUniqueWork(WORK_ID_FEED_UPDATE_ONCE, ExistingWorkPolicy.REPLACE, workRequest); + + } + /** + /** + * Run auto feed refresh once in background immediately, using its own thread. + * + * Callers where the additional threads is not suitable should use {@link #runOnce()} + */ + public static void runImmediate(@NonNull Context context) { + Log.d(TAG, "Run auto update immediately in background."); + new Thread(() -> { + DBTasks.refreshAllFeeds(context.getApplicationContext()); + }, "ManualRefreshAllFeeds").start(); } public static void disableAutoUpdate() { -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 26b7f6c30088bbcf61a6224f59936c118ce50d02 Mon Sep 17 00:00:00 2001 From: orionlee Date: Tue, 24 Sep 2019 11:14:35 -0700 Subject: auto feed update mini-refactor: move periodic update entry point method from UserPreference to AutoUpdateManager --- .../antennapod/preferences/PreferenceUpgrader.java | 4 +++- .../core/preferences/UserPreferences.java | 17 ++--------------- .../antennapod/core/service/FeedUpdateWorker.java | 3 ++- .../core/util/download/AutoUpdateManager.java | 22 ++++++++++++++++++++-- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java index 195d062f3..6392d0535 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java @@ -3,9 +3,11 @@ package de.danoeh.antennapod.preferences; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; + import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.core.util.gui.NotificationUtils; public class PreferenceUpgrader { @@ -22,7 +24,7 @@ public class PreferenceUpgrader { if (oldVersion != newVersion) { NotificationUtils.createChannels(context); - UserPreferences.restartUpdateAlarm(); + AutoUpdateManager.restartUpdateAlarm(); upgrade(oldVersion); upgraderPrefs.edit().putInt(PREF_CONFIGURED_VERSION, newVersion).apply(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index a06047229..787e32ccc 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -622,7 +622,7 @@ public class UserPreferences { .apply(); // when updating with an interval, we assume the user wants // to update *now* and then every 'hours' interval thereafter. - restartUpdateAlarm(); + AutoUpdateManager.restartUpdateAlarm(); } /** @@ -632,7 +632,7 @@ public class UserPreferences { prefs.edit() .putString(PREF_UPDATE_INTERVAL, hourOfDay + ":" + minute) .apply(); - restartUpdateAlarm(); + AutoUpdateManager.restartUpdateAlarm(); } public static void disableAutoUpdate() { @@ -882,19 +882,6 @@ public class UserPreferences { return getUpdateTimeOfDay().length == 2; } - public static void restartUpdateAlarm() { - if (isAutoUpdateDisabled()) { - AutoUpdateManager.disableAutoUpdate(); - } else if (isAutoUpdateTimeOfDay()) { - int[] timeOfDay = getUpdateTimeOfDay(); - Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay)); - AutoUpdateManager.restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]); - } else { - long milliseconds = getUpdateInterval(); - AutoUpdateManager.restartUpdateIntervalAlarm(milliseconds); - } - } - /** * Evaluates whether Cast support (Chromecast, Audio Cast, etc) is enabled on the preferences. */ diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java index 92d43cea2..87c18227b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java @@ -11,6 +11,7 @@ import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.util.NetworkUtils; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; public class FeedUpdateWorker extends Worker { @@ -38,7 +39,7 @@ public class FeedUpdateWorker extends Worker { if (!isRunOnce && UserPreferences.isAutoUpdateTimeOfDay()) { // WorkManager does not allow to set specific time for repeated tasks. // We repeatedly schedule a OneTimeWorkRequest instead. - UserPreferences.restartUpdateAlarm(); + AutoUpdateManager.restartUpdateAlarm(); } return Result.success(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java index e3cb03077..ebeec058d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java @@ -13,6 +13,7 @@ import androidx.work.OneTimeWorkRequest; import androidx.work.PeriodicWorkRequest; import androidx.work.WorkManager; +import java.util.Arrays; import java.util.Calendar; import java.util.concurrent.TimeUnit; @@ -29,10 +30,26 @@ public class AutoUpdateManager { } + /** + * Start / restart periodic auto feed refresh + */ + public static void restartUpdateAlarm() { + if (UserPreferences.isAutoUpdateDisabled()) { + disableAutoUpdate(); + } else if (UserPreferences.isAutoUpdateTimeOfDay()) { + int[] timeOfDay = UserPreferences.getUpdateTimeOfDay(); + Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay)); + restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]); + } else { + long milliseconds = UserPreferences.getUpdateInterval(); + restartUpdateIntervalAlarm(milliseconds); + } + } + /** * Sets the interval in which the feeds are refreshed automatically */ - public static void restartUpdateIntervalAlarm(long intervalMillis) { + private static void restartUpdateIntervalAlarm(long intervalMillis) { Log.d(TAG, "Restarting update alarm."); PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(FeedUpdateWorker.class, @@ -47,7 +64,7 @@ public class AutoUpdateManager { /** * Sets time of day the feeds are refreshed automatically */ - public static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) { + private static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) { Log.d(TAG, "Restarting update alarm."); Calendar now = Calendar.getInstance(); @@ -116,4 +133,5 @@ public class AutoUpdateManager { } return constraints.build(); } + } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From aeafb62a3cefcbde8e3c292b5fa2a5f562723f27 Mon Sep 17 00:00:00 2001 From: orionlee Date: Tue, 24 Sep 2019 11:35:01 -0700 Subject: re-add missing awaitility dependency in AndroidTest --- app/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/app/build.gradle b/app/build.gradle index 21dcf454b..460f9b4e3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -174,6 +174,7 @@ dependencies { implementation 'com.github.mfietz:fyydlin:v0.4.2' implementation 'com.github.ByteHamster:SearchPreference:v1.3.0' + androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion" androidTestImplementation 'com.nanohttpd:nanohttpd-webserver:2.1.1' androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion" androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 96a42b1bbe2005832b552077b8126d635ce9596c Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 14:40:18 +0200 Subject: Fixed HTTP redirects in ExoPlayer --- .../antennapod/core/service/playback/ExoPlayerWrapper.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index f20525f73..0fc165183 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -22,6 +22,8 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.util.Util; import org.antennapod.audio.MediaPlayer; @@ -180,8 +182,12 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void setDataSource(String s) throws IllegalArgumentException, IllegalStateException { - DataSource.Factory dataSourceFactory = - new DefaultDataSourceFactory(mContext, Util.getUserAgent(mContext, mContext.getPackageName()), null); + DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory( + Util.getUserAgent(mContext, mContext.getPackageName()), null, + DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, + DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, + true); + DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mContext, null, httpDataSourceFactory); ExtractorMediaSource.Factory f = new ExtractorMediaSource.Factory(dataSourceFactory); mediaSource = f.createMediaSource(Uri.parse(s)); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 2b8b262499db329ef529cf68ffa2c1b17c09f40d Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 14:45:47 +0200 Subject: Fixed crashes when leaving search fragments --- .../core/util/exception/RxJavaErrorHandlerSetup.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java b/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java index 12f0c1c6e..223104d2e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/exception/RxJavaErrorHandlerSetup.java @@ -1,12 +1,9 @@ package de.danoeh.antennapod.core.util.exception; import android.util.Log; -import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException; import io.reactivex.exceptions.UndeliverableException; import io.reactivex.plugins.RxJavaPlugins; -import java.io.InterruptedIOException; - public class RxJavaErrorHandlerSetup { private RxJavaErrorHandlerSetup() { @@ -14,21 +11,14 @@ public class RxJavaErrorHandlerSetup { } public static void setupRxJavaErrorHandler() { - RxJavaPlugins.setErrorHandler(originalCause -> { - Throwable e = originalCause; + RxJavaPlugins.setErrorHandler(e -> { if (e instanceof UndeliverableException) { - e = e.getCause(); - } - if (e instanceof GpodnetServiceException) { - e = e.getCause(); - } - if (e instanceof InterruptedException || e instanceof InterruptedIOException) { - // fine, some blocking code was interrupted by a dispose call - Log.d("RxJavaErrorHandler", "Ignored exception: " + Log.getStackTraceString(originalCause)); + // Probably just disposed because the fragment was left + Log.d("RxJavaErrorHandler", "Ignored exception: " + Log.getStackTraceString(e)); return; } Thread.currentThread().getUncaughtExceptionHandler() - .uncaughtException(Thread.currentThread(), originalCause); + .uncaughtException(Thread.currentThread(), e); }); } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From b65c688b53779f436062d33517f95b2c0a29733c Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 15:00:33 +0200 Subject: Fixed crash if there is no browser installed --- .../de/danoeh/antennapod/activity/AboutActivity.java | 4 ++-- .../de/danoeh/antennapod/activity/BugReportActivity.java | 13 ++----------- .../danoeh/antennapod/activity/MediaplayerActivity.java | 3 +-- .../java/de/danoeh/antennapod/dialog/RatingDialog.java | 9 +++------ .../antennapod/fragment/ItemDescriptionFragment.java | 14 ++------------ .../java/de/danoeh/antennapod/fragment/ItemFragment.java | 11 ++--------- .../fragment/preferences/MainPreferencesFragment.java | 15 +++------------ .../antennapod/menuhandler/FeedItemMenuHandler.java | 9 +-------- .../danoeh/antennapod/menuhandler/FeedMenuHandler.java | 9 +-------- .../java/de/danoeh/antennapod/core/util/IntentUtils.java | 16 ++++++++++++++++ 10 files changed, 33 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java index 1bcdada44..821e2f347 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java @@ -15,6 +15,7 @@ import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.LinearLayout; +import de.danoeh.antennapod.core.util.IntentUtils; import org.apache.commons.io.IOUtils; import java.io.IOException; @@ -57,8 +58,7 @@ public class AboutActivity extends AppCompatActivity { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith("http")) { - Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - startActivity(browserIntent); + IntentUtils.openInBrowser(AboutActivity.this, url); return true; } else { url = url.replace("file:///android_asset/", ""); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java index 32694a74e..7df973f9b 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java @@ -1,19 +1,16 @@ package de.danoeh.antennapod.activity; -import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; -import android.widget.Toast; import de.danoeh.antennapod.CrashReportWriter; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.util.IntentUtils; import org.apache.commons.io.IOUtils; import java.io.File; @@ -45,13 +42,7 @@ public class BugReportActivity extends AppCompatActivity { } findViewById(R.id.btn_open_bug_tracker).setOnClickListener(v -> { - try { - Intent myIntent = new Intent(Intent.ACTION_VIEW, - Uri.parse("https://github.com/AntennaPod/AntennaPod/issues")); - startActivity(myIntent); - } catch (ActivityNotFoundException e) { - Toast.makeText(this, R.string.pref_no_browser_found, Toast.LENGTH_LONG).show(); - } + IntentUtils.openInBrowser(BugReportActivity.this, "https://github.com/AntennaPod/AntennaPod/issues"); }); findViewById(R.id.btn_copy_log).setOnClickListener(v -> { diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java index eefa35500..91c3796af 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -452,8 +452,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements } break; case R.id.visit_website_item: - Uri uri = Uri.parse(getWebsiteLinkWithFallback(media)); - startActivity(new Intent(Intent.ACTION_VIEW, uri)); + IntentUtils.openInBrowser(MediaplayerActivity.this, getWebsiteLinkWithFallback(media)); break; case R.id.share_link_item: if (feedItem != null) { diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java index 24656ed29..5969963f2 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java @@ -15,6 +15,7 @@ import java.lang.ref.WeakReference; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.util.IntentUtils; public class RatingDialog { @@ -59,14 +60,10 @@ public class RatingDialog { private static void rateNow() { Context context = mContext.get(); - if(context == null) { + if (context == null) { return; } - final String appPackage = "de.danoeh.antennapod"; - final Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=" + appPackage); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + IntentUtils.openInBrowser(context, "https://play.google.com/store/apps/details?id=de.danoeh.antennapod"); saveRated(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index 5cf2c5eeb..bfca90b2a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -96,13 +96,7 @@ public class ItemDescriptionFragment extends Fragment { if (Timeline.isTimecodeLink(url)) { onTimecodeLinkSelected(url); } else { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - try { - startActivity(intent); - } catch (ActivityNotFoundException e) { - e.printStackTrace(); - return true; - } + IntentUtils.openInBrowser(getContext(), url); } return true; } @@ -159,11 +153,7 @@ public class ItemDescriptionFragment extends Fragment { if (selectedURL != null) { switch (item.getItemId()) { case R.id.open_in_browser_item: - Uri uri = Uri.parse(selectedURL); - final Intent intent = new Intent(Intent.ACTION_VIEW, uri); - if(IntentUtils.isCallable(getActivity(), intent)) { - getActivity().startActivity(intent); - } + IntentUtils.openInBrowser(getContext(), selectedURL); break; case R.id.share_url_item: ShareUtils.shareLink(getActivity(), selectedURL); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index 04bf32fd0..9395b0994 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -210,10 +210,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture { webvDescription.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - if(IntentUtils.isCallable(getActivity(), intent)) { - startActivity(intent); - } + IntentUtils.openInBrowser(getContext(), url); return true; } }); @@ -484,11 +481,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture { if (selectedURL != null) { switch (item.getItemId()) { case R.id.open_in_browser_item: - Uri uri = Uri.parse(selectedURL); - final Intent intent = new Intent(Intent.ACTION_VIEW, uri); - if(IntentUtils.isCallable(getActivity(), intent)) { - getActivity().startActivity(intent); - } + IntentUtils.openInBrowser(getContext(), selectedURL); break; case R.id.share_url_item: ShareUtils.shareLink(getActivity(), selectedURL); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java index 31fb7ff8b..9f36e1355 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java @@ -15,6 +15,7 @@ import de.danoeh.antennapod.activity.AboutActivity; import de.danoeh.antennapod.activity.BugReportActivity; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.activity.StatisticsActivity; +import de.danoeh.antennapod.core.util.IntentUtils; public class MainPreferencesFragment extends PreferenceFragmentCompat { private static final String TAG = "MainPreferencesFragment"; @@ -72,11 +73,11 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { } ); findPreference(PREF_FAQ).setOnPreferenceClickListener(preference -> { - openInBrowser("https://antennapod.org/faq.html"); + IntentUtils.openInBrowser(getContext(), "https://antennapod.org/faq.html"); return true; }); findPreference(PREF_VIEW_MAILING_LIST).setOnPreferenceClickListener(preference -> { - openInBrowser("https://groups.google.com/forum/#!forum/antennapod"); + IntentUtils.openInBrowser(getContext(), "https://groups.google.com/forum/#!forum/antennapod"); return true; }); findPreference(PREF_SEND_BUG_REPORT).setOnPreferenceClickListener(preference -> { @@ -85,16 +86,6 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { }); } - private void openInBrowser(String url) { - try { - Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - startActivity(myIntent); - } catch (ActivityNotFoundException e) { - Toast.makeText(getActivity(), R.string.pref_no_browser_found, Toast.LENGTH_LONG).show(); - Log.e(TAG, Log.getStackTraceString(e)); - } - } - private void setupSearch() { SearchPreference searchPreference = (SearchPreference) findPreference("searchPreference"); SearchConfiguration config = searchPreference.getSearchConfiguration(); diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java index f0b6330b3..add62b480 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java @@ -214,14 +214,7 @@ public class FeedItemMenuHandler { DBWriter.setFeedItemAutoDownload(selectedItem, false); break; case R.id.visit_website_item: - Uri uri = Uri.parse(FeedItemUtil.getLinkWithFallback(selectedItem)); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - if(IntentUtils.isCallable(context, intent)) { - context.startActivity(intent); - } else { - Toast.makeText(context, context.getString(R.string.download_error_malformed_url), - Toast.LENGTH_SHORT).show(); - } + IntentUtils.openInBrowser(context, FeedItemUtil.getLinkWithFallback(selectedItem)); break; case R.id.share_link_item: ShareUtils.shareFeedItemLink(context, selectedItem); diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java index 3949119fc..dbb3b6e7b 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java @@ -86,14 +86,7 @@ public class FeedMenuHandler { conDialog.createNewDialog().show(); break; case R.id.visit_website_item: - Uri uri = Uri.parse(selectedFeed.getLink()); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - if(IntentUtils.isCallable(context, intent)) { - context.startActivity(intent); - } else { - Toast.makeText(context, context.getString(R.string.download_error_malformed_url), - Toast.LENGTH_SHORT).show(); - } + IntentUtils.openInBrowser(context, selectedFeed.getLink()); break; case R.id.share_link_item: ShareUtils.shareFeedlink(context, selectedFeed); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java index e81ab47ed..656b518bf 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/IntentUtils.java @@ -1,13 +1,20 @@ package de.danoeh.antennapod.core.util; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.util.Log; +import android.widget.Toast; +import de.danoeh.antennapod.core.R; import java.util.List; public class IntentUtils { + private static final String TAG = "IntentUtils"; + private IntentUtils(){} /* @@ -28,4 +35,13 @@ public class IntentUtils { context.sendBroadcast(new Intent(action).setPackage(context.getPackageName())); } + public static void openInBrowser(Context context, String url) { + try { + Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + context.startActivity(myIntent); + } catch (ActivityNotFoundException e) { + Toast.makeText(context, R.string.pref_no_browser_found, Toast.LENGTH_LONG).show(); + Log.e(TAG, Log.getStackTraceString(e)); + } + } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 72d5c65c4f696b74dd7d217eb45bef5ad1bd619d Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 15:24:23 +0200 Subject: Removed transparent notification button outline --- .../playback/PlaybackServiceNotificationBuilder.java | 12 ++++++------ .../main/res/drawable-hdpi/ic_media_cast_disconnect.png | Bin 2355 -> 0 bytes .../main/res/drawable-mdpi/ic_media_cast_disconnect.png | Bin 1467 -> 0 bytes .../main/res/drawable-xhdpi/ic_media_cast_disconnect.png | Bin 4496 -> 0 bytes .../res/drawable-xxhdpi/ic_media_cast_disconnect.png | Bin 7096 -> 0 bytes core/src/main/res/drawable/ic_notification_cast_off.xml | 5 +++++ .../main/res/drawable/ic_notification_fast_forward.xml | 5 +++++ .../main/res/drawable/ic_notification_fast_rewind.xml | 5 +++++ core/src/main/res/drawable/ic_notification_key.xml | 9 +++++---- core/src/main/res/drawable/ic_notification_pause.xml | 5 +++++ core/src/main/res/drawable/ic_notification_play.xml | 5 +++++ core/src/main/res/drawable/ic_notification_skip.xml | 5 +++++ 12 files changed, 41 insertions(+), 10 deletions(-) delete mode 100644 core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.png delete mode 100644 core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.png delete mode 100644 core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.png delete mode 100644 core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.png create mode 100644 core/src/main/res/drawable/ic_notification_cast_off.xml create mode 100644 core/src/main/res/drawable/ic_notification_fast_forward.xml create mode 100644 core/src/main/res/drawable/ic_notification_fast_rewind.xml create mode 100644 core/src/main/res/drawable/ic_notification_pause.xml create mode 100644 core/src/main/res/drawable/ic_notification_play.xml create mode 100644 core/src/main/res/drawable/ic_notification_skip.xml diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java index 0e7339ac4..1a13fe5a7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java @@ -115,7 +115,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build stopCastingIntent.putExtra(PlaybackService.EXTRA_CAST_DISCONNECT, true); PendingIntent stopCastingPendingIntent = PendingIntent.getService(context, numActions, stopCastingIntent, PendingIntent.FLAG_UPDATE_CURRENT); - addAction(R.drawable.ic_media_cast_disconnect, + addAction(R.drawable.ic_notification_cast_off, context.getString(R.string.cast_disconnect_label), stopCastingPendingIntent); numActions++; @@ -124,7 +124,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build // always let them rewind PendingIntent rewindButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_REWIND, numActions); - addAction(android.R.drawable.ic_media_rew, context.getString(R.string.rewind_label), rewindButtonPendingIntent); + addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label), rewindButtonPendingIntent); if (UserPreferences.showRewindOnCompactNotification()) { compactActionList.add(numActions); } @@ -133,14 +133,14 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build if (playerStatus == PlayerStatus.PLAYING) { PendingIntent pauseButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_PAUSE, numActions); - addAction(android.R.drawable.ic_media_pause, //pause action + addAction(R.drawable.ic_notification_pause, //pause action context.getString(R.string.pause_label), pauseButtonPendingIntent); compactActionList.add(numActions++); } else { PendingIntent playButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_PLAY, numActions); - addAction(android.R.drawable.ic_media_play, //play action + addAction(R.drawable.ic_notification_play, //play action context.getString(R.string.play_label), playButtonPendingIntent); compactActionList.add(numActions++); @@ -149,7 +149,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build // ff follows play, then we have skip (if it's present) PendingIntent ffButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, numActions); - addAction(android.R.drawable.ic_media_ff, context.getString(R.string.fast_forward_label), ffButtonPendingIntent); + addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label), ffButtonPendingIntent); if (UserPreferences.showFastForwardOnCompactNotification()) { compactActionList.add(numActions); } @@ -158,7 +158,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build if (UserPreferences.isFollowQueue()) { PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_NEXT, numActions); - addAction(android.R.drawable.ic_media_next, + addAction(R.drawable.ic_notification_skip, context.getString(R.string.skip_episode_label), skipButtonPendingIntent); if (UserPreferences.showSkipOnCompactNotification()) { diff --git a/core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.png deleted file mode 100644 index 700c116e5..000000000 Binary files a/core/src/main/res/drawable-hdpi/ic_media_cast_disconnect.png and /dev/null differ diff --git a/core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.png deleted file mode 100644 index 767f420df..000000000 Binary files a/core/src/main/res/drawable-mdpi/ic_media_cast_disconnect.png and /dev/null differ diff --git a/core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.png deleted file mode 100644 index 740867129..000000000 Binary files a/core/src/main/res/drawable-xhdpi/ic_media_cast_disconnect.png and /dev/null differ diff --git a/core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.png b/core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.png deleted file mode 100644 index 2d2ec9035..000000000 Binary files a/core/src/main/res/drawable-xxhdpi/ic_media_cast_disconnect.png and /dev/null differ diff --git a/core/src/main/res/drawable/ic_notification_cast_off.xml b/core/src/main/res/drawable/ic_notification_cast_off.xml new file mode 100644 index 000000000..63a21fbe2 --- /dev/null +++ b/core/src/main/res/drawable/ic_notification_cast_off.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/core/src/main/res/drawable/ic_notification_fast_forward.xml b/core/src/main/res/drawable/ic_notification_fast_forward.xml new file mode 100644 index 000000000..bf564977c --- /dev/null +++ b/core/src/main/res/drawable/ic_notification_fast_forward.xml @@ -0,0 +1,5 @@ + + + diff --git a/core/src/main/res/drawable/ic_notification_fast_rewind.xml b/core/src/main/res/drawable/ic_notification_fast_rewind.xml new file mode 100644 index 000000000..847159cc5 --- /dev/null +++ b/core/src/main/res/drawable/ic_notification_fast_rewind.xml @@ -0,0 +1,5 @@ + + + diff --git a/core/src/main/res/drawable/ic_notification_key.xml b/core/src/main/res/drawable/ic_notification_key.xml index b1e2f9b8c..c8a817eeb 100644 --- a/core/src/main/res/drawable/ic_notification_key.xml +++ b/core/src/main/res/drawable/ic_notification_key.xml @@ -1,5 +1,6 @@ - - + + diff --git a/core/src/main/res/drawable/ic_notification_pause.xml b/core/src/main/res/drawable/ic_notification_pause.xml new file mode 100644 index 000000000..d46efb2f5 --- /dev/null +++ b/core/src/main/res/drawable/ic_notification_pause.xml @@ -0,0 +1,5 @@ + + + diff --git a/core/src/main/res/drawable/ic_notification_play.xml b/core/src/main/res/drawable/ic_notification_play.xml new file mode 100644 index 000000000..d571460c6 --- /dev/null +++ b/core/src/main/res/drawable/ic_notification_play.xml @@ -0,0 +1,5 @@ + + + diff --git a/core/src/main/res/drawable/ic_notification_skip.xml b/core/src/main/res/drawable/ic_notification_skip.xml new file mode 100644 index 000000000..0c65448cc --- /dev/null +++ b/core/src/main/res/drawable/ic_notification_skip.xml @@ -0,0 +1,5 @@ + + + -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 889144f993680a9c79b4c840cd0a206a43e654eb Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 15:49:24 +0200 Subject: Added refresh item to subscriptions view --- .../antennapod/fragment/SubscriptionFragment.java | 29 ++++++++++++++++++++++ app/src/main/res/menu/subscriptions.xml | 7 ++++++ 2 files changed, 36 insertions(+) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java index 15c6052a9..df02a38b2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java @@ -25,19 +25,28 @@ import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.SubscriptionsAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; +import de.danoeh.antennapod.core.event.DownloadEvent; +import de.danoeh.antennapod.core.event.DownloaderUpdate; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; +import de.danoeh.antennapod.core.service.download.DownloadService; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.dialog.RenameFeedDialog; +import de.danoeh.antennapod.menuhandler.MenuItemUtils; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * Fragment for displaying feed subscriptions @@ -56,6 +65,7 @@ public class SubscriptionFragment extends Fragment { private SubscriptionsAdapter subscriptionAdapter; private int mPosition = -1; + private boolean isUpdatingFeeds = false; private Disposable disposable; private SharedPreferences prefs; @@ -89,6 +99,8 @@ public class SubscriptionFragment extends Fragment { menu.findItem(R.id.subscription_num_columns_3).setChecked(columns == 3); menu.findItem(R.id.subscription_num_columns_4).setChecked(columns == 4); menu.findItem(R.id.subscription_num_columns_5).setChecked(columns == 5); + + isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker); } @Override @@ -97,6 +109,9 @@ public class SubscriptionFragment extends Fragment { return true; } switch (item.getItemId()) { + case R.id.refresh_item: + AutoUpdateManager.runImmediate(requireContext()); + return true; case R.id.subscription_num_columns_2: setColumnNumber(2); return true; @@ -136,6 +151,7 @@ public class SubscriptionFragment extends Fragment { public void onStart() { super.onStart(); EventDistributor.getInstance().register(contentUpdate); + EventBus.getDefault().register(this); loadSubscriptions(); } @@ -143,6 +159,7 @@ public class SubscriptionFragment extends Fragment { public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); + EventBus.getDefault().unregister(this); if(disposable != null) { disposable.dispose(); } @@ -278,6 +295,18 @@ public class SubscriptionFragment extends Fragment { } }; + @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) + public void onEventMainThread(DownloadEvent event) { + Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); + DownloaderUpdate update = event.update; + if (isUpdatingFeeds != update.feedIds.length > 0) { + getActivity().invalidateOptionsMenu(); + } + } + + private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker = + () -> DownloadService.isRunning && DownloadRequester.getInstance().isDownloadingFeeds(); + private final SubscriptionsAdapter.ItemAccess itemAccess = new SubscriptionsAdapter.ItemAccess() { @Override public int getCount() { diff --git a/app/src/main/res/menu/subscriptions.xml b/app/src/main/res/menu/subscriptions.xml index f39e0ac97..1780592d5 100644 --- a/app/src/main/res/menu/subscriptions.xml +++ b/app/src/main/res/menu/subscriptions.xml @@ -2,6 +2,13 @@ + + Date: Wed, 25 Sep 2019 16:20:21 +0200 Subject: Removed ProgressEvent Database upgrade is done on splash screen --- .../danoeh/antennapod/activity/MainActivity.java | 20 ------------ .../antennapod/core/event/ProgressEvent.java | 36 ---------------------- .../antennapod/core/storage/PodDBAdapter.java | 5 --- 3 files changed, 61 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java index 08686bd02..b028f7983 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -47,7 +47,6 @@ import de.danoeh.antennapod.adapter.NavListAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.event.MessageEvent; -import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; @@ -787,25 +786,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi loadData(); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ProgressEvent event) { - Log.d(TAG, "onEvent(" + event + ")"); - switch(event.action) { - case START: - pd = new ProgressDialog(this); - pd.setMessage(event.message); - pd.setIndeterminate(true); - pd.setCancelable(false); - pd.show(); - break; - case END: - if(pd != null) { - pd.dismiss(); - } - break; - } - } - @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(MessageEvent event) { Log.d(TAG, "onEvent(" + event + ")"); diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java deleted file mode 100644 index 3769d6bb1..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/event/ProgressEvent.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.danoeh.antennapod.core.event; - -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -public class ProgressEvent { - - public enum Action { - START, END - } - - public final Action action; - public final String message; - - private ProgressEvent(Action action, String message) { - this.action = action; - this.message = message; - } - - public static ProgressEvent start(String message) { - return new ProgressEvent(Action.START, message); - } - - public static ProgressEvent end() { - return new ProgressEvent(Action.END, null); - } - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) - .append("action", action) - .append("message", message) - .toString(); - } - -} 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 a3271bcf9..a1732e08f 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 @@ -28,8 +28,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; @@ -38,7 +36,6 @@ import de.danoeh.antennapod.core.feed.FeedPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.util.LongIntMap; -import org.greenrobot.eventbus.EventBus; // TODO Remove media column from feeditem table @@ -1478,11 +1475,9 @@ public class PodDBAdapter { @Override public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { - EventBus.getDefault().post(ProgressEvent.start(context.getString(R.string.progress_upgrading_database))); Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to " + newVersion + "."); DBUpgrader.upgrade(db, oldVersion, newVersion); - EventBus.getDefault().post(ProgressEvent.end()); } } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 72fc4f5eb08d61eaa0ab7f126b0c2276e6dfbcfb Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 16:43:46 +0200 Subject: Using PlaybackService to distribute position events instead of PlaybackController --- .../core/event/PlaybackPositionEvent.java | 8 ++++ .../core/service/playback/PlaybackService.java | 26 +++++++++++ .../core/util/playback/PlaybackController.java | 50 +--------------------- 3 files changed, 35 insertions(+), 49 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java new file mode 100644 index 000000000..a12c2b8ad --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/event/PlaybackPositionEvent.java @@ -0,0 +1,8 @@ +package de.danoeh.antennapod.core.event; + +public class PlaybackPositionEvent { + + public PlaybackPositionEvent() { + + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index ace89e40a..e72629971 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -45,10 +45,14 @@ import com.bumptech.glide.request.target.Target; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.event.MessageEvent; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.event.ServiceEvent; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.Feed; @@ -213,6 +217,9 @@ public class PlaybackService extends MediaBrowserServiceCompat { private PlaybackServiceFlavorHelper flavorHelper; private PlaybackServiceStateManager stateManager; + private final ScheduledThreadPoolExecutor positionEventDistributorExecutor = new ScheduledThreadPoolExecutor(1); + private ScheduledFuture positionEventDistributorFuture; + /** * Used for Lollipop notifications, Android Wear, and Android Auto. */ @@ -734,6 +741,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { // remove notification on pause stateManager.stopForeground(true); } + cancelPositionObserver(); writePlayerStatusPlaybackPreferences(); break; @@ -745,6 +753,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { case PLAYING: writePlayerStatusPlaybackPreferences(); setupNotification(newInfo); + setupPositionUpdater(); stateManager.validStartCommandWasReceived(); // set sleep timer if auto-enabled if (newInfo.oldPlayerStatus != null && newInfo.oldPlayerStatus != PlayerStatus.SEEKING && @@ -1653,6 +1662,23 @@ public class PlaybackService extends MediaBrowserServiceCompat { return mediaPlayer.getVideoSize(); } + private void setupPositionUpdater() { + if (positionEventDistributorFuture == null || + positionEventDistributorFuture.isCancelled() || + positionEventDistributorFuture.isDone()) { + Log.d(TAG, "Setting up position observer"); + positionEventDistributorFuture = positionEventDistributorExecutor.scheduleWithFixedDelay( + () -> EventBus.getDefault().post(new PlaybackPositionEvent()), 1000, 1000, TimeUnit.MILLISECONDS); + } + } + + private void cancelPositionObserver() { + if (positionEventDistributorFuture != null) { + boolean result = positionEventDistributorFuture.cancel(true); + Log.d(TAG, "PositionObserver cancelled. Result: " + result); + } + } + private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() { private static final String TAG = "MediaSessionCompat"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java index ac5418dd0..1456ebd8d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java @@ -21,11 +21,10 @@ import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.TextView; -import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.event.ServiceEvent; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -69,9 +68,6 @@ public class PlaybackController { private final ScheduledThreadPoolExecutor schedExecutor; private static final int SCHED_EX_POOLSIZE = 1; - private MediaPositionObserver positionObserver; - private ScheduledFuture positionObserverFuture; - private boolean mediaInfoLoaded = false; private boolean released = false; private boolean initialized = false; @@ -177,7 +173,6 @@ public class PlaybackController { } catch (IllegalArgumentException e) { // ignore } - cancelPositionObserver(); schedExecutor.shutdownNow(); media = null; released = true; @@ -254,29 +249,6 @@ public class PlaybackController { .getIntent()); } - - - private void setupPositionObserver() { - if (positionObserverFuture == null || - positionObserverFuture.isCancelled() || - positionObserverFuture.isDone()) { - - Log.d(TAG, "Setting up position observer"); - positionObserver = new MediaPositionObserver(); - positionObserverFuture = schedExecutor.scheduleWithFixedDelay( - positionObserver, MediaPositionObserver.WAITING_INTERVALL, - MediaPositionObserver.WAITING_INTERVALL, - TimeUnit.MILLISECONDS); - } - } - - private void cancelPositionObserver() { - if (positionObserverFuture != null) { - boolean result = positionObserverFuture.cancel(true); - Log.d(TAG, "PositionObserver cancelled. Result: " + result); - } - } - private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if(service instanceof PlaybackService.LocalBinder) { @@ -337,7 +309,6 @@ public class PlaybackController { onBufferUpdate(progress); break; case PlaybackService.NOTIFICATION_TYPE_RELOAD: - cancelPositionObserver(); mediaInfoLoaded = false; queryService(); onReloadNotification(intent.getIntExtra( @@ -447,7 +418,6 @@ public class PlaybackController { case PAUSED: clearStatusMsg(); checkMediaInfoLoaded(); - cancelPositionObserver(); onPositionObserverUpdate(); updatePlayButtonAppearance(playResource, playText); if (!PlaybackService.isCasting() && @@ -463,7 +433,6 @@ public class PlaybackController { onAwaitingVideoSurface(); setScreenOn(true); } - setupPositionObserver(); updatePlayButtonAppearance(pauseResource, pauseText); break; case PREPARING: @@ -581,7 +550,6 @@ public class PlaybackController { */ public void onSeekBarStartTrackingTouch(SeekBar seekBar) { // interrupt position Observer, restart later - cancelPositionObserver(); } /** @@ -590,7 +558,6 @@ public class PlaybackController { public void onSeekBarStopTrackingTouch(SeekBar seekBar, float prog) { if (playbackService != null && media != null) { playbackService.seekTo((int) (prog * media.getDuration())); - setupPositionObserver(); } } @@ -836,19 +803,4 @@ public class PlaybackController { } }, error -> Log.e(TAG, Log.getStackTraceString(error))); } - - /** - * Refreshes the current position of the media file that is playing. - */ - public class MediaPositionObserver implements Runnable { - - static final int WAITING_INTERVALL = 1000; - - @Override - public void run() { - if (playbackService != null && playbackService.getStatus() == PlayerStatus.PLAYING) { - activity.runOnUiThread(PlaybackController.this::onPositionObserverUpdate); - } - } - } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 646b3eba8a69f119af74494e737d4601e2f703e8 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 16:44:31 +0200 Subject: Listening to position updates in ExternalPlayerFragment --- .../danoeh/antennapod/fragment/ExternalPlayerFragment.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java index 348c73b92..9f136490a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -18,7 +18,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.event.ServiceEvent; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.service.playback.PlaybackService; @@ -28,6 +28,9 @@ import io.reactivex.Maybe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * Fragment which is supposed to be displayed outside of the MediaplayerActivity @@ -138,6 +141,7 @@ public class ExternalPlayerFragment extends Fragment { controller = setupPlaybackController(); controller.init(); loadMediaInfo(); + EventBus.getDefault().register(this); } @Override @@ -147,6 +151,12 @@ public class ExternalPlayerFragment extends Fragment { controller.release(); controller = null; } + EventBus.getDefault().unregister(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + onPositionObserverUpdate(); } @Override -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From f12d3a8c53fc62ad0753d062fa9a4c5b376e0cb2 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 16:48:26 +0200 Subject: Listening to position updates in MediaPlayerActivity --- .../de/danoeh/antennapod/activity/MediaplayerActivity.java | 11 +++++++++++ .../danoeh/antennapod/activity/MediaplayerInfoActivity.java | 2 -- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java index eefa35500..b9576cbd7 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -34,6 +34,7 @@ import com.joanzapata.iconify.IconDrawable; import com.joanzapata.iconify.fonts.FontAwesomeIcons; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; @@ -63,6 +64,9 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** @@ -194,6 +198,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements }; } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + onPositionObserverUpdate(); + } + private static TextView getTxtvFFFromActivity(MediaplayerActivity activity) { return activity.txtvFF; } @@ -274,6 +283,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements controller.init(); loadMediaInfo(); onPositionObserverUpdate(); + EventBus.getDefault().register(this); } @Override @@ -286,6 +296,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements if (disposable != null) { disposable.dispose(); } + EventBus.getDefault().unregister(this); super.onStop(); } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java index 5210bdc06..234962a8d 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java @@ -122,7 +122,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem disposable.dispose(); } EventDistributor.getInstance().unregister(contentUpdate); - EventBus.getDefault().unregister(this); saveCurrentFragment(); } @@ -175,7 +174,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem protected void onStart() { super.onStart(); EventDistributor.getInstance().register(contentUpdate); - EventBus.getDefault().register(this); loadData(); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 66cb923e9da60d1c13969f63e0074d1b0c749d24 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 17:07:24 +0200 Subject: Update playback position in queue --- .../antennapod/adapter/QueueRecyclerAdapter.java | 23 ++++++++++++++++++++++ .../danoeh/antennapod/fragment/QueueFragment.java | 8 ++++++++ .../core/event/PlaybackPositionEvent.java | 13 +++++++++++- .../core/service/playback/PlaybackService.java | 5 ++--- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java index 30057dde3..148b36d21 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.adapter; import android.os.Build; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.support.v4.view.MotionEventCompat; @@ -24,9 +25,11 @@ import android.widget.TextView; import com.joanzapata.iconify.Iconify; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import org.apache.commons.lang3.ArrayUtils; import java.lang.ref.WeakReference; +import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; @@ -57,6 +60,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter payload) { + onBindViewHolder(holder, pos); + + if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) { + PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0); + holder.progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + holder.progressLeft.setText(Converter.getDurationStringLong(event.getPosition())); + holder.progressRight.setText(Converter.getDurationStringLong(event.getDuration())); + } + } + @Nullable public FeedItem getSelectedItem() { return selectedItem; @@ -108,6 +124,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter EventBus.getDefault().post(new PlaybackPositionEvent()), 1000, 1000, TimeUnit.MILLISECONDS); + () -> EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration())), + 1000, 1000, TimeUnit.MILLISECONDS); } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 8c1e6206daf341b028cb56a8bc57fa6b86aedee2 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 17:13:17 +0200 Subject: Update playback position in all episodes list --- .../adapter/AllEpisodesRecycleAdapter.java | 23 +++++++++++++++++++++- .../antennapod/fragment/EpisodesListFragment.java | 8 ++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java index 85b5e3985..9eb181edc 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.adapter; import android.os.Build; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; @@ -23,10 +24,12 @@ import android.widget.TextView; import com.joanzapata.iconify.Iconify; import java.lang.ref.WeakReference; +import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.storage.DownloadRequester; @@ -50,6 +53,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter payload) { + onBindViewHolder(holder, pos); + + if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) { + PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0); + holder.progress.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + } + } + + public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event) { + if (currentlyPlayingItem != null && currentlyPlayingItem.getAdapterPosition() != RecyclerView.NO_POSITION) { + notifyItemChanged(currentlyPlayingItem.getAdapterPosition(), event); + } + } + @Nullable public FeedItem getSelectedItem() { return selectedItem; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 7c6e34d66..6cccba15f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -24,6 +24,7 @@ import android.widget.Toast; import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -384,6 +385,13 @@ public abstract class EpisodesListFragment extends Fragment { } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + if (listAdapter != null) { + listAdapter.notifyCurrentlyPlayingItemChanged(event); + } + } + protected boolean shouldUpdatedItemRemainInList(FeedItem item) { return true; } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 7bdc0b3ddd4ded34313c60bdfad86350d0f360ce Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 25 Sep 2019 17:37:17 +0200 Subject: Update playback position in feed details list --- .../antennapod/adapter/FeedItemlistAdapter.java | 21 ++++++++++++++++++++- .../antennapod/fragment/FeedItemlistFragment.java | 8 ++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) 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 d090bc4b1..463ad10a0 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -13,15 +13,18 @@ import android.widget.BaseAdapter; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.DateUtils; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.ThemeUtils; @@ -39,6 +42,8 @@ public class FeedItemlistAdapter extends BaseAdapter { private final int playingBackGroundColor; private final int normalBackGroundColor; + private int currentlyPlayingItem = -1; + public FeedItemlistAdapter(Context context, ItemAccess itemAccess, boolean showFeedtitle, @@ -176,8 +181,9 @@ public class FeedItemlistAdapter extends BaseAdapter { } typeDrawables.recycle(); - if(media.isCurrentlyPlaying()) { + if (media.isCurrentlyPlaying()) { holder.container.setBackgroundColor(playingBackGroundColor); + currentlyPlayingItem = position; } else { holder.container.setBackgroundColor(normalBackGroundColor); } @@ -195,6 +201,19 @@ public class FeedItemlistAdapter extends BaseAdapter { return convertView; } + public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event, ListView listView) { + if (currentlyPlayingItem != -1 && currentlyPlayingItem < getCount()) { + View view = listView.getChildAt(currentlyPlayingItem + - listView.getFirstVisiblePosition() + listView.getHeaderViewsCount()); + if (view == null) { + return; + } + Holder holder = (Holder) view.getTag(); + holder.episodeProgress.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + holder.lenSize.setText(Converter.getDurationStringLong(event.getDuration() - event.getPosition())); + } + } + static class Holder { LinearLayout container; TextView title; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index b4f479bcc..5c743fcda 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -29,6 +29,7 @@ import com.bumptech.glide.request.RequestOptions; import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.widget.IconTextView; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import org.apache.commons.lang3.Validate; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -398,6 +399,13 @@ public class FeedItemlistFragment extends ListFragment { } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + if (adapter != null) { + adapter.notifyCurrentlyPlayingItemChanged(event, getListView()); + } + } + private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { @Override -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From b94595fe44f4e75f2e5bdc27e5bb62a0e1f250fc Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 26 Sep 2019 18:47:24 +0200 Subject: Using RxJava to update position on main thread --- .../core/service/playback/PlaybackService.java | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index aced12b9c..f166749fb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -44,8 +44,6 @@ import com.bumptech.glide.request.target.Target; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.ClientConfig; @@ -76,6 +74,9 @@ import de.danoeh.antennapod.core.util.gui.NotificationUtils; import de.danoeh.antennapod.core.util.playback.ExternalMedia; import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; import org.greenrobot.eventbus.EventBus; /** @@ -214,9 +215,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { private PlaybackServiceTaskManager taskManager; private PlaybackServiceFlavorHelper flavorHelper; private PlaybackServiceStateManager stateManager; - - private final ScheduledThreadPoolExecutor positionEventDistributorExecutor = new ScheduledThreadPoolExecutor(1); - private ScheduledFuture positionEventDistributorFuture; + private Disposable positionEventTimer; /** * Used for Lollipop notifications, Android Wear, and Android Auto. @@ -336,8 +335,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { isRunning = false; currentMediaType = MediaType.UNKNOWN; - PreferenceManager.getDefaultSharedPreferences(this) - .unregisterOnSharedPreferenceChangeListener(prefListener); + cancelPositionObserver(); + PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(prefListener); if (mediaSession != null) { mediaSession.release(); } @@ -1661,20 +1660,20 @@ public class PlaybackService extends MediaBrowserServiceCompat { } private void setupPositionUpdater() { - if (positionEventDistributorFuture == null || - positionEventDistributorFuture.isCancelled() || - positionEventDistributorFuture.isDone()) { - Log.d(TAG, "Setting up position observer"); - positionEventDistributorFuture = positionEventDistributorExecutor.scheduleWithFixedDelay( - () -> EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration())), - 1000, 1000, TimeUnit.MILLISECONDS); + if (positionEventTimer != null) { + positionEventTimer.dispose(); } + + Log.d(TAG, "Setting up position observer"); + positionEventTimer = Observable.interval(1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> + EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration()))); } private void cancelPositionObserver() { - if (positionEventDistributorFuture != null) { - boolean result = positionEventDistributorFuture.cancel(true); - Log.d(TAG, "PositionObserver cancelled. Result: " + result); + if (positionEventTimer != null) { + positionEventTimer.dispose(); } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 56d08c429119a288a6f8f8eddc41b80f2559ffb3 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 26 Sep 2019 18:49:39 +0200 Subject: Using RxJava to update buffering --- .../core/service/playback/ExoPlayerWrapper.java | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index 7af33f8f9..af86db633 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -2,7 +2,6 @@ package de.danoeh.antennapod.core.service.playback; import android.content.Context; import android.net.Uri; -import android.os.Handler; import android.view.SurfaceHolder; import com.google.android.exoplayer2.C; @@ -25,36 +24,36 @@ import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.util.Util; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; import org.antennapod.audio.MediaPlayer; import de.danoeh.antennapod.core.util.playback.IPlayer; +import java.util.concurrent.TimeUnit; + public class ExoPlayerWrapper implements IPlayer { private final Context mContext; + private final Disposable bufferingUpdateDisposable; private SimpleExoPlayer mExoPlayer; private MediaSource mediaSource; private MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener; private MediaPlayer.OnCompletionListener audioCompletionListener; private MediaPlayer.OnErrorListener audioErrorListener; private MediaPlayer.OnBufferingUpdateListener bufferingUpdateListener; - private boolean shouldCheckBufferingUpdates = true; ExoPlayerWrapper(Context context) { mContext = context; mExoPlayer = createPlayer(); - Handler handler = new Handler(); // Main thread - handler.postDelayed(new Runnable() { - @Override - public void run() { - if (bufferingUpdateListener != null) { - bufferingUpdateListener.onBufferingUpdate(null, mExoPlayer.getBufferedPercentage()); - } - if (shouldCheckBufferingUpdates) { - handler.postDelayed(this, 2000); - } - } - }, 2000); + bufferingUpdateDisposable = Observable.interval(2, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> { + if (bufferingUpdateListener != null) { + bufferingUpdateListener.onBufferingUpdate(null, mExoPlayer.getBufferedPercentage()); + } + }); } private SimpleExoPlayer createPlayer() { @@ -168,7 +167,7 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void release() { - shouldCheckBufferingUpdates = false; + bufferingUpdateDisposable.dispose(); if (mExoPlayer != null) { mExoPlayer.release(); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 8b53268bfe89ef174411ca6adfa19cbd418c8440 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 26 Sep 2019 19:06:26 +0200 Subject: Refactored method for readability --- .../main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java | 2 +- .../main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java | 4 ++-- app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java | 4 ++-- .../main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java | 3 +-- core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java | 4 ++++ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 7c6e34d66..c0c23685a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -393,7 +393,7 @@ public abstract class EpisodesListFragment extends Fragment { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; downloaderList = update.downloaders; - if (isMenuInvalidationAllowed && isUpdatingFeeds != update.feedIds.length > 0) { + if (isMenuInvalidationAllowed && event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) { requireActivity().invalidateOptionsMenu(); } if (update.mediaIds.length > 0) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index b4f479bcc..1aad74466 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -390,10 +390,10 @@ public class FeedItemlistFragment extends ListFragment { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; downloaderList = update.downloaders; - if (isUpdatingFeed != event.update.feedIds.length > 0) { + if (event.hasChangedFeedUpdateStatus(isUpdatingFeed)) { updateProgressBarVisibility(); } - if(adapter != null && update.mediaIds.length > 0) { + if (adapter != null && update.mediaIds.length > 0) { adapter.notifyDataSetChanged(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index 34d128cc8..a1f5dca18 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -200,8 +200,8 @@ public class QueueFragment extends Fragment { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; downloaderList = update.downloaders; - if (isUpdatingFeeds != update.feedIds.length > 0) { - getActivity().supportInvalidateOptionsMenu(); + if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) { + getActivity().invalidateOptionsMenu(); } if (recyclerAdapter != null && update.mediaIds.length > 0) { for (long mediaId : update.mediaIds) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java index df02a38b2..ed315050b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java @@ -298,8 +298,7 @@ public class SubscriptionFragment extends Fragment { @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEventMainThread(DownloadEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); - DownloaderUpdate update = event.update; - if (isUpdatingFeeds != update.feedIds.length > 0) { + if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) { getActivity().invalidateOptionsMenu(); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java index 124fd3e64..24a71ec96 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java @@ -25,4 +25,8 @@ public class DownloadEvent { "update=" + update + '}'; } + + public boolean hasChangedFeedUpdateStatus(boolean oldStatus) { + return oldStatus != update.feedIds.length > 0; + } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 0c0e50d3ae2a0446e14f21231615089d798ae3fd Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 27 Sep 2019 12:03:36 +0200 Subject: Fixed another phantom service is running notification Steps to reproduce: - Send STOP key two times - Service starts foreground but does not stop again because stateManager does not know about foreground state --- .../de/danoeh/antennapod/core/service/playback/PlaybackService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index e479a7711..7d23b4c4c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -451,7 +451,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { notificationBuilder.loadIcon(getPlayable()); } } - startForeground(NOTIFICATION_ID, notificationBuilder.build()); + stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); } NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From d7f0f95adaa2adf15d3231994dab2eb469d8dd14 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 27 Sep 2019 12:48:15 +0200 Subject: Bumped version to 1.7.3b --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f9ef8a7ef..c9d6200d9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { // "1.2.3-SNAPSHOT" -> 1020300 // "1.2.3-RC4" -> 1020304 // "1.2.3" -> 1020395 - versionCode 1070395 - versionName "1.7.3" + versionCode 1070396 + versionName "1.7.3b" testApplicationId "de.test.antennapod" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" generatedDensities = [] -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 872b7a813db79107047f70a3513b4ae8c3d4ee32 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 27 Sep 2019 13:14:54 +0200 Subject: Moved reloading fragment to onCreate --- .../antennapod/fragment/FeedItemlistFragment.java | 38 ++++++++-------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index bb4f348fc..36c98e8b9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -138,14 +138,6 @@ public class FeedItemlistFragment extends ListFragment { feedID = args.getLong(ARGUMENT_FEED_ID); } - @Override - public void onStart() { - super.onStart(); - EventDistributor.getInstance().register(contentUpdate); - EventBus.getDefault().register(this); - loadItems(); - } - @Override public void onResume() { super.onResume(); @@ -154,22 +146,25 @@ public class FeedItemlistFragment extends ListFragment { } @Override - public void onStop() { - super.onStop(); - EventDistributor.getInstance().unregister(contentUpdate); - EventBus.getDefault().unregister(this); - if(disposable != null) { - disposable.dispose(); - } + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + registerForContextMenu(getListView()); + + EventDistributor.getInstance().register(contentUpdate); + EventBus.getDefault().register(this); + loadItems(); } @Override public void onDestroyView() { super.onDestroyView(); - resetViewState(); - } - private void resetViewState() { + EventDistributor.getInstance().unregister(contentUpdate); + EventBus.getDefault().unregister(this); + if (disposable != null) { + disposable.dispose(); + } adapter = null; listFooter = null; } @@ -342,13 +337,6 @@ public class FeedItemlistFragment extends ListFragment { return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem); } - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - registerForContextMenu(getListView()); - } - @Override public void onListItemClick(ListView l, View v, int position, long id) { if(adapter == null) { -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 5b909894f4bdb2f0cbfca3b5becdb7fb6106f3e8 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 27 Sep 2019 13:25:38 +0200 Subject: Keep background fragments alive --- .../main/java/de/danoeh/antennapod/activity/MainActivity.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java index 912f07747..7ee8ef8d5 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -389,14 +389,16 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi break; case FLIP: transaction.setCustomAnimations( - R.anim.card_flip_right_in, - R.anim.card_flip_right_out, R.anim.card_flip_left_in, - R.anim.card_flip_left_out); + R.anim.card_flip_left_out, + R.anim.card_flip_right_in, + R.anim.card_flip_right_out); break; } - transaction.replace(R.id.main_view, fragment, "main") + transaction + .hide(getSupportFragmentManager().findFragmentByTag("main")) + .add(R.id.main_view, fragment, "main") .addToBackStack(null) .commit(); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 6e5c4dd9d21ff5c5b7272fc97944fc484dbfb642 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 27 Sep 2019 14:01:10 +0200 Subject: Clear title on resume --- .../java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 36c98e8b9..81b7dda8a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -139,10 +139,11 @@ public class FeedItemlistFragment extends ListFragment { } @Override - public void onResume() { - super.onResume(); - ((MainActivity)getActivity()).getSupportActionBar().setTitle(""); - updateProgressBarVisibility(); + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + if (!hidden) { + ((MainActivity)getActivity()).getSupportActionBar().setTitle(""); + } } @Override -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From d80daee37e0e56573802a793b3dde6d1dc89fa0e Mon Sep 17 00:00:00 2001 From: orionlee Date: Thu, 12 Sep 2019 09:12:28 -0700 Subject: #3387 new permission for WiFi filter UI be compatible with Android 10+ --- core/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index 7d84bdddb..c57696072 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -9,11 +9,11 @@ - - + Date: Fri, 13 Sep 2019 12:00:22 -0700 Subject: #3387 ask for location permission for Wi-Fi filter UI on Android 10+. --- .../AutoDownloadPreferencesFragment.java | 87 +++++++++++++++++++++- core/src/main/res/values/strings.xml | 2 + 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index a04615a00..49a58a621 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -1,25 +1,31 @@ package de.danoeh.antennapod.fragment.preferences; +import android.Manifest; import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; +import android.os.Build; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; import android.support.v7.preference.CheckBoxPreference; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; import android.support.v7.preference.PreferenceScreen; import android.util.Log; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.preferences.UserPreferences; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.preferences.UserPreferences; + public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { private static final String TAG = "AutoDnldPrefFragment"; private CheckBoxPreference[] selectedNetworks; @@ -175,10 +181,87 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { } private void setSelectedNetworksEnabled(boolean b) { + if (permissionHelper.showPermissionRequestPromptOnAndroid10IfNeeded(b)) { + return; + } + if (selectedNetworks != null) { for (Preference p : selectedNetworks) { p.setEnabled(b); } } } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + permissionHelper.doOnRequestPermissionsResult(requestCode, permissions, grantResults); + } + + private class PermissionHelper { + private static final String requestedPermission = Manifest.permission.ACCESS_COARSE_LOCATION; + private static final int permissionRequestCode = 1; + + private static final String PREF_KEY_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt"; + + private Preference prefPermissionRequestPromptOnAndroid10 = null; + + void doOnRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode != permissionRequestCode) { + return; + } + if (permissions.length > 0 && permissions[0].equals(requestedPermission) && + grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + buildAutodownloadSelectedNetworksPreference(); + } + } + + boolean showPermissionRequestPromptOnAndroid10IfNeeded(boolean wifiFilterEnabled) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { + return false; + } + + // Cases Android 10(Q) or later + + final PreferenceScreen prefScreen = getPreferenceScreen(); + + if (prefPermissionRequestPromptOnAndroid10 != null) { + prefScreen.removePreference(prefPermissionRequestPromptOnAndroid10); + prefPermissionRequestPromptOnAndroid10 = null; + } + + + if (hasLocationPermission()) { + return false; + } + + // Case location permission not yet granted, permission-specific UI is needed + + if (!wifiFilterEnabled) { // don't show the UI when WiFi filter disabled + return true; + } + + Preference pref = new Preference(requireActivity()); + pref.setKey(PREF_KEY_PERMISSION_REQUEST_PROMPT); + pref.setTitle(R.string.autodl_wifi_filter_permission_title); + pref.setSummary(R.string.autodl_wifi_filter_permission_message); + pref.setOnPreferenceClickListener(preference -> { + requestLocationPermission(); + return true; + }); + pref.setPersistent(false); + getPreferenceScreen().addPreference(pref); + prefPermissionRequestPromptOnAndroid10 = pref; + + return true; + } + + private boolean hasLocationPermission() { + return ContextCompat.checkSelfPermission(requireContext(), requestedPermission) == PackageManager.PERMISSION_GRANTED; + } + + private void requestLocationPermission() { + requestPermissions(new String[]{requestedPermission}, permissionRequestCode); + } + } + private final PermissionHelper permissionHelper = new PermissionHelper(); } diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index c7bd2d2a2..adf938d75 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -394,6 +394,8 @@ Configure the automatic download of episodes. Enable Wi-Fi filter Allow automatic download only for selected Wi-Fi networks. + Permission required + Location permission is required for Wi-Fi filter. Tap to grant the permission. Download when not charging Allow automatic download when the battery is not charging Parallel Downloads -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From d559a8b9067d4efefd3ffcd45439909b1ac616ca Mon Sep 17 00:00:00 2001 From: orionlee Date: Fri, 13 Sep 2019 12:53:59 -0700 Subject: #3387 use ACCESS_FINE_LOCATION per Google feedback https://issuetracker.google.com/issues/140696830 --- .../fragment/preferences/AutoDownloadPreferencesFragment.java | 2 +- core/src/main/AndroidManifest.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index 49a58a621..4994e6594 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -198,7 +198,7 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { } private class PermissionHelper { - private static final String requestedPermission = Manifest.permission.ACCESS_COARSE_LOCATION; + private static final String requestedPermission = Manifest.permission.ACCESS_FINE_LOCATION; private static final int permissionRequestCode = 1; private static final String PREF_KEY_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt"; diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index c57696072..7d84bdddb 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -9,11 +9,11 @@ - - + Date: Sat, 14 Sep 2019 13:14:57 -0700 Subject: #3387 permission prompt - add warning icon to make it stand out. --- .../fragment/preferences/AutoDownloadPreferencesFragment.java | 1 + core/src/main/res/drawable/ic_warning_red.xml | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 core/src/main/res/drawable/ic_warning_red.xml diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index 4994e6594..7d1d98cfd 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -244,6 +244,7 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { pref.setKey(PREF_KEY_PERMISSION_REQUEST_PROMPT); pref.setTitle(R.string.autodl_wifi_filter_permission_title); pref.setSummary(R.string.autodl_wifi_filter_permission_message); + pref.setIcon(R.drawable.ic_warning_red); pref.setOnPreferenceClickListener(preference -> { requestLocationPermission(); return true; diff --git a/core/src/main/res/drawable/ic_warning_red.xml b/core/src/main/res/drawable/ic_warning_red.xml new file mode 100644 index 000000000..475a41bbb --- /dev/null +++ b/core/src/main/res/drawable/ic_warning_red.xml @@ -0,0 +1,5 @@ + + + -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 292aaa610ec261d959340cedc3eea66cb37fedd4 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 14 Sep 2019 13:15:50 -0700 Subject: #3387 permission prompt - add comments for case Wi-Fi filter not enabled. --- .../fragment/preferences/AutoDownloadPreferencesFragment.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index 7d1d98cfd..859016bbc 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -236,7 +236,10 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { // Case location permission not yet granted, permission-specific UI is needed - if (!wifiFilterEnabled) { // don't show the UI when WiFi filter disabled + if (!wifiFilterEnabled) { + // Don't show the UI when WiFi filter disabled. + // it still return true, so that the caller knows + // it does not have required permission, and will not invoke codes that require so. return true; } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 342fe60279d1079e562ed48dd3f3ad1438b7f1bc Mon Sep 17 00:00:00 2001 From: orionlee Date: Fri, 27 Sep 2019 10:46:23 -0700 Subject: Auto Wifi filter permission UI - flattened the logic back to the fragment per review. --- .../AutoDownloadPreferencesFragment.java | 113 ++++++++++----------- 1 file changed, 53 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index 859016bbc..f2ff71478 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -28,8 +28,15 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { private static final String TAG = "AutoDnldPrefFragment"; + + private static final String requestedPermission = Manifest.permission.ACCESS_FINE_LOCATION; + private static final int permissionRequestCode = 1; + private static final String PREF_KEY_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt"; + private CheckBoxPreference[] selectedNetworks; + private Preference prefPermissionRequestPromptOnAndroid10 = null; + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences_autodownload); @@ -181,7 +188,7 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { } private void setSelectedNetworksEnabled(boolean b) { - if (permissionHelper.showPermissionRequestPromptOnAndroid10IfNeeded(b)) { + if (showPermissionRequestPromptOnAndroid10IfNeeded(b)) { return; } @@ -194,78 +201,64 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - permissionHelper.doOnRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode != permissionRequestCode) { + return; + } + if (permissions.length > 0 && permissions[0].equals(requestedPermission) && + grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + buildAutodownloadSelectedNetworksPreference(); + } } - private class PermissionHelper { - private static final String requestedPermission = Manifest.permission.ACCESS_FINE_LOCATION; - private static final int permissionRequestCode = 1; - - private static final String PREF_KEY_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt"; - - private Preference prefPermissionRequestPromptOnAndroid10 = null; - - void doOnRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode != permissionRequestCode) { - return; - } - if (permissions.length > 0 && permissions[0].equals(requestedPermission) && - grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - buildAutodownloadSelectedNetworksPreference(); - } + private boolean showPermissionRequestPromptOnAndroid10IfNeeded(boolean wifiFilterEnabled) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { + return false; } - boolean showPermissionRequestPromptOnAndroid10IfNeeded(boolean wifiFilterEnabled) { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { - return false; - } - - // Cases Android 10(Q) or later - - final PreferenceScreen prefScreen = getPreferenceScreen(); - - if (prefPermissionRequestPromptOnAndroid10 != null) { - prefScreen.removePreference(prefPermissionRequestPromptOnAndroid10); - prefPermissionRequestPromptOnAndroid10 = null; - } + // Cases Android 10(Q) or later + final PreferenceScreen prefScreen = getPreferenceScreen(); - if (hasLocationPermission()) { - return false; - } + if (prefPermissionRequestPromptOnAndroid10 != null) { + prefScreen.removePreference(prefPermissionRequestPromptOnAndroid10); + prefPermissionRequestPromptOnAndroid10 = null; + } - // Case location permission not yet granted, permission-specific UI is needed - if (!wifiFilterEnabled) { - // Don't show the UI when WiFi filter disabled. - // it still return true, so that the caller knows - // it does not have required permission, and will not invoke codes that require so. - return true; - } + if (hasLocationPermission()) { + return false; + } - Preference pref = new Preference(requireActivity()); - pref.setKey(PREF_KEY_PERMISSION_REQUEST_PROMPT); - pref.setTitle(R.string.autodl_wifi_filter_permission_title); - pref.setSummary(R.string.autodl_wifi_filter_permission_message); - pref.setIcon(R.drawable.ic_warning_red); - pref.setOnPreferenceClickListener(preference -> { - requestLocationPermission(); - return true; - }); - pref.setPersistent(false); - getPreferenceScreen().addPreference(pref); - prefPermissionRequestPromptOnAndroid10 = pref; + // Case location permission not yet granted, permission-specific UI is needed + if (!wifiFilterEnabled) { + // Don't show the UI when WiFi filter disabled. + // it still return true, so that the caller knows + // it does not have required permission, and will not invoke codes that require so. return true; } - private boolean hasLocationPermission() { - return ContextCompat.checkSelfPermission(requireContext(), requestedPermission) == PackageManager.PERMISSION_GRANTED; - } + Preference pref = new Preference(requireActivity()); + pref.setKey(PREF_KEY_PERMISSION_REQUEST_PROMPT); + pref.setTitle(R.string.autodl_wifi_filter_permission_title); + pref.setSummary(R.string.autodl_wifi_filter_permission_message); + pref.setIcon(R.drawable.ic_warning_red); + pref.setOnPreferenceClickListener(preference -> { + requestLocationPermission(); + return true; + }); + pref.setPersistent(false); + getPreferenceScreen().addPreference(pref); + prefPermissionRequestPromptOnAndroid10 = pref; - private void requestLocationPermission() { - requestPermissions(new String[]{requestedPermission}, permissionRequestCode); - } + return true; + } + + private boolean hasLocationPermission() { + return ContextCompat.checkSelfPermission(requireContext(), requestedPermission) == PackageManager.PERMISSION_GRANTED; + } + + private void requestLocationPermission() { + requestPermissions(new String[]{requestedPermission}, permissionRequestCode); } - private final PermissionHelper permissionHelper = new PermissionHelper(); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 0b5f4e9dc0b87d500a4139744883eb052e4815c7 Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 23 Sep 2019 03:50:00 -0700 Subject: Avoid Cast initialization unless it is enabled (to avoid triggering Google Play Service) --- .../antennapod/activity/CastEnabledActivity.java | 55 ++++++++++++++++------ .../de/danoeh/antennapod/core/ClientConfig.java | 13 ++++- .../danoeh/antennapod/core/cast/CastManager.java | 4 ++ .../playback/PlaybackServiceFlavorHelper.java | 31 ++++++++++++ 4 files changed, 87 insertions(+), 16 deletions(-) diff --git a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java index 87304b3d6..c39be8870 100644 --- a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java +++ b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java @@ -29,17 +29,34 @@ public abstract class CastEnabledActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String TAG = "CastEnabledActivity"; - protected CastManager castManager; - protected SwitchableMediaRouteActionProvider mediaRouteActionProvider; + private CastConsumer castConsumer; + private CastManager castManager; + + private SwitchableMediaRouteActionProvider mediaRouteActionProvider; private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (!CastManager.isInitialized()) { + return; + } + PreferenceManager.getDefaultSharedPreferences(getApplicationContext()). registerOnSharedPreferenceChangeListener(this); + castConsumer = new DefaultCastConsumer() { + @Override + public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { + onCastConnectionChanged(true); + } + + @Override + public void onDisconnected() { + onCastConnectionChanged(false); + } + }; castManager = CastManager.getInstance(); castManager.addCastConsumer(castConsumer); castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled()); @@ -48,6 +65,10 @@ public abstract class CastEnabledActivity extends AppCompatActivity @Override protected void onDestroy() { + if (!CastManager.isInitialized()) { + super.onDestroy(); + return; + } PreferenceManager.getDefaultSharedPreferences(getApplicationContext()) .unregisterOnSharedPreferenceChangeListener(this); castManager.removeCastConsumer(castConsumer); @@ -58,6 +79,9 @@ public abstract class CastEnabledActivity extends AppCompatActivity @CallSuper public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); + if (!CastManager.isInitialized()) { + return true; + } getMenuInflater().inflate(R.menu.cast_enabled, menu); castButtonVisibilityManager.setMenu(menu); return true; @@ -67,6 +91,10 @@ public abstract class CastEnabledActivity extends AppCompatActivity @CallSuper public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); + if (!CastManager.isInitialized()) { + return true; + } + MenuItem mediaRouteButton = menu.findItem(R.id.media_route_menu_item); if (mediaRouteButton == null) { Log.wtf(TAG, "MediaRoute item could not be found on the menu!", new Exception()); @@ -83,15 +111,21 @@ public abstract class CastEnabledActivity extends AppCompatActivity @Override protected void onResume() { super.onResume(); + if (!CastManager.isInitialized()) { + return; + } castButtonVisibilityManager.setResumed(true); } @Override protected void onPause() { super.onPause(); - castButtonVisibilityManager.setResumed(false); + if (!CastManager.isInitialized()) { + return; + } } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (UserPreferences.PREF_CAST_ENABLED.equals(key)) { @@ -105,18 +139,6 @@ public abstract class CastEnabledActivity extends AppCompatActivity } } - CastConsumer castConsumer = new DefaultCastConsumer() { - @Override - public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { - onCastConnectionChanged(true); - } - - @Override - public void onDisconnected() { - onCastConnectionChanged(false); - } - }; - private void onCastConnectionChanged(boolean connected) { if (connected) { castButtonVisibilityManager.onConnected(); @@ -133,6 +155,9 @@ public abstract class CastEnabledActivity extends AppCompatActivity * @param showAsAction refer to {@link MenuItem#setShowAsAction(int)} */ public final void requestCastButton(int showAsAction) { + if (!CastManager.isInitialized()) { + return; + } castButtonVisibilityManager.requestCastButton(showAsAction); } diff --git a/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java b/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java index 244fb0254..800222ada 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java +++ b/core/src/play/java/de/danoeh/antennapod/core/ClientConfig.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.core; import android.content.Context; +import android.util.Log; import de.danoeh.antennapod.core.cast.CastManager; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; @@ -15,6 +16,8 @@ import de.danoeh.antennapod.core.util.exception.RxJavaErrorHandlerSetup; * Apps using the core module of AntennaPod should register implementations of all interfaces here. */ public class ClientConfig { + private static final String TAG = "ClientConfig"; + private ClientConfig(){} /** @@ -44,7 +47,15 @@ public class ClientConfig { UserPreferences.init(context); PlaybackPreferences.init(context); NetworkUtils.init(context); - CastManager.init(context); + // Don't initialize Cast-related logic unless it is enabled, to avoid the unnecessary + // Google Play Service usage. + // Down side: when the user decides to enable casting, AntennaPod needs to be restarted + // for it to take effect. + if (UserPreferences.isCastEnabled()) { + CastManager.init(context); + } else { + Log.v(TAG, "Cast is disabled. All Cast-related initialization will be skipped."); + } SleepTimerPreferences.init(context); RxJavaErrorHandlerSetup.setupRxJavaErrorHandler(); initialized = true; diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java index 5198a76bd..414a7840c 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java +++ b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java @@ -163,6 +163,10 @@ public class CastManager extends BaseCastManager implements OnFailedListener { return INSTANCE; } + public static boolean isInitialized() { + return INSTANCE != null; + } + /** * Returns the active {@link RemoteMediaPlayer} instance. Since there are a number of media * control APIs that this library do not provide a wrapper for, client applications can call diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java b/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java index 7ab1be380..79c71f164 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java +++ b/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java @@ -56,11 +56,18 @@ public class PlaybackServiceFlavorHelper { PlaybackServiceFlavorHelper(Context context, PlaybackService.FlavorHelperCallback callback) { this.callback = callback; + if (!CastManager.isInitialized()) { + return; + } mediaRouter = MediaRouter.getInstance(context.getApplicationContext()); setCastConsumer(context); } void initializeMediaPlayer(Context context) { + if (!CastManager.isInitialized()) { + callback.setMediaPlayer(new LocalPSMP(context, callback.getMediaPlayerCallback())); + return; + } castManager = CastManager.getInstance(); castManager.addCastConsumer(castConsumer); boolean isCasting = castManager.isConnected(); @@ -77,10 +84,16 @@ public class PlaybackServiceFlavorHelper { } void removeCastConsumer() { + if (!CastManager.isInitialized()) { + return; + } castManager.removeCastConsumer(castConsumer); } boolean castDisconnect(boolean castDisconnect) { + if (!CastManager.isInitialized()) { + return false; + } if (castDisconnect) { castManager.disconnect(); } @@ -88,6 +101,9 @@ public class PlaybackServiceFlavorHelper { } boolean onMediaPlayerInfo(Context context, int code, @StringRes int resourceId) { + if (!CastManager.isInitialized()) { + return false; + } switch (code) { case RemotePSMP.CAST_ERROR: callback.sendNotificationBroadcast(PlaybackService.NOTIFICATION_TYPE_SHOW_TOAST, resourceId); @@ -218,6 +234,9 @@ public class PlaybackServiceFlavorHelper { } void registerWifiBroadcastReceiver() { + if (!CastManager.isInitialized()) { + return; + } if (wifiBroadcastReceiver != null) { return; } @@ -243,6 +262,9 @@ public class PlaybackServiceFlavorHelper { } void unregisterWifiBroadcastReceiver() { + if (!CastManager.isInitialized()) { + return; + } if (wifiBroadcastReceiver != null) { callback.unregisterReceiver(wifiBroadcastReceiver); wifiBroadcastReceiver = null; @@ -250,6 +272,9 @@ public class PlaybackServiceFlavorHelper { } boolean onSharedPreference(String key) { + if (!CastManager.isInitialized()) { + return false; + } if (UserPreferences.PREF_CAST_ENABLED.equals(key)) { if (!UserPreferences.isCastEnabled()) { if (castManager.isConnecting() || castManager.isConnected()) { @@ -263,6 +288,9 @@ public class PlaybackServiceFlavorHelper { } void sessionStateAddActionForWear(PlaybackStateCompat.Builder sessionState, String actionName, CharSequence name, int icon) { + if (!CastManager.isInitialized()) { + return; + } PlaybackStateCompat.CustomAction.Builder actionBuilder = new PlaybackStateCompat.CustomAction.Builder(actionName, name, icon); Bundle actionExtras = new Bundle(); @@ -273,6 +301,9 @@ public class PlaybackServiceFlavorHelper { } void mediaSessionSetExtraForWear(MediaSessionCompat mediaSession) { + if (!CastManager.isInitialized()) { + return; + } Bundle sessionExtras = new Bundle(); sessionExtras.putBoolean(MediaControlConstants.EXTRA_RESERVE_SLOT_SKIP_TO_PREVIOUS, true); sessionExtras.putBoolean(MediaControlConstants.EXTRA_RESERVE_SLOT_SKIP_TO_NEXT, true); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 2fe70c3b41fb74e10d3b98b2d3ffbd3131d2708a Mon Sep 17 00:00:00 2001 From: orionlee Date: Fri, 27 Sep 2019 11:56:07 -0700 Subject: Avoid Cast initialization UI - prompt users to restart upon settings changed. --- .../preferences/PreferenceControllerFlavorHelper.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java index c9d52df0c..6db2ad7b0 100644 --- a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java +++ b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java @@ -1,8 +1,13 @@ package de.danoeh.antennapod.preferences; +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.app.AlertDialog; + import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; +import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment; @@ -18,6 +23,7 @@ public class PreferenceControllerFlavorHelper { final int googlePlayServicesCheck = GoogleApiAvailability.getInstance() .isGooglePlayServicesAvailable(ui.getActivity()); if (googlePlayServicesCheck == ConnectionResult.SUCCESS) { + displayRestartRequiredDialog(ui.requireContext()); return true; } else { GoogleApiAvailability.getInstance() @@ -26,7 +32,16 @@ public class PreferenceControllerFlavorHelper { return false; } } + displayRestartRequiredDialog(ui.requireContext()); return true; }); } + + private static void displayRestartRequiredDialog(@NonNull Context context) { + AlertDialog.Builder dialog = new AlertDialog.Builder(context); + dialog.setTitle(android.R.string.dialog_alert_title); + dialog.setMessage(R.string.pref_restart_required); + dialog.setPositiveButton(android.R.string.ok, null); + dialog.show(); + } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 3041336b92f84f902c75e897316aa19075f9a34d Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 28 Sep 2019 13:04:40 +0200 Subject: Do not notify cancelled downloads --- .../antennapod/core/service/download/DownloadService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index 0f346893e..37d778fd6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -1058,7 +1058,13 @@ public class DownloadService extends Service { private final Runnable postDownloaderTask = new Runnable() { @Override public void run() { - List list = Collections.unmodifiableList(downloads); + List runningDownloads = new ArrayList<>(); + for (Downloader downloader : downloads) { + if (!downloader.cancelled) { + runningDownloads.add(downloader); + } + } + List list = Collections.unmodifiableList(runningDownloads); EventBus.getDefault().postSticky(DownloadEvent.refresh(list)); postHandler.postDelayed(postDownloaderTask, 1500); } @@ -1076,6 +1082,9 @@ public class DownloadService extends Service { private static String compileNotificationString(List downloads) { List lines = new ArrayList<>(downloads.size()); for (Downloader downloader : downloads) { + if (downloader.cancelled) { + continue; + } StringBuilder line = new StringBuilder("• "); DownloadRequest request = downloader.getDownloadRequest(); switch (request.getFeedfileType()) { -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 66cf4a8a438a740ca521b91b0a03a73bdc5d43fc Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 28 Sep 2019 14:20:57 +0200 Subject: Sending event if download was cancelled --- .../core/service/download/DownloadService.java | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index 37d778fd6..ce61bff68 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -13,6 +13,7 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; @@ -190,10 +191,8 @@ public class DownloadService extends Service { handleFailedDownload(status, downloader.getDownloadRequest()); if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { - long id = status.getFeedfileId(); - FeedMedia media = DBReader.getFeedMedia(id); - FeedItem item; - if (media == null || (item = media.getItem()) == null) { + FeedItem item = getFeedItemFromId(status.getFeedfileId()); + if (item == null) { return; } boolean httpNotFound = status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR @@ -213,9 +212,8 @@ public class DownloadService extends Service { // if FeedMedia download has been canceled, fake FeedItem update // so that lists reload that it if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { - FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId()); - FeedItem item; - if (media == null || (item = media.getItem()) == null) { + FeedItem item = getFeedItemFromId(status.getFeedfileId()); + if (item == null) { return; } EventBus.getDefault().post(FeedItemEvent.updated(item)); @@ -386,6 +384,12 @@ public class DownloadService extends Service { Downloader d = getDownloader(url); if (d != null) { d.cancel(); + DownloadRequester.getInstance().removeDownload(d.getDownloadRequest()); + + FeedItem item = getFeedItemFromId(d.getDownloadRequest().getFeedfileId()); + if (item != null) { + EventBus.getDefault().post(FeedItemEvent.updated(item)); + } } else { Log.e(TAG, "Could not cancel download with url " + url); } @@ -578,6 +582,16 @@ public class DownloadService extends Service { syncExecutor.execute(new FailedDownloadHandler(status, request)); } + @Nullable + private FeedItem getFeedItemFromId(long id) { + FeedMedia media = DBReader.getFeedMedia(id); + if (media != null) { + return media.getItem(); + } else { + return null; + } + } + /** * Takes a single Feed, parses the corresponding file and refreshes * information in the manager -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 28a816b16cdc21e212fcae78b1d1ae92081b82b5 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 28 Sep 2019 17:23:36 +0200 Subject: Enabled more checkstyle rules --- config/checkstyle/checkstyle.xml | 54 ++++++++++++++++++++++ .../de/danoeh/antennapod/core/util/Optional.java | 2 +- .../core/util/id3reader/ChapterReader.java | 2 +- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 4bc3d0b51..0a5b47eb8 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -10,6 +10,7 @@ + @@ -17,12 +18,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java b/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java index 0fe11ec53..37f12c01c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/Optional.java @@ -77,7 +77,7 @@ public final class Optional { * @param Type of the non-existent value * @return an empty {@code Optional} */ - public static Optional empty() { + public static Optional empty() { @SuppressWarnings("unchecked") Optional t = (Optional) EMPTY; return t; diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java index d22d08e09..a3f747e09 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java @@ -72,7 +72,7 @@ public class ChapterReader extends ID3Reader { String decodedLink = URLDecoder.decode(link.toString(), "UTF-8"); currentChapter.setLink(decodedLink); Log.d(TAG, "Found link: " + currentChapter.getLink()); - } catch (IllegalArgumentException _iae) { + } catch (IllegalArgumentException iae) { Log.w(TAG, "Bad URL found in ID3 data"); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 7ae393479436e26d41fa1edbd8a157771a25466b Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Sat, 28 Sep 2019 18:11:08 +0200 Subject: Fix the smart shuffle spread calculation We want to ensure that the total spread is divisible by all feed sizes, so the modulo calculation needs to divide spread by the feed size, not the other way round as is done currently. In addition, this ensures the per-feed spread is never 0 (so the degenerate case is equivalent to the old smart shuffle). Signed-off-by: Stephen Kitt --- core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java index 37172d042..0c21ca393 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java @@ -164,7 +164,7 @@ public class QueueSorter { Collections.sort(feedItems, itemComparator); if (spread == 0) { spread = feedItems.size(); - } else if (feedItems.size() % spread != 0){ + } else if (spread % feedItems.size() != 0){ spread *= feedItems.size(); } } @@ -180,6 +180,9 @@ public class QueueSorter { Map> spreadItems = new HashMap<>(); for (List feedItems : feeds) { long thisSpread = spread / feedItems.size(); + if (thisSpread == 0) { + thisSpread = 1; + } // Starting from 0 ensures we front-load, so the queue starts with one episode from // each feed in the queue long itemSpread = 0; -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From d6e2803bebca2b42305039a0c265b7e10d870eda Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 28 Sep 2019 13:04:39 -0700 Subject: Wifi Filter UI - code style tweaks, mainly inlining. --- .../AutoDownloadPreferencesFragment.java | 31 +++++++--------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index f2ff71478..d0c209326 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -29,9 +29,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { private static final String TAG = "AutoDnldPrefFragment"; - private static final String requestedPermission = Manifest.permission.ACCESS_FINE_LOCATION; - private static final int permissionRequestCode = 1; - private static final String PREF_KEY_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt"; + private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; + private static final String PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt"; private CheckBoxPreference[] selectedNetworks; @@ -201,10 +200,10 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode != permissionRequestCode) { + if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { return; } - if (permissions.length > 0 && permissions[0].equals(requestedPermission) && + if (permissions.length > 0 && permissions[0].equals(Manifest.permission.ACCESS_FINE_LOCATION) && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { buildAutodownloadSelectedNetworksPreference(); } @@ -216,21 +215,17 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { } // Cases Android 10(Q) or later - - final PreferenceScreen prefScreen = getPreferenceScreen(); - if (prefPermissionRequestPromptOnAndroid10 != null) { - prefScreen.removePreference(prefPermissionRequestPromptOnAndroid10); + getPreferenceScreen().removePreference(prefPermissionRequestPromptOnAndroid10); prefPermissionRequestPromptOnAndroid10 = null; } - - if (hasLocationPermission()) { + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { return false; } // Case location permission not yet granted, permission-specific UI is needed - if (!wifiFilterEnabled) { // Don't show the UI when WiFi filter disabled. // it still return true, so that the caller knows @@ -239,26 +234,18 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { } Preference pref = new Preference(requireActivity()); - pref.setKey(PREF_KEY_PERMISSION_REQUEST_PROMPT); + pref.setKey(PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT); pref.setTitle(R.string.autodl_wifi_filter_permission_title); pref.setSummary(R.string.autodl_wifi_filter_permission_message); pref.setIcon(R.drawable.ic_warning_red); pref.setOnPreferenceClickListener(preference -> { - requestLocationPermission(); + requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); return true; }); pref.setPersistent(false); getPreferenceScreen().addPreference(pref); prefPermissionRequestPromptOnAndroid10 = pref; - return true; } - private boolean hasLocationPermission() { - return ContextCompat.checkSelfPermission(requireContext(), requestedPermission) == PackageManager.PERMISSION_GRANTED; - } - - private void requestLocationPermission() { - requestPermissions(new String[]{requestedPermission}, permissionRequestCode); - } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 9373b61787a926235080e60b144cf7af66e5ea0a Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 28 Sep 2019 13:26:30 -0700 Subject: Avoid Cast Initialization - bugfix of accidental removal of cast-enabled codes --- app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java index c39be8870..caca8a6e3 100644 --- a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java +++ b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java @@ -123,6 +123,7 @@ public abstract class CastEnabledActivity extends AppCompatActivity if (!CastManager.isInitialized()) { return; } + castButtonVisibilityManager.setResumed(false); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 78aecac3cabde5e28d8a97ac7600cebbf217b15c Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 28 Sep 2019 13:28:12 -0700 Subject: Avoid Cast Initialization UI - prompt restart only when enabled. Make prompt more sticky by being not cancelable. --- .../danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java index 6db2ad7b0..0e69da61e 100644 --- a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java +++ b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java @@ -32,7 +32,6 @@ public class PreferenceControllerFlavorHelper { return false; } } - displayRestartRequiredDialog(ui.requireContext()); return true; }); } @@ -42,6 +41,7 @@ public class PreferenceControllerFlavorHelper { dialog.setTitle(android.R.string.dialog_alert_title); dialog.setMessage(R.string.pref_restart_required); dialog.setPositiveButton(android.R.string.ok, null); + dialog.setCancelable(false); dialog.show(); } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 3beda73e3cc9ba391285c0c474b9b969d89a0fd8 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 12:39:13 +0200 Subject: Do not reinit on pause --- .../de/danoeh/antennapod/core/service/playback/PlaybackService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index a3535616e..4fd2d5e64 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -566,7 +566,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: if (status == PlayerStatus.PLAYING) { - mediaPlayer.pause(!UserPreferences.isPersistNotify(), true); + mediaPlayer.pause(!UserPreferences.isPersistNotify(), false); } else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) { mediaPlayer.resume(); } else if (status == PlayerStatus.PREPARING) { @@ -590,7 +590,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { return true; case KeyEvent.KEYCODE_MEDIA_PAUSE: if (status == PlayerStatus.PLAYING) { - mediaPlayer.pause(!UserPreferences.isPersistNotify(), true); + mediaPlayer.pause(!UserPreferences.isPersistNotify(), false); } return true; -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From fc317e3b687d097a8ea6074ef08b116979d49e2c Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 12:49:06 +0200 Subject: Keep 30 seconds of back buffer --- .../de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index c3b412012..13349dfdd 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -63,6 +63,7 @@ public class ExoPlayerWrapper implements IPlayer { loadControl.setBufferDurationsMs(30000, 120000, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS); + loadControl.setBackBuffer(30000, true); SimpleExoPlayer p = ExoPlayerFactory.newSimpleInstance(mContext, new DefaultRenderersFactory(mContext), new DefaultTrackSelector(), loadControl.createDefaultLoadControl()); p.setSeekParameters(SeekParameters.PREVIOUS_SYNC); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 510f00e2047ec9a6a2690f77709bea6269bcc28f Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 12:55:27 +0200 Subject: Making sure that we don't miss updates --- .../java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index f5290bd85..5c70a5973 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -409,8 +409,9 @@ public class FeedItemlistFragment extends ListFragment { } - private void onFragmentLoaded() { - if(!isVisible()) { + private void displayList() { + if (getView() == null) { + Log.e(TAG, "Required root view is not yet created. Stop binding data to UI."); return; } if (adapter == null) { @@ -612,7 +613,7 @@ public class FeedItemlistFragment extends ListFragment { .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { feed = result.orElse(null); - onFragmentLoaded(); + displayList(); }, error -> Log.e(TAG, Log.getStackTraceString(error))); } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 1c60a0134d5bd44638111074aaafff2142ce195b Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 14:05:48 +0200 Subject: Keep buffer depending on rewind time --- .../de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index 13349dfdd..556aad573 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -26,6 +26,7 @@ import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.util.Util; +import de.danoeh.antennapod.core.preferences.UserPreferences; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; @@ -63,7 +64,7 @@ public class ExoPlayerWrapper implements IPlayer { loadControl.setBufferDurationsMs(30000, 120000, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS, DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS); - loadControl.setBackBuffer(30000, true); + loadControl.setBackBuffer(UserPreferences.getRewindSecs() * 1000 + 500, true); SimpleExoPlayer p = ExoPlayerFactory.newSimpleInstance(mContext, new DefaultRenderersFactory(mContext), new DefaultTrackSelector(), loadControl.createDefaultLoadControl()); p.setSeekParameters(SeekParameters.PREVIOUS_SYNC); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From a3598daaa715774a9de16d9ee78d155fe99b36c6 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 14:25:24 +0200 Subject: Moved storing PlaybackPreferences to PlaybackPreferences --- .../core/preferences/PlaybackPreferences.java | 69 +++++++++++++++--- .../core/service/playback/PlaybackService.java | 83 ++-------------------- 2 files changed, 63 insertions(+), 89 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java index a4cc22d8b..f2c0c8fe3 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java @@ -4,7 +4,12 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import android.util.Log; import de.danoeh.antennapod.core.feed.EventDistributor; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.feed.MediaType; +import de.danoeh.antennapod.core.service.playback.PlayerStatus; +import de.danoeh.antennapod.core.util.playback.Playable; /** * Provides access to preferences set by the playback service. A private @@ -19,35 +24,35 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference * Contains the feed id of the currently playing item if it is a FeedMedia * object. */ - public static final String PREF_CURRENTLY_PLAYING_FEED_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedId"; + private static final String PREF_CURRENTLY_PLAYING_FEED_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedId"; /** * Contains the id of the currently playing FeedMedia object or * NO_MEDIA_PLAYING if the currently playing media is no FeedMedia object. */ - public static final String PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedMediaId"; + private static final String PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedMediaId"; /** * Type of the media object that is currently being played. This preference * is set to NO_MEDIA_PLAYING after playback has been completed and is set * as soon as the 'play' button is pressed. */ - public static final String PREF_CURRENTLY_PLAYING_MEDIA = "de.danoeh.antennapod.preferences.currentlyPlayingMedia"; + private static final String PREF_CURRENTLY_PLAYING_MEDIA = "de.danoeh.antennapod.preferences.currentlyPlayingMedia"; /** * True if last played media was streamed. */ - public static final String PREF_CURRENT_EPISODE_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream"; + private static final String PREF_CURRENT_EPISODE_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream"; /** * True if last played media was a video. */ - public static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo"; + private static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo"; /** * The current player status as int. */ - public static final String PREF_CURRENT_PLAYER_STATUS = "de.danoeh.antennapod.preferences.currentPlayerStatus"; + private static final String PREF_CURRENT_PLAYER_STATUS = "de.danoeh.antennapod.preferences.currentPlayerStatus"; /** * Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing. @@ -87,10 +92,6 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference } } - public static long getLastPlayedFeedId() { - return prefs.getLong(PREF_CURRENTLY_PLAYING_FEED_ID, -1); - } - public static long getCurrentlyPlayingMedia() { return prefs.getLong(PREF_CURRENTLY_PLAYING_MEDIA, NO_MEDIA_PLAYING); } @@ -119,4 +120,52 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference editor.putInt(PREF_CURRENT_PLAYER_STATUS, PLAYER_STATUS_OTHER); editor.apply(); } + + public static void writeMediaPlaying(Playable playable, PlayerStatus playerStatus, boolean stream) { + Log.d(TAG, "Writing playback preferences"); + SharedPreferences.Editor editor = prefs.edit(); + + if (playable == null) { + writeNoMediaPlaying(); + } else { + editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA, playable.getPlayableType()); + editor.putBoolean(PREF_CURRENT_EPISODE_IS_STREAM, stream); + editor.putBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, playable.getMediaType() == MediaType.VIDEO); + if (playable instanceof FeedMedia) { + FeedMedia fMedia = (FeedMedia) playable; + editor.putLong(PREF_CURRENTLY_PLAYING_FEED_ID, fMedia.getItem().getFeed().getId()); + editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, fMedia.getId()); + } else { + editor.putLong(PREF_CURRENTLY_PLAYING_FEED_ID, NO_MEDIA_PLAYING); + editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING); + } + playable.writeToPreferences(editor); + } + editor.putInt(PREF_CURRENT_PLAYER_STATUS, getCurrentPlayerStatusAsInt(playerStatus)); + + editor.apply(); + } + + public static void writePlayerStatus(PlayerStatus playerStatus) { + Log.d(TAG, "Writing player status playback preferences"); + + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(PREF_CURRENT_PLAYER_STATUS, getCurrentPlayerStatusAsInt(playerStatus)); + editor.apply(); + } + + private static int getCurrentPlayerStatusAsInt(PlayerStatus playerStatus) { + int playerStatusAsInt; + switch (playerStatus) { + case PLAYING: + playerStatusAsInt = PLAYER_STATUS_PLAYING; + break; + case PAUSED: + playerStatusAsInt = PLAYER_STATUS_PAUSED; + break; + default: + playerStatusAsInt = PLAYER_STATUS_OTHER; + } + return playerStatusAsInt; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index d25b528c2..e58d5cb31 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -721,7 +721,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { updateMediaSession(newInfo.playerStatus); switch (newInfo.playerStatus) { case INITIALIZED: - writePlaybackPreferences(); + PlaybackPreferences.writeMediaPlaying(mediaPlayer.getPSMPInfo().playable, + mediaPlayer.getPSMPInfo().playerStatus, mediaPlayer.isStreaming()); break; case PREPARED: @@ -739,7 +740,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { stateManager.stopForeground(true); } cancelPositionObserver(); - writePlayerStatusPlaybackPreferences(); + PlaybackPreferences.writePlayerStatus(mediaPlayer.getPlayerStatus()); break; case STOPPED: @@ -748,7 +749,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { break; case PLAYING: - writePlayerStatusPlaybackPreferences(); + PlaybackPreferences.writePlayerStatus(mediaPlayer.getPlayerStatus()); setupNotification(newInfo); setupPositionUpdater(); stateManager.validStartCommandWasReceived(); @@ -1029,82 +1030,6 @@ public class PlaybackService extends MediaBrowserServiceCompat { EventBus.getDefault().post(new MessageEvent(getString(R.string.sleep_timer_disabled_label))); } - private int getCurrentPlayerStatusAsInt(PlayerStatus playerStatus) { - int playerStatusAsInt; - switch (playerStatus) { - case PLAYING: - playerStatusAsInt = PlaybackPreferences.PLAYER_STATUS_PLAYING; - break; - case PAUSED: - playerStatusAsInt = PlaybackPreferences.PLAYER_STATUS_PAUSED; - break; - default: - playerStatusAsInt = PlaybackPreferences.PLAYER_STATUS_OTHER; - } - return playerStatusAsInt; - } - - private void writePlaybackPreferences() { - Log.d(TAG, "Writing playback preferences"); - - SharedPreferences.Editor editor = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo(); - MediaType mediaType = mediaPlayer.getCurrentMediaType(); - boolean stream = mediaPlayer.isStreaming(); - int playerStatus = getCurrentPlayerStatusAsInt(info.playerStatus); - - if (info.playable != null) { - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, - info.playable.getPlayableType()); - editor.putBoolean( - PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM, - stream); - editor.putBoolean( - PlaybackPreferences.PREF_CURRENT_EPISODE_IS_VIDEO, - mediaType == MediaType.VIDEO); - if (info.playable instanceof FeedMedia) { - FeedMedia fMedia = (FeedMedia) info.playable; - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - fMedia.getItem().getFeed().getId()); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, - fMedia.getId()); - } else { - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - } - info.playable.writeToPreferences(editor); - } else { - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - } - editor.putInt( - PlaybackPreferences.PREF_CURRENT_PLAYER_STATUS, playerStatus); - - editor.apply(); - } - - private void writePlayerStatusPlaybackPreferences() { - Log.d(TAG, "Writing player status playback preferences"); - - SharedPreferences.Editor editor = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - int playerStatus = getCurrentPlayerStatusAsInt(mediaPlayer.getPlayerStatus()); - editor.putInt(PlaybackPreferences.PREF_CURRENT_PLAYER_STATUS, playerStatus); - editor.apply(); - } - private void sendNotificationBroadcast(int type, int code) { Intent intent = new Intent(ACTION_PLAYER_NOTIFICATION); intent.putExtra(EXTRA_NOTIFICATION_TYPE, type); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 9469ebc6c3a8b0ed2cb268f4e7b153199d3d6dfb Mon Sep 17 00:00:00 2001 From: orionlee Date: Sun, 29 Sep 2019 12:46:21 -0700 Subject: bugfix: Ensure playback service use the updated feedItem after media download completes (rather than trying to stream) --- .../playback/PlaybackServiceTaskManagerTest.java | 50 ++++++++++++++++++++-- .../playback/PlaybackServiceTaskManager.java | 34 ++++++++++++++- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 9c0e90929..91a796638 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -5,6 +5,11 @@ import android.support.test.InstrumentationRegistry; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.LargeTest; +import org.greenrobot.eventbus.EventBus; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -15,14 +20,15 @@ import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.playback.Playable; -import org.greenrobot.eventbus.EventBus; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -123,6 +129,42 @@ public class PlaybackServiceTaskManagerTest { pstm.shutdown(); } + @Test + public void testQueueUpdatedUponDownloadComplete() throws Exception { + final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext(); + { // Setup test data + List queue = writeTestQueue("a"); + FeedItem item = DBReader.getFeedItem(queue.get(0).getId()); + FeedMedia media = new FeedMedia(item, "http://abc.test/acme.mp3", 12345, "audio/mp3"); + item.setMedia(media); + DBWriter.setFeedMedia(media).get(); + DBWriter.setFeedItem(item).get(); + } + + PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM); + final FeedItem testItem = pstm.getQueue().get(0); + assertThat("The item is not yet downloaded", + testItem.getMedia().isDownloaded(), is(false)); + + { // simulate download complete (in DownloadService.MediaHandlerThread) + FeedItem item = DBReader.getFeedItem(testItem.getId()); + item.getMedia().setDownloaded(true); + item.getMedia().setFile_url("file://123"); + item.setAutoDownload(false); + DBWriter.setFeedItem(item).get(); + DBWriter.setFeedMedia(item.getMedia()).get(); + } + + // an approximation to ensure the item update event has been posted and processed. + Thread.sleep(10); + + final FeedItem itemUpdated = pstm.getQueue().get(0); + assertThat("The queue in PlaybackService has been updated item after download is completed", + itemUpdated.getMedia().isDownloaded(), is(true)); + + pstm.shutdown(); + } + @Test public void testStartPositionSaver() throws InterruptedException { final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java index 68839023e..1a13f9e9f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java @@ -7,6 +7,9 @@ import android.os.Vibrator; import android.support.annotation.NonNull; import android.util.Log; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -14,13 +17,12 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import de.danoeh.antennapod.core.event.FeedItemEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.playback.Playable; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import io.reactivex.Completable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -102,6 +104,34 @@ public class PlaybackServiceTaskManager { } } + @Subscribe + public void onEvent(FeedItemEvent event) { + // Use case: when an item in the queue has been downloaded, + // listening to the event to ensure the downloaded item will be used. + Log.d(TAG, "onEvent(FeedItemEvent " + event + ")"); + + for (FeedItem item : event.items) { + if (isItemInQueue(item.getId())) { + Log.d(TAG, "onEvent(FeedItemEvent) - some item (" + item.getId() + ") in the queue has been updated (usually downloaded). Refresh the queue."); + cancelQueueLoader(); + loadQueue(); + return; + } + } + } + + private boolean isItemInQueue(long itemId) { + List queue = getQueueIfLoaded(); + if (queue != null) { + for (FeedItem item : queue) { + if (item.getId() == itemId) { + return true; + } + } + } + return false; + } + /** * Returns the queue if it is already loaded or null if it hasn't been loaded yet. * In order to wait until the queue has been loaded, use getQueue() -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 71de4607a35c0164f91687cabc81b62abd1df51c Mon Sep 17 00:00:00 2001 From: orionlee Date: Sun, 29 Sep 2019 12:55:02 -0700 Subject: bugfix: Ensure when media download completes and item update event is posted, the feed media has been updated, --- .../service/playback/PlaybackServiceTaskManagerTest.java | 2 +- .../danoeh/antennapod/core/service/download/DownloadService.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 91a796638..53a402e7b 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -151,8 +151,8 @@ public class PlaybackServiceTaskManagerTest { item.getMedia().setDownloaded(true); item.getMedia().setFile_url("file://123"); item.setAutoDownload(false); - DBWriter.setFeedItem(item).get(); DBWriter.setFeedMedia(item.getMedia()).get(); + DBWriter.setFeedItem(item).get(); } // an approximation to ensure the item update event has been posted and processed. diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index ce61bff68..4b6416384 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -997,14 +997,17 @@ public class DownloadService extends Service { final FeedItem item = media.getItem(); try { + DBWriter.setFeedMedia(media).get(); + // we've received the media, we don't want to autodownload it again if (item != null) { item.setAutoDownload(false); + // setFeedItem() signals (via EventBus) that the item has been updated, + // so we do it after the enclosing media has been updated above, + // to ensure subscribers will get the updated FeedMedia as well DBWriter.setFeedItem(item).get(); } - DBWriter.setFeedMedia(media).get(); - if (item != null && UserPreferences.enqueueDownloadedEpisodes() && !DBTasks.isInQueue(DownloadService.this, item.getId())) { DBWriter.addQueueItem(DownloadService.this, item).get(); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 0ffa0e77d9e8705ac9eba3f9432ec59b6bf946cb Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 22:07:39 +0200 Subject: Reduced logcat output --- app/src/main/java/de/danoeh/antennapod/PodcastApp.java | 2 ++ .../java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java | 6 ++---- .../java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java index cb2f597d6..94d281a45 100644 --- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java +++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java @@ -63,6 +63,8 @@ public class PodcastApp extends Application { EventBus.builder() .addIndex(new ApEventBusIndex()) .addIndex(new ApCoreEventBusIndex()) + .logNoSubscriberMessages(false) + .sendNoSubscriberEvent(false) .installDefaultEventBus(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java index bb34e2c0f..3dd87cc0b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java @@ -92,11 +92,9 @@ class ApOkHttpUrlLoader implements ModelLoader { @Nullable @Override public LoadData buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) { - Log.d(TAG, "buildLoadData() called with: " + "model = [" + model + "], width = [" - + width + "], height = [" + height + "]"); - if(TextUtils.isEmpty(model)) { + if (TextUtils.isEmpty(model)) { return null; - } else if(model.startsWith("/")) { + } else if (model.startsWith("/")) { return new LoadData<>(new ObjectKey(model), new AudioCoverFetcher(model)); } else { GlideUrl url = new GlideUrl(model); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java index 9164f561f..f8f095ea8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java @@ -584,7 +584,6 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { } playerLock.unlock(); - Log.d(TAG, "getPosition() -> " + retVal); return retVal; } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 0187786047175a4be1e4fa01c9fa7da8eca49ff3 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 22:19:17 +0200 Subject: Using FeedSettingsFragment without Activity --- app/src/main/AndroidManifest.xml | 6 - .../antennapod/activity/FeedSettingsActivity.java | 130 --------------------- .../antennapod/fragment/FeedItemlistFragment.java | 7 +- .../antennapod/fragment/FeedSettingsFragment.java | 20 +++- 4 files changed, 20 insertions(+), 143 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6e555be43..2d1d6c671 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -105,12 +105,6 @@ android:value="de.danoeh.antennapod.activity.MainActivity"/> - - - { - feed = result; - showFragment(); - showHeader(); - }, error -> { - Log.d(TAG, Log.getStackTraceString(error)); - finish(); - }, () -> { - Log.e(TAG, "Activity was started with invalid arguments"); - finish(); - }); - } - - private void showFragment() { - FeedSettingsFragment fragment = new FeedSettingsFragment(); - fragment.setArguments(getIntent().getExtras()); - - FragmentManager fragmentManager = getSupportFragmentManager(); - FragmentTransaction fragmentTransaction = - fragmentManager.beginTransaction(); - fragmentTransaction.replace(R.id.settings_fragment_container, fragment); - fragmentTransaction.commit(); - } - - private void showHeader() { - txtvTitle.setText(feed.getTitle()); - - if (!TextUtils.isEmpty(feed.getAuthor())) { - txtvAuthorHeader.setText(feed.getAuthor()); - } - - Glide.with(FeedSettingsActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(imgvCover); - Glide.with(FeedSettingsActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.image_readability_tint) - .error(R.color.image_readability_tint) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .transform(new FastBlurTransformation()) - .dontAnimate()) - .into(imgvBackground); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (disposable != null) { - disposable.dispose(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 5c70a5973..2a750f0f8 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -37,7 +37,6 @@ import org.greenrobot.eventbus.ThreadMode; import java.util.List; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.FeedSettingsActivity; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.FeedItemlistAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; @@ -495,10 +494,8 @@ public class FeedItemlistFragment extends ListFragment { imgvCover.setOnClickListener(v -> showFeedInfo()); butShowSettings.setOnClickListener(v -> { if (feed != null) { - Intent startIntent = new Intent(getActivity(), FeedSettingsActivity.class); - startIntent.putExtra(FeedSettingsActivity.EXTRA_FEED_ID, - feed.getId()); - startActivity(startIntent); + FeedSettingsFragment fragment = FeedSettingsFragment.newInstance(feed); + ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP); } }); headerCreated = true; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java index 4fb3d90f5..be3bf12af 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java @@ -8,6 +8,7 @@ import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.ListPreference; import android.support.v7.preference.PreferenceFragmentCompat; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedFilter; @@ -18,17 +19,25 @@ import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.danoeh.antennapod.dialog.EpisodeFilterDialog; import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel; -import static de.danoeh.antennapod.activity.FeedSettingsActivity.EXTRA_FEED_ID; - public class FeedSettingsFragment extends PreferenceFragmentCompat { private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter"; + private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; private Feed feed; private FeedPreferences feedPreferences; + public static FeedSettingsFragment newInstance(Feed feed) { + FeedSettingsFragment fragment = new FeedSettingsFragment(); + Bundle arguments = new Bundle(); + arguments.putLong(EXTRA_FEED_ID, feed.getId()); + fragment.setArguments(arguments); + return fragment; + } + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.feed_settings); + postponeEnterTransition(); long feedId = getArguments().getLong(EXTRA_FEED_ID); ViewModelProviders.of(getActivity()).get(FeedSettingsViewModel.class).getFeed(feedId) .subscribe(result -> { @@ -43,9 +52,16 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { updateAutoDeleteSummary(); updateAutoDownloadEnabled(); + startPostponedEnterTransition(); }).dispose(); } + @Override + public void onResume() { + super.onResume(); + ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_settings_label); + } + private void setupEpisodeFilterPreference() { findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> { new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) { -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 31c746684bbdb44c6b737a52bf5c8debf05625d6 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 22:27:46 +0200 Subject: Added ViewModel to FeedInfoFragment for even smoother animation --- .../antennapod/fragment/FeedInfoFragment.java | 29 ++++++++------------- .../antennapod/fragment/FeedSettingsFragment.java | 4 +-- .../antennapod/viewmodel/FeedLoaderViewModel.java | 30 ++++++++++++++++++++++ .../viewmodel/FeedSettingsViewModel.java | 30 ---------------------- 4 files changed, 43 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java delete mode 100644 app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java index c37d1e3eb..b47559124 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.fragment; +import android.arch.lifecycle.ViewModelProviders; import android.content.ClipData; import android.content.Context; import android.content.Intent; @@ -26,6 +27,7 @@ import com.bumptech.glide.request.RequestOptions; import com.joanzapata.iconify.Iconify; import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.viewmodel.FeedLoaderViewModel; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -102,7 +104,6 @@ public class FeedInfoFragment extends Fragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View root = inflater.inflate(R.layout.feedinfo, null); - long feedId = getArguments().getLong(EXTRA_FEED_ID, -1); setHasOptionsMenu(true); imgvCover = root.findViewById(R.id.imgvCover); @@ -123,27 +124,19 @@ public class FeedInfoFragment extends Fragment { txtvUrl = root.findViewById(R.id.txtvUrl); txtvUrl.setOnClickListener(copyUrlToClipboard); + postponeEnterTransition(); + return root; + } - disposable = Maybe.create((MaybeOnSubscribe) emitter -> { - Feed feed = DBReader.getFeed(feedId); - if (feed != null) { - emitter.onSuccess(feed); - } else { - emitter.onComplete(); - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + long feedId = getArguments().getLong(EXTRA_FEED_ID); + ViewModelProviders.of(getActivity()).get(FeedLoaderViewModel.class).getFeed(feedId) .subscribe(result -> { feed = result; showFeed(); - }, error -> { - Log.d(TAG, Log.getStackTraceString(error)); - }, () -> { - Log.e(TAG, "Activity was started with invalid arguments"); - }); - - return root; + startPostponedEnterTransition(); + }).dispose(); } private void showFeed() { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java index be3bf12af..dd45c9baa 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java @@ -17,7 +17,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.danoeh.antennapod.dialog.EpisodeFilterDialog; -import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel; +import de.danoeh.antennapod.viewmodel.FeedLoaderViewModel; public class FeedSettingsFragment extends PreferenceFragmentCompat { private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter"; @@ -39,7 +39,7 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { postponeEnterTransition(); long feedId = getArguments().getLong(EXTRA_FEED_ID); - ViewModelProviders.of(getActivity()).get(FeedSettingsViewModel.class).getFeed(feedId) + ViewModelProviders.of(getActivity()).get(FeedLoaderViewModel.class).getFeed(feedId) .subscribe(result -> { feed = result; feedPreferences = feed.getPreferences(); diff --git a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java new file mode 100644 index 000000000..bba14fe2d --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java @@ -0,0 +1,30 @@ +package de.danoeh.antennapod.viewmodel; + +import android.arch.lifecycle.ViewModel; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.storage.DBReader; +import io.reactivex.Maybe; + +public class FeedLoaderViewModel extends ViewModel { + private Feed feed; + + public Maybe getFeed(long feedId) { + if (feed == null) { + return loadFeed(feedId); + } else { + return Maybe.just(feed); + } + } + + private Maybe loadFeed(long feedId) { + return Maybe.create(emitter -> { + Feed feed = DBReader.getFeed(feedId); + if (feed != null) { + this.feed = feed; + emitter.onSuccess(feed); + } else { + emitter.onComplete(); + } + }); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java deleted file mode 100644 index fe11a645c..000000000 --- a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.danoeh.antennapod.viewmodel; - -import android.arch.lifecycle.ViewModel; -import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.storage.DBReader; -import io.reactivex.Maybe; - -public class FeedSettingsViewModel extends ViewModel { - private Feed feed; - - public Maybe getFeed(long feedId) { - if (feed == null) { - return loadFeed(feedId); - } else { - return Maybe.just(feed); - } - } - - private Maybe loadFeed(long feedId) { - return Maybe.create(emitter -> { - Feed feed = DBReader.getFeed(feedId); - if (feed != null) { - this.feed = feed; - emitter.onSuccess(feed); - } else { - emitter.onComplete(); - } - }); - } -} -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 71949ab1b73c186ebabb01dc0af81b4b559af23d Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 22:52:15 +0200 Subject: Converted statistics to fragment Also set title of all preferences pages --- app/src/main/AndroidManifest.xml | 7 - .../antennapod/activity/StatisticsActivity.java | 153 --------------------- .../AutoDownloadPreferencesFragment.java | 7 + .../preferences/GpodderPreferencesFragment.java | 7 + .../IntegrationsPreferencesFragment.java | 6 + .../preferences/MainPreferencesFragment.java | 14 +- .../preferences/NetworkPreferencesFragment.java | 6 + .../preferences/PlaybackPreferencesFragment.java | 7 + .../fragment/preferences/StatisticsFragment.java | 151 ++++++++++++++++++++ .../preferences/StoragePreferencesFragment.java | 7 + .../UserInterfacePreferencesFragment.java | 7 + 11 files changed, 206 insertions(+), 166 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java create mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c2c6f53c5..aa9dc96c4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -150,13 +150,6 @@ android:name="android.support.PARENT_ACTIVITY" android:value="de.danoeh.antennapod.activity.PreferenceActivity"/> - - - diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java deleted file mode 100644 index 37199ccf7..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java +++ /dev/null @@ -1,153 +0,0 @@ -package de.danoeh.antennapod.activity; - -import android.content.SharedPreferences; -import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.RadioButton; -import android.widget.TextView; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.adapter.StatisticsListAdapter; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.util.Converter; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - -/** - * Displays the 'statistics' screen - */ -public class StatisticsActivity extends AppCompatActivity - implements AdapterView.OnItemClickListener { - - private static final String TAG = StatisticsActivity.class.getSimpleName(); - private static final String PREF_NAME = "StatisticsActivityPrefs"; - private static final String PREF_COUNT_ALL = "countAll"; - - private Disposable disposable; - private TextView totalTimeTextView; - private ListView feedStatisticsList; - private ProgressBar progressBar; - private StatisticsListAdapter listAdapter; - private boolean countAll = false; - private SharedPreferences prefs; - - @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); - super.onCreate(savedInstanceState); - getSupportActionBar().setDisplayShowHomeEnabled(true); - setContentView(R.layout.statistics_activity); - - prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE); - countAll = prefs.getBoolean(PREF_COUNT_ALL, false); - - totalTimeTextView = findViewById(R.id.total_time); - feedStatisticsList = findViewById(R.id.statistics_list); - progressBar = findViewById(R.id.progressBar); - listAdapter = new StatisticsListAdapter(this); - listAdapter.setCountAll(countAll); - feedStatisticsList.setAdapter(listAdapter); - feedStatisticsList.setOnItemClickListener(this); - } - - @Override - public void onResume() { - super.onResume(); - refreshStatistics(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.statistics, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - return true; - } else if (item.getItemId() == R.id.statistics_mode) { - selectStatisticsMode(); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - - private void selectStatisticsMode() { - View contentView = View.inflate(this, R.layout.statistics_mode_select_dialog, null); - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setView(contentView); - builder.setTitle(R.string.statistics_mode); - - if (countAll) { - ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).setChecked(true); - } else { - ((RadioButton) contentView.findViewById(R.id.statistics_mode_normal)).setChecked(true); - } - - builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { - countAll = ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).isChecked(); - listAdapter.setCountAll(countAll); - prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).apply(); - refreshStatistics(); - }); - - builder.show(); - } - - private void refreshStatistics() { - progressBar.setVisibility(View.VISIBLE); - totalTimeTextView.setVisibility(View.GONE); - feedStatisticsList.setVisibility(View.GONE); - loadStatistics(); - } - - private void loadStatistics() { - if (disposable != null) { - disposable.dispose(); - } - disposable = Observable.fromCallable(() -> DBReader.getStatistics(countAll)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - totalTimeTextView.setText(Converter - .shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime)); - listAdapter.update(result.feedTime); - progressBar.setVisibility(View.GONE); - totalTimeTextView.setVisibility(View.VISIBLE); - feedStatisticsList.setVisibility(View.VISIBLE); - }, error -> Log.e(TAG, Log.getStackTraceString(error))); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - DBReader.StatisticsItem stats = listAdapter.getItem(position); - - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle(stats.feed.getTitle()); - dialog.setMessage(getString(R.string.statistics_details_dialog, - countAll ? stats.episodesStartedIncludingMarked : stats.episodesStarted, - stats.episodes, - Converter.shortLocalizedDuration(this, countAll ? - stats.timePlayedCountAll : stats.timePlayed), - Converter.shortLocalizedDuration(this, stats.time))); - dialog.setPositiveButton(android.R.string.ok, null); - dialog.show(); - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index d0c209326..3e5e75a08 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.List; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.UserPreferences; public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { @@ -46,6 +47,12 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { buildEpisodeCleanupPreference(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.auto_download_label); + } + @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java index 491922056..ca902b0e4 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java @@ -9,6 +9,7 @@ import android.text.Html; import android.text.format.DateUtils; import android.widget.Toast; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.GpodnetPreferences; import de.danoeh.antennapod.core.service.GpodnetSyncService; import de.danoeh.antennapod.dialog.AuthenticationDialog; @@ -29,6 +30,12 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat { setupGpodderScreen(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.gpodnet_main_label); + } + @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java index 229274b76..d0c86ca34 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java @@ -14,6 +14,12 @@ public class IntegrationsPreferencesFragment extends PreferenceFragmentCompat { setupIntegrationsScreen(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.integrations_label); + } + private void setupIntegrationsScreen() { findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> { ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_gpodder); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java index 9f36e1355..2b385851e 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java @@ -1,20 +1,15 @@ package de.danoeh.antennapod.fragment.preferences; -import android.content.ActivityNotFoundException; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.preference.PreferenceFragmentCompat; -import android.util.Log; -import android.widget.Toast; import com.bytehamster.lib.preferencesearch.SearchConfiguration; import com.bytehamster.lib.preferencesearch.SearchPreference; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.AboutActivity; import de.danoeh.antennapod.activity.BugReportActivity; import de.danoeh.antennapod.activity.PreferenceActivity; -import de.danoeh.antennapod.activity.StatisticsActivity; import de.danoeh.antennapod.core.util.IntentUtils; public class MainPreferencesFragment extends PreferenceFragmentCompat { @@ -38,6 +33,12 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { setupSearch(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label); + } + private void setupMainScreen() { findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference -> { ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_user_interface); @@ -68,7 +69,8 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { ); findPreference(STATISTICS).setOnPreferenceClickListener( preference -> { - startActivity(new Intent(getActivity(), StatisticsActivity.class)); + getFragmentManager().beginTransaction().replace(R.id.content, new StatisticsFragment()) + .addToBackStack(getString(R.string.statistics_label)).commit(); return true; } ); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java index ac2436e25..1d4310869 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java @@ -30,6 +30,12 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat { setupNetworkScreen(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.network_pref); + } + @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java index e1714d4bd..9a0eec744 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java @@ -8,6 +8,7 @@ import android.support.v7.preference.ListPreference; import android.support.v7.preference.PreferenceFragmentCompat; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MediaplayerActivity; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil; import de.danoeh.antennapod.dialog.VariableSpeedDialog; @@ -27,6 +28,12 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat { buildSmartMarkAsPlayedPreference(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.playback_pref); + } + @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java new file mode 100644 index 000000000..6129387c0 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java @@ -0,0 +1,151 @@ +package de.danoeh.antennapod.fragment.preferences; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.RadioButton; +import android.widget.TextView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; +import de.danoeh.antennapod.adapter.StatisticsListAdapter; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.util.Converter; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * Displays the 'statistics' screen + */ +public class StatisticsFragment extends Fragment implements AdapterView.OnItemClickListener { + private static final String TAG = StatisticsFragment.class.getSimpleName(); + private static final String PREF_NAME = "StatisticsActivityPrefs"; + private static final String PREF_COUNT_ALL = "countAll"; + + private Disposable disposable; + private TextView totalTimeTextView; + private ListView feedStatisticsList; + private ProgressBar progressBar; + private StatisticsListAdapter listAdapter; + private boolean countAll = false; + private SharedPreferences prefs; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + prefs = getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + countAll = prefs.getBoolean(PREF_COUNT_ALL, false); + setHasOptionsMenu(true); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.statistics_activity, container, false); + totalTimeTextView = root.findViewById(R.id.total_time); + feedStatisticsList = root.findViewById(R.id.statistics_list); + progressBar = root.findViewById(R.id.progressBar); + listAdapter = new StatisticsListAdapter(getContext()); + listAdapter.setCountAll(countAll); + feedStatisticsList.setAdapter(listAdapter); + feedStatisticsList.setOnItemClickListener(this); + return root; + } + + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label); + refreshStatistics(); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.statistics, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.statistics_mode) { + selectStatisticsMode(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void selectStatisticsMode() { + View contentView = View.inflate(getContext(), R.layout.statistics_mode_select_dialog, null); + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setView(contentView); + builder.setTitle(R.string.statistics_mode); + + if (countAll) { + ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).setChecked(true); + } else { + ((RadioButton) contentView.findViewById(R.id.statistics_mode_normal)).setChecked(true); + } + + builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { + countAll = ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).isChecked(); + listAdapter.setCountAll(countAll); + prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).apply(); + refreshStatistics(); + }); + + builder.show(); + } + + private void refreshStatistics() { + progressBar.setVisibility(View.VISIBLE); + totalTimeTextView.setVisibility(View.GONE); + feedStatisticsList.setVisibility(View.GONE); + loadStatistics(); + } + + private void loadStatistics() { + if (disposable != null) { + disposable.dispose(); + } + disposable = Observable.fromCallable(() -> DBReader.getStatistics(countAll)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + totalTimeTextView.setText(Converter.shortLocalizedDuration(getContext(), + countAll ? result.totalTimeCountAll : result.totalTime)); + listAdapter.update(result.feedTime); + progressBar.setVisibility(View.GONE); + totalTimeTextView.setVisibility(View.VISIBLE); + feedStatisticsList.setVisibility(View.VISIBLE); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + DBReader.StatisticsItem stats = listAdapter.getItem(position); + + AlertDialog.Builder dialog = new AlertDialog.Builder(getContext()); + dialog.setTitle(stats.feed.getTitle()); + dialog.setMessage(getString(R.string.statistics_details_dialog, + countAll ? stats.episodesStartedIncludingMarked : stats.episodesStarted, + stats.episodes, Converter.shortLocalizedDuration(getContext(), + countAll ? stats.timePlayedCountAll : stats.timePlayed), + Converter.shortLocalizedDuration(getContext(), stats.time))); + dialog.setPositiveButton(android.R.string.ok, null); + dialog.show(); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java index e36476c6f..1cbb5cde2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java @@ -23,6 +23,7 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.DirectoryChooserActivity; import de.danoeh.antennapod.activity.ImportExportActivity; import de.danoeh.antennapod.activity.OpmlImportFromPathActivity; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.asynctask.DocumentFileExportWorker; import de.danoeh.antennapod.asynctask.ExportWorker; import de.danoeh.antennapod.core.export.ExportWriter; @@ -63,6 +64,12 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat { setupStorageScreen(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.storage_pref); + } + @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java index e1d44f7d3..7b5eeb125 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java @@ -11,6 +11,7 @@ import android.widget.ListView; import android.widget.Toast; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.UserPreferences; import org.apache.commons.lang3.ArrayUtils; @@ -25,6 +26,12 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { setupInterfaceScreen(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.user_interface_label); + } + private void setupInterfaceScreen() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 045e4bc4191d9677afcf67d213d7dd5d54d0ebc5 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 29 Sep 2019 22:55:50 +0200 Subject: Updated statistics layout --- app/src/main/res/layout/statistics_activity.xml | 81 ++++++++++++--------- app/src/main/res/layout/statistics_listitem.xml | 95 +++++++++++-------------- 2 files changed, 92 insertions(+), 84 deletions(-) diff --git a/app/src/main/res/layout/statistics_activity.xml b/app/src/main/res/layout/statistics_activity.xml index 4a72dc7de..fe42ce32e 100644 --- a/app/src/main/res/layout/statistics_activity.xml +++ b/app/src/main/res/layout/statistics_activity.xml @@ -1,41 +1,58 @@ + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> - + - + - + + + + + + + android:id="@+id/statistics_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:choiceMode="singleChoice" + android:clipToPadding="false" + android:divider="@android:color/transparent" + android:dividerHeight="0dp" + android:paddingBottom="@dimen/list_vertical_padding" + android:paddingTop="@dimen/list_vertical_padding" + android:scrollbarStyle="outsideOverlay" + tools:listitem="@layout/statistics_listitem"/> diff --git a/app/src/main/res/layout/statistics_listitem.xml b/app/src/main/res/layout/statistics_listitem.xml index f52aa73e0..b85cdc74e 100644 --- a/app/src/main/res/layout/statistics_listitem.xml +++ b/app/src/main/res/layout/statistics_listitem.xml @@ -3,63 +3,54 @@ xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="@dimen/listitem_iconwithtext_height" - android:paddingLeft="@dimen/listitem_threeline_verticalpadding" - android:paddingStart="@dimen/listitem_threeline_verticalpadding" - android:paddingRight="@dimen/listitem_threeline_verticalpadding" - android:paddingEnd="@dimen/listitem_threeline_verticalpadding" - tools:background="@android:color/darker_gray"> + android:layout_height="wrap_content" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingTop="8dp" + android:paddingBottom="8dp"> + android:id="@+id/imgvCover" + android:contentDescription="@string/cover_label" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:adjustViewBounds="true" + android:cropToPadding="true" + android:scaleType="centerCrop" + tools:src="@drawable/ic_antenna" + tools:background="@android:color/holo_green_dark"/> + android:id="@+id/txtvTitle" + android:lines="1" + android:ellipsize="end" + android:singleLine="true" + android:textColor="?android:attr/textColorPrimary" + android:textSize="16sp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" + android:layout_toRightOf="@id/imgvCover" + android:layout_alignTop="@id/imgvCover" + android:layout_alignWithParentIfMissing="true" + tools:text="Feed title"/> - + android:id="@+id/txtvTime" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:lines="1" + android:textColor="?android:attr/textColorTertiary" + android:textSize="14sp" + android:layout_toEndOf="@+id/imgvCover" + android:layout_toRightOf="@+id/imgvCover" + android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" + android:layout_below="@+id/txtvTitle" + tools:text="23 hours"/> -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 940e03bcc732b3624475607fc71281cdb772975c Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Mon, 30 Sep 2019 19:28:51 +0200 Subject: Fixed sharing ViewModel with multiple feeds --- app/build.gradle | 4 --- .../antennapod/fragment/FeedInfoFragment.java | 37 ++++++++++++---------- .../antennapod/fragment/FeedSettingsFragment.java | 35 +++++++++++++++++--- .../antennapod/viewmodel/FeedLoaderViewModel.java | 30 ------------------ build.gradle | 1 - 5 files changed, 50 insertions(+), 57 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java diff --git a/app/build.gradle b/app/build.gradle index 3996d7ba5..0fdfd153e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -139,10 +139,6 @@ dependencies { implementation "com.android.support:recyclerview-v7:$supportVersion" compileOnly 'com.google.android.wearable:wearable:2.2.0' - // ViewModel and LiveData - implementation "android.arch.lifecycle:extensions:$lifecycle_version" - annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" - implementation "org.apache.commons:commons-lang3:$commonslangVersion" implementation "commons-io:commons-io:$commonsioVersion" implementation "org.jsoup:jsoup:$jsoupVersion" diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java index b47559124..a1df6c428 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java @@ -1,6 +1,5 @@ package de.danoeh.antennapod.fragment; -import android.arch.lifecycle.ViewModelProviders; import android.content.ClipData; import android.content.Context; import android.content.Intent; @@ -21,18 +20,11 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; - import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import com.joanzapata.iconify.Iconify; - -import de.danoeh.antennapod.activity.MainActivity; -import de.danoeh.antennapod.viewmodel.FeedLoaderViewModel; -import org.apache.commons.lang3.StringUtils; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; - import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.glide.ApGlideSettings; @@ -48,6 +40,9 @@ import io.reactivex.MaybeOnSubscribe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; /** * Displays information about a feed. @@ -56,8 +51,9 @@ public class FeedInfoFragment extends Fragment { private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; private static final String TAG = "FeedInfoActivity"; - private Feed feed; + private Feed feed; + private Disposable disposable; private ImageView imgvCover; private TextView txtvTitle; private TextView txtvDescription; @@ -69,8 +65,6 @@ public class FeedInfoFragment extends Fragment { private TextView txtvAuthorHeader; private ImageView imgvBackground; - private Disposable disposable; - public static FeedInfoFragment newInstance(Feed feed) { FeedInfoFragment fragment = new FeedInfoFragment(); Bundle arguments = new Bundle(); @@ -131,12 +125,21 @@ public class FeedInfoFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { long feedId = getArguments().getLong(EXTRA_FEED_ID); - ViewModelProviders.of(getActivity()).get(FeedLoaderViewModel.class).getFeed(feedId) + disposable = Maybe.create((MaybeOnSubscribe) emitter -> { + Feed feed = DBReader.getFeed(feedId); + if (feed != null) { + emitter.onSuccess(feed); + } else { + emitter.onComplete(); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { - feed = result; - showFeed(); - startPostponedEnterTransition(); - }).dispose(); + feed = result; + showFeed(); + }, error -> Log.d(TAG, Log.getStackTraceString(error)), + this::startPostponedEnterTransition); } private void showFeed() { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java index dd45c9baa..4549203f8 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java @@ -1,12 +1,12 @@ package de.danoeh.antennapod.fragment; -import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.ListPreference; import android.support.v7.preference.PreferenceFragmentCompat; +import android.util.Log; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; @@ -14,15 +14,23 @@ import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedFilter; import de.danoeh.antennapod.core.feed.FeedPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.danoeh.antennapod.dialog.EpisodeFilterDialog; -import de.danoeh.antennapod.viewmodel.FeedLoaderViewModel; +import io.reactivex.Maybe; +import io.reactivex.MaybeOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; public class FeedSettingsFragment extends PreferenceFragmentCompat { private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter"; private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; + private static final String TAG = "FeedSettingsFragment"; + private Feed feed; + private Disposable disposable; private FeedPreferences feedPreferences; public static FeedSettingsFragment newInstance(Feed feed) { @@ -39,7 +47,16 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { postponeEnterTransition(); long feedId = getArguments().getLong(EXTRA_FEED_ID); - ViewModelProviders.of(getActivity()).get(FeedLoaderViewModel.class).getFeed(feedId) + disposable = Maybe.create((MaybeOnSubscribe) emitter -> { + Feed feed = DBReader.getFeed(feedId); + if (feed != null) { + emitter.onSuccess(feed); + } else { + emitter.onComplete(); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { feed = result; feedPreferences = feed.getPreferences(); @@ -52,8 +69,8 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { updateAutoDeleteSummary(); updateAutoDownloadEnabled(); - startPostponedEnterTransition(); - }).dispose(); + }, error -> Log.d(TAG, Log.getStackTraceString(error)), + this::startPostponedEnterTransition); } @Override @@ -62,6 +79,14 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_settings_label); } + @Override + public void onDestroy() { + super.onDestroy(); + if (disposable != null) { + disposable.dispose(); + } + } + private void setupEpisodeFilterPreference() { findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> { new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) { diff --git a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java deleted file mode 100644 index bba14fe2d..000000000 --- a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedLoaderViewModel.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.danoeh.antennapod.viewmodel; - -import android.arch.lifecycle.ViewModel; -import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.storage.DBReader; -import io.reactivex.Maybe; - -public class FeedLoaderViewModel extends ViewModel { - private Feed feed; - - public Maybe getFeed(long feedId) { - if (feed == null) { - return loadFeed(feedId); - } else { - return Maybe.just(feed); - } - } - - private Maybe loadFeed(long feedId) { - return Maybe.create(emitter -> { - Feed feed = DBReader.getFeed(feedId); - if (feed != null) { - this.feed = feed; - emitter.onSuccess(feed); - } else { - emitter.onComplete(); - } - }); - } -} diff --git a/build.gradle b/build.gradle index 87a335dcc..5edabc9d2 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,6 @@ project.ext { targetSdkVersion = 28 supportVersion = "27.1.1" - lifecycle_version = "1.1.1" workManagerVersion = "1.0.1" awaitilityVersion = "3.1.2" commonsioVersion = "2.5" -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From f71b933c6baaec4d7b4255737d5be186953806a2 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Mon, 30 Sep 2019 20:39:02 +0200 Subject: Fixed feed without any identifying value --- core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java | 2 ++ .../de/danoeh/antennapod/core/service/download/DownloadService.java | 2 ++ core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java index 3495164a6..744e9b924 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java @@ -218,6 +218,8 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, ImageR return itemIdentifier; } else if (title != null && !title.isEmpty()) { return title; + } else if (hasMedia() && media.getDownload_url() != null) { + return media.getDownload_url(); } else { return link; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index ce61bff68..5e81d279f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -668,6 +668,7 @@ public class DownloadService extends Service { Log.e(TAG, "FeedSyncThread was interrupted"); } catch (ExecutionException e) { Log.e(TAG, "ExecutionException in FeedSyncThread: " + e.getMessage()); + e.printStackTrace(); } } @@ -702,6 +703,7 @@ public class DownloadService extends Service { Log.e(TAG, "FeedSyncThread was interrupted"); } catch (ExecutionException e) { Log.e(TAG, "ExecutionException in FeedSyncThread: " + e.getMessage()); + e.printStackTrace(); } } 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 4c15f5f00..46fa4b99c 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 @@ -4,6 +4,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.os.Looper; +import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; @@ -440,10 +441,9 @@ public final class DBTasks { /** * Get a FeedItem by its identifying value. */ - private static FeedItem searchFeedItemByIdentifyingValue(Feed feed, - String identifier) { + private static FeedItem searchFeedItemByIdentifyingValue(Feed feed, String identifier) { for (FeedItem item : feed.getItems()) { - if (item.getIdentifyingValue().equals(identifier)) { + if (TextUtils.equals(item.getIdentifyingValue(), identifier)) { return item; } } -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 38e9cafee3afb7010fb870e547dceb0f8ae9feec Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Sep 2019 11:59:55 -0700 Subject: test tweak - ensure playback queue updated after download - follow de-facto convention for test feeds --- .../antennapod/service/playback/PlaybackServiceTaskManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 53a402e7b..38b097d51 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -135,7 +135,7 @@ public class PlaybackServiceTaskManagerTest { { // Setup test data List queue = writeTestQueue("a"); FeedItem item = DBReader.getFeedItem(queue.get(0).getId()); - FeedMedia media = new FeedMedia(item, "http://abc.test/acme.mp3", 12345, "audio/mp3"); + FeedMedia media = new FeedMedia(item, "http://example.com/episode.mp3", 12345, "audio/mp3"); item.setMedia(media); DBWriter.setFeedMedia(media).get(); DBWriter.setFeedItem(item).get(); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From cbf6103c00d4baad160ed5e6b6acba536d940c24 Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Sep 2019 12:07:53 -0700 Subject: test tweak - ensure playback queue updated after download - await for the event explicitly. --- .../playback/PlaybackServiceTaskManagerTest.java | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 38b097d51..1d2a72c92 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -5,7 +5,9 @@ import android.support.test.InstrumentationRegistry; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.LargeTest; +import org.awaitility.Awaitility; import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -16,6 +18,7 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import de.danoeh.antennapod.core.event.FeedItemEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; @@ -146,6 +149,9 @@ public class PlaybackServiceTaskManagerTest { assertThat("The item is not yet downloaded", testItem.getMedia().isDownloaded(), is(false)); + FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); + EventBus.getDefault().register(feedItemEventListener); + { // simulate download complete (in DownloadService.MediaHandlerThread) FeedItem item = DBReader.getFeedItem(testItem.getId()); item.getMedia().setDownloaded(true); @@ -155,16 +161,32 @@ public class PlaybackServiceTaskManagerTest { DBWriter.setFeedItem(item).get(); } - // an approximation to ensure the item update event has been posted and processed. - Thread.sleep(10); + Awaitility.await() + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> feedItemEventListener.getEvents().size() > 0); final FeedItem itemUpdated = pstm.getQueue().get(0); assertThat("The queue in PlaybackService has been updated item after download is completed", itemUpdated.getMedia().isDownloaded(), is(true)); + EventBus.getDefault().unregister(feedItemEventListener); pstm.shutdown(); } + private static class FeedItemEventListener { + + private final List events = new ArrayList<>(); + + @Subscribe + public void onEvent(FeedItemEvent event) { + events.add(event); + } + + List getEvents() { + return events; + } + } + @Test public void testStartPositionSaver() throws InterruptedException { final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext(); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 4a0a825c0895e3052075b285c33cc0fdecaa291a Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Sep 2019 12:18:41 -0700 Subject: test refactor - ensure playback queue updated after download - make test logic more readable by hiding EventBus setup in a helper. --- .../playback/PlaybackServiceTaskManagerTest.java | 37 +++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 1d2a72c92..2880e86eb 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -29,6 +29,7 @@ import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.playback.Playable; +import io.reactivex.functions.Consumer; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -149,30 +150,42 @@ public class PlaybackServiceTaskManagerTest { assertThat("The item is not yet downloaded", testItem.getMedia().isDownloaded(), is(false)); - FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); - EventBus.getDefault().register(feedItemEventListener); - - { // simulate download complete (in DownloadService.MediaHandlerThread) + withFeedItemEventListener( feedItemEventListener -> { + // simulate download complete (in DownloadService.MediaHandlerThread) FeedItem item = DBReader.getFeedItem(testItem.getId()); item.getMedia().setDownloaded(true); item.getMedia().setFile_url("file://123"); item.setAutoDownload(false); DBWriter.setFeedMedia(item.getMedia()).get(); DBWriter.setFeedItem(item).get(); - } - Awaitility.await() - .atMost(1000, TimeUnit.MILLISECONDS) - .until(() -> feedItemEventListener.getEvents().size() > 0); + Awaitility.await() + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> feedItemEventListener.getEvents().size() > 0); - final FeedItem itemUpdated = pstm.getQueue().get(0); - assertThat("The queue in PlaybackService has been updated item after download is completed", - itemUpdated.getMedia().isDownloaded(), is(true)); + final FeedItem itemUpdated = pstm.getQueue().get(0); + assertThat("The queue in PlaybackService has been updated item after download is completed", + itemUpdated.getMedia().isDownloaded(), is(true)); + }); - EventBus.getDefault().unregister(feedItemEventListener); pstm.shutdown(); } + /** + * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use + * + * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown. + */ + private static void withFeedItemEventListener(Consumer consumer) throws Exception { + FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); + try { + EventBus.getDefault().register(feedItemEventListener); + consumer.accept(feedItemEventListener); + } finally { + EventBus.getDefault().unregister(feedItemEventListener); + } + } + private static class FeedItemEventListener { private final List events = new ArrayList<>(); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From c0befc98542bc147a8aa341c48e6445d4cfbbfb7 Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Sep 2019 12:28:27 -0700 Subject: test tweak - ensure playback queue updated after download - use more concise assertTrue/False --- .../service/playback/PlaybackServiceTaskManagerTest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 2880e86eb..3a3a64d80 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -31,8 +31,6 @@ import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.playback.Playable; import io.reactivex.functions.Consumer; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -147,8 +145,7 @@ public class PlaybackServiceTaskManagerTest { PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM); final FeedItem testItem = pstm.getQueue().get(0); - assertThat("The item is not yet downloaded", - testItem.getMedia().isDownloaded(), is(false)); + assertFalse("The item should not yet be downloaded", testItem.getMedia().isDownloaded()); withFeedItemEventListener( feedItemEventListener -> { // simulate download complete (in DownloadService.MediaHandlerThread) @@ -164,8 +161,8 @@ public class PlaybackServiceTaskManagerTest { .until(() -> feedItemEventListener.getEvents().size() > 0); final FeedItem itemUpdated = pstm.getQueue().get(0); - assertThat("The queue in PlaybackService has been updated item after download is completed", - itemUpdated.getMedia().isDownloaded(), is(true)); + assertTrue("media.isDownloaded() should be true - The queue in PlaybackService should be updated after download is completed", + itemUpdated.getMedia().isDownloaded()); }); pstm.shutdown(); -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From d84fc95f0d7b9bee3eb3970c853072f35bb24c55 Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Sep 2019 13:46:59 -0700 Subject: test for DownloadService, case media download successful. --- .../core/service/download/StubDownloader.java | 52 +++++++ .../service/download/DownloadServiceTest.java | 158 +++++++++++++++++++++ .../core/service/download/DownloadService.java | 39 ++++- 3 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java create mode 100644 app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java diff --git a/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java b/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java new file mode 100644 index 000000000..9bb2c58db --- /dev/null +++ b/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java @@ -0,0 +1,52 @@ +package de.danoeh.antennapod.core.service.download; + +import android.support.annotation.NonNull; + +import de.danoeh.antennapod.core.util.Consumer; + +public class StubDownloader extends Downloader { + + private final long downloadTime; + + @NonNull + private final Consumer onDownloadComplete; + + public StubDownloader(@NonNull DownloadRequest request, long downloadTime, @NonNull Consumer onDownloadComplete) { + super(request); + this.downloadTime = downloadTime; + this.onDownloadComplete = onDownloadComplete; + } + + @Override + protected void download() { + try { + Thread.sleep(downloadTime); + } catch (Throwable t) { + t.printStackTrace(); + } + onDownloadComplete.accept(result); + } + + @NonNull + @Override + public DownloadRequest getDownloadRequest() { + return super.getDownloadRequest(); + } + + @NonNull + @Override + public DownloadStatus getResult() { + return super.getResult(); + } + + @Override + public boolean isFinished() { + return super.isFinished(); + } + + @Override + public void cancel() { + super.cancel(); + result.setCancelled(); + } +} diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java new file mode 100644 index 000000000..3f309878e --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java @@ -0,0 +1,158 @@ +package de.test.antennapod.service.download; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.awaitility.Awaitility; +import org.awaitility.core.ConditionTimeoutException; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import de.danoeh.antennapod.core.event.FeedItemEvent; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.service.download.DownloadRequest; +import de.danoeh.antennapod.core.service.download.DownloadService; +import de.danoeh.antennapod.core.service.download.DownloadStatus; +import de.danoeh.antennapod.core.service.download.Downloader; +import de.danoeh.antennapod.core.service.download.StubDownloader; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.Consumer; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @see HttpDownloaderTest for the test of actual download (and saving the file) + */ +@RunWith(AndroidJUnit4.class) +public class DownloadServiceTest { + + private CountDownLatch latch = null; + private Feed testFeed = null; + private FeedMedia testMedia11 = null; + + private DownloadService.DownloaderFactory origFactory = null; + + @Before + public void setUp() throws Exception { + origFactory = DownloadService.getDownloaderFactory(); + testFeed = setUpTestFeeds(); + testMedia11 = testFeed.getItemAtIndex(0).getMedia(); + } + + private Feed setUpTestFeeds() throws Exception { + Feed feed = new Feed("url", null, "Test Feed title 1"); + List items = new ArrayList<>(); + feed.setItems(items); + FeedItem item1 = new FeedItem(0, "Item 1-1", "Item 1-1", "url", new Date(), FeedItem.NEW, feed); + items.add(item1); + FeedMedia media1 = new FeedMedia(0, item1, 123, 1, 1, "audio/mp3", null, "http://example.com/episode.mp3", false, null, 0, 0); + item1.setMedia(media1); + + DBWriter.setFeedItem(item1).get(); + return feed; + } + + + @After + public void tearDown() throws Exception { + DownloadService.setDownloaderFactory(origFactory); + } + + @Test + public void testEventsGeneratedCaseMediaDownloadSuccess() throws Exception { + // create a stub download that returns successful + // + // OPEN: Ideally, I'd like the download time long enough so that multiple in-progress DownloadEvents + // are generated (to simulate typical download), but it'll make download time quite long (1-2 seconds) + // to do so + DownloadService.setDownloaderFactory(new StubDownloaderFactory(50, downloadStatus -> { + downloadStatus.setSuccessful(); + })); + + withFeedItemEventListener(feedItemEventListener -> { + try { + assertEquals(0, feedItemEventListener.getEvents().size()); + assertFalse("The media in test should not yet been downloaded", + DBReader.getFeedMedia(testMedia11.getId()).isDownloaded()); + + DownloadRequester.getInstance().downloadMedia(InstrumentationRegistry.getTargetContext(), + testMedia11); + Awaitility.await() + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> feedItemEventListener.getEvents().size() > 0); + assertTrue("After media download has completed, FeedMedia object in db should indicate so.", + DBReader.getFeedMedia(testMedia11.getId()).isDownloaded()); + } catch (ConditionTimeoutException cte) { + fail("The expected FeedItemEvent (for media download complete) has not been posted. " + + cte.getMessage()); + } + }); + } + + /** + * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use + * + * Note: it uses RxJava's version of {@link io.reactivex.functions.Consumer} because it allows exceptions to be thrown. + */ + private static void withFeedItemEventListener(io.reactivex.functions.Consumer consumer) throws Exception { + FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); + try { + EventBus.getDefault().register(feedItemEventListener); + consumer.accept(feedItemEventListener); + } finally { + EventBus.getDefault().unregister(feedItemEventListener); + } + } + + private static class FeedItemEventListener { + + private final List events = new ArrayList<>(); + + @Subscribe + public void onEvent(FeedItemEvent event) { + events.add(event); + } + + List getEvents() { + return events; + } + } + + private static class StubDownloaderFactory implements DownloadService.DownloaderFactory { + private final long downloadTime; + + @NonNull + private final Consumer onDownloadComplete; + + StubDownloaderFactory(long downloadTime, @NonNull Consumer onDownloadComplete) { + this.downloadTime = downloadTime; + this.onDownloadComplete = onDownloadComplete; + } + + @Nullable + @Override + public Downloader create(@NonNull DownloadRequest request) { + return new StubDownloader(request, downloadTime, onDownloadComplete); + } + } + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index 8e74d1c42..b429740bf 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -14,6 +14,7 @@ import android.os.Handler; import android.os.IBinder; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; @@ -434,12 +435,40 @@ public class DownloadService extends Service { queryDownloads(); } - private Downloader getDownloader(DownloadRequest request) { - if (!URLUtil.isHttpUrl(request.getSource()) && !URLUtil.isHttpsUrl(request.getSource())) { - Log.e(TAG, "Could not find appropriate downloader for " + request.getSource()); - return null; + @VisibleForTesting + public interface DownloaderFactory { + @Nullable + Downloader create(@NonNull DownloadRequest request); + } + + private static class DefaultDownloaderFactory implements DownloaderFactory { + @Nullable + @Override + public Downloader create(@NonNull DownloadRequest request) { + if (!URLUtil.isHttpUrl(request.getSource()) && !URLUtil.isHttpsUrl(request.getSource())) { + Log.e(TAG, "Could not find appropriate downloader for " + request.getSource()); + return null; + } + return new HttpDownloader(request); } - return new HttpDownloader(request); + } + + private static DownloaderFactory downloaderFactory = new DefaultDownloaderFactory(); + + @VisibleForTesting + public static DownloaderFactory getDownloaderFactory() { + return downloaderFactory; + } + + // public scope rather than package private, + // because androidTest put classes in the non-standard de.test.antennapod hierarchy + @VisibleForTesting + public static void setDownloaderFactory(DownloaderFactory downloaderFactory) { + DownloadService.downloaderFactory = downloaderFactory; + } + + private Downloader getDownloader(@NonNull DownloadRequest request) { + return downloaderFactory.create(request); } /** -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 9459460ed4bc202e6c7ad7f916e7a408593ef9f6 Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Sep 2019 13:55:50 -0700 Subject: test refactor - extract common FeedItemEventListener test helper. --- .../service/download/DownloadServiceTest.java | 33 +--------------- .../playback/PlaybackServiceTaskManagerTest.java | 33 +--------------- .../util/feed/FeedItemEventListener.java | 46 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 64 deletions(-) create mode 100644 app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java index 3f309878e..d4f75cfe8 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java @@ -7,8 +7,6 @@ import android.support.test.runner.AndroidJUnit4; import org.awaitility.Awaitility; import org.awaitility.core.ConditionTimeoutException; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -20,7 +18,6 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import de.danoeh.antennapod.core.event.FeedItemEvent; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -34,6 +31,7 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Consumer; +import static de.test.antennapod.util.feed.FeedItemEventListener.withFeedItemEventListener; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -108,35 +106,6 @@ public class DownloadServiceTest { }); } - /** - * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use - * - * Note: it uses RxJava's version of {@link io.reactivex.functions.Consumer} because it allows exceptions to be thrown. - */ - private static void withFeedItemEventListener(io.reactivex.functions.Consumer consumer) throws Exception { - FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); - try { - EventBus.getDefault().register(feedItemEventListener); - consumer.accept(feedItemEventListener); - } finally { - EventBus.getDefault().unregister(feedItemEventListener); - } - } - - private static class FeedItemEventListener { - - private final List events = new ArrayList<>(); - - @Subscribe - public void onEvent(FeedItemEvent event) { - events.add(event); - } - - List getEvents() { - return events; - } - } - private static class StubDownloaderFactory implements DownloadService.DownloaderFactory { private final long downloadTime; diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 3a3a64d80..b2aba30f8 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -7,7 +7,6 @@ import android.support.test.filters.LargeTest; import org.awaitility.Awaitility; import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -18,7 +17,6 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import de.danoeh.antennapod.core.event.FeedItemEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; @@ -29,8 +27,8 @@ import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.playback.Playable; -import io.reactivex.functions.Consumer; +import static de.test.antennapod.util.feed.FeedItemEventListener.withFeedItemEventListener; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -168,35 +166,6 @@ public class PlaybackServiceTaskManagerTest { pstm.shutdown(); } - /** - * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use - * - * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown. - */ - private static void withFeedItemEventListener(Consumer consumer) throws Exception { - FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); - try { - EventBus.getDefault().register(feedItemEventListener); - consumer.accept(feedItemEventListener); - } finally { - EventBus.getDefault().unregister(feedItemEventListener); - } - } - - private static class FeedItemEventListener { - - private final List events = new ArrayList<>(); - - @Subscribe - public void onEvent(FeedItemEvent event) { - events.add(event); - } - - List getEvents() { - return events; - } - } - @Test public void testStartPositionSaver() throws InterruptedException { final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext(); diff --git a/app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java b/app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java new file mode 100644 index 000000000..ef371e39b --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java @@ -0,0 +1,46 @@ +package de.test.antennapod.util.feed; + +import android.support.annotation.NonNull; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +import de.danoeh.antennapod.core.event.FeedItemEvent; +import io.reactivex.functions.Consumer; + +/** + * Test helpers to listen {@link FeedItemEvent} and handle them accordingly + * + */ +public class FeedItemEventListener { + private final List events = new ArrayList<>(); + + /** + * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use + * + * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown. + */ + public static void withFeedItemEventListener(@NonNull Consumer consumer) + throws Exception { + FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); + try { + EventBus.getDefault().register(feedItemEventListener); + consumer.accept(feedItemEventListener); + } finally { + EventBus.getDefault().unregister(feedItemEventListener); + } + } + + @Subscribe + public void onEvent(FeedItemEvent event) { + events.add(event); + } + + @NonNull + public List getEvents() { + return events; + } +} -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 8824b7568d73a7943ea716cf417ca95d4f70d3fc Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Sep 2019 20:34:12 -0700 Subject: test refactor - move the common FeedItemEventListener test helper to the proper event/ package. --- .../service/download/DownloadServiceTest.java | 2 +- .../playback/PlaybackServiceTaskManagerTest.java | 2 +- .../util/event/FeedItemEventListener.java | 46 ++++++++++++++++++++++ .../util/feed/FeedItemEventListener.java | 46 ---------------------- 4 files changed, 48 insertions(+), 48 deletions(-) create mode 100644 app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java delete mode 100644 app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java index d4f75cfe8..81edb75ba 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java @@ -31,7 +31,7 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Consumer; -import static de.test.antennapod.util.feed.FeedItemEventListener.withFeedItemEventListener; +import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index b2aba30f8..35f178a44 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -28,7 +28,7 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.playback.Playable; -import static de.test.antennapod.util.feed.FeedItemEventListener.withFeedItemEventListener; +import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; diff --git a/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java b/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java new file mode 100644 index 000000000..3088a3288 --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java @@ -0,0 +1,46 @@ +package de.test.antennapod.util.event; + +import android.support.annotation.NonNull; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +import de.danoeh.antennapod.core.event.FeedItemEvent; +import io.reactivex.functions.Consumer; + +/** + * Test helpers to listen {@link FeedItemEvent} and handle them accordingly + * + */ +public class FeedItemEventListener { + private final List events = new ArrayList<>(); + + /** + * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use + * + * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown. + */ + public static void withFeedItemEventListener(@NonNull Consumer consumer) + throws Exception { + FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); + try { + EventBus.getDefault().register(feedItemEventListener); + consumer.accept(feedItemEventListener); + } finally { + EventBus.getDefault().unregister(feedItemEventListener); + } + } + + @Subscribe + public void onEvent(FeedItemEvent event) { + events.add(event); + } + + @NonNull + public List getEvents() { + return events; + } +} diff --git a/app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java b/app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java deleted file mode 100644 index ef371e39b..000000000 --- a/app/src/androidTest/java/de/test/antennapod/util/feed/FeedItemEventListener.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.test.antennapod.util.feed; - -import android.support.annotation.NonNull; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; - -import java.util.ArrayList; -import java.util.List; - -import de.danoeh.antennapod.core.event.FeedItemEvent; -import io.reactivex.functions.Consumer; - -/** - * Test helpers to listen {@link FeedItemEvent} and handle them accordingly - * - */ -public class FeedItemEventListener { - private final List events = new ArrayList<>(); - - /** - * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use - * - * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown. - */ - public static void withFeedItemEventListener(@NonNull Consumer consumer) - throws Exception { - FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); - try { - EventBus.getDefault().register(feedItemEventListener); - consumer.accept(feedItemEventListener); - } finally { - EventBus.getDefault().unregister(feedItemEventListener); - } - } - - @Subscribe - public void onEvent(FeedItemEvent event) { - events.add(event); - } - - @NonNull - public List getEvents() { - return events; - } -} -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From 6967e9c8902b789079c7dee6a78d835410716d60 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 2 Oct 2019 15:39:10 +0200 Subject: Added feed title to ActionBar --- .../de/danoeh/antennapod/fragment/FeedItemlistFragment.java | 4 ++-- .../de/danoeh/antennapod/fragment/FeedSettingsFragment.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 2a750f0f8..c7ac8286c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -140,8 +140,8 @@ public class FeedItemlistFragment extends ListFragment { @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); - if (!hidden) { - ((MainActivity)getActivity()).getSupportActionBar().setTitle(""); + if (!hidden && getActivity() != null) { + ((MainActivity) getActivity()).getSupportActionBar().setTitle(""); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java index 4549203f8..f9564336d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java @@ -60,6 +60,7 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { .subscribe(result -> { feed = result; feedPreferences = feed.getPreferences(); + ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle()); setupAutoDownloadPreference(); setupKeepUpdatedPreference(); @@ -77,6 +78,15 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { public void onResume() { super.onResume(); ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_settings_label); + if (feed != null) { + ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle()); + } + } + + @Override + public void onStop() { + super.onStop(); + ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(null); } @Override -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0 From cbdd3603aab4519aa477df480c57c8e2fd033012 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 2 Oct 2019 15:42:55 +0200 Subject: Added logging to ExoPlayer --- .../de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index 13349dfdd..fc2cee54d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.service.playback; import android.content.Context; import android.net.Uri; +import android.util.Log; import android.view.SurfaceHolder; import com.google.android.exoplayer2.C; @@ -35,6 +36,7 @@ import de.danoeh.antennapod.core.util.playback.IPlayer; import java.util.concurrent.TimeUnit; public class ExoPlayerWrapper implements IPlayer { + private static final String TAG = "ExoPlayerWrapper"; private final Context mContext; private final Disposable bufferingUpdateDisposable; private SimpleExoPlayer mExoPlayer; @@ -204,6 +206,7 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void setDataSource(String s) throws IllegalArgumentException, IllegalStateException { + Log.d(TAG, "setDataSource: " + s); DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory( Util.getUserAgent(mContext, mContext.getPackageName()), null, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, -- cgit debian/1.2.3+git2.25.1-1-2-gaceb0