summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/build.gradle5
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java43
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java171
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java94
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java323
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java4
-rw-r--r--app/src/main/res/layout/downloadlog_item.xml3
-rw-r--r--app/src/main/res/layout/proxy_settings.xml90
-rw-r--r--app/src/main/res/layout/queue_fragment.xml2
-rw-r--r--app/src/main/res/menu/opml_selection_options.xml19
-rw-r--r--app/src/main/res/xml/preferences.xml5
-rw-r--r--build.gradle6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java22
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java63
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java32
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java32
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java19
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/Converter.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/IntList.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java56
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java62
-rw-r--r--core/src/main/res/values/strings.xml22
-rw-r--r--core/src/main/res/values/styles.xml2
48 files changed, 978 insertions, 281 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 55c1080ae..240fd6f9f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -71,6 +71,7 @@ android {
versionName "${getMyVersionName()}"
testApplicationId "de.test.antennapod"
testInstrumentationRunner "de.test.antennapod.AntennaPodTestRunner"
+ generatedDensities = []
}
signingConfigs {
@@ -132,6 +133,10 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ aaptOptions {
+ additionalParameters "--no-version-vectors"
+ }
}
// about.html is templatized so that we can automatically insert
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b0c47f5a1..af23c287c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:versionCode="1050008"
- android:versionName="1.5.0.8">
+ android:versionCode="1050200"
+ android:versionName="1.5.2.0">
<!--
Version code schema:
"1.2.3-SNAPSHOT" -> 1020300
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 8af6f3552..b4e8d4d71 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -94,8 +94,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
private int mPosition = -1;
private Playable media;
- private ViewPager mPager;
- private AudioplayerPagerAdapter mPagerAdapter;
+ private ViewPager pager;
+ private AudioplayerPagerAdapter pagerAdapter;
private Subscription subscription;
@@ -116,8 +116,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
// don't risk creating memory leaks
navAdapter = null;
drawerToggle = null;
- mPager = null;
- mPagerAdapter = null;
+ pager = null;
+ pagerAdapter = null;
}
@Override
@@ -126,27 +126,29 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
}
private void saveCurrentFragment() {
- if(mPager == null) {
+ if(pager == null) {
return;
}
Log.d(TAG, "Saving preferences");
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
prefs.edit()
- .putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, mPager.getCurrentItem())
+ .putInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, pager.getCurrentItem())
.commit();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- drawerToggle.onConfigurationChanged(newConfig);
+ if(drawerToggle != null) {
+ drawerToggle.onConfigurationChanged(newConfig);
+ }
}
private void loadLastFragment() {
Log.d(TAG, "Restoring instance state");
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
int lastPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, -1);
- mPager.setCurrentItem(lastPosition);
+ pager.setCurrentItem(lastPosition);
}
@Override
@@ -166,9 +168,9 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
true);
startService(launchIntent);
}
- if(mPagerAdapter != null && controller != null && controller.getMedia() != media) {
+ if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
media = controller.getMedia();
- mPagerAdapter.onMediaChanged(media);
+ pagerAdapter.onMediaChanged(media);
}
EventDistributor.getInstance().register(contentUpdate);
@@ -255,13 +257,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
startActivity(new Intent(AudioplayerActivity.this, PreferenceController.getPreferenceActivity()));
});
- mPager = (ViewPager) findViewById(R.id.pager);
- mPagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager());
- mPager.setAdapter(mPagerAdapter);
+ pager = (ViewPager) findViewById(R.id.pager);
+ pagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager());
+ pager.setAdapter(pagerAdapter);
CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
- pageIndicator.setViewPager(mPager);
+ pageIndicator.setViewPager(pager);
loadLastFragment();
- mPager.onSaveInstanceState();
+ pager.onSaveInstanceState();
}
@Override
@@ -277,13 +279,16 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
}
if(controller.getMedia() != media) {
media = controller.getMedia();
- mPagerAdapter.onMediaChanged(media);
+ pagerAdapter.onMediaChanged(media);
}
return true;
}
public void notifyMediaPositionChanged() {
- ChaptersFragment chaptersFragment = mPagerAdapter.getChaptersFragment();
+ if(pagerAdapter == null) {
+ return;
+ }
+ ChaptersFragment chaptersFragment = pagerAdapter.getChaptersFragment();
if(chaptersFragment != null) {
ChaptersListAdapter adapter = (ChaptersListAdapter) chaptersFragment.getListAdapter();
if (adapter != null) {
@@ -411,13 +416,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
public void onBackPressed() {
if(isDrawerOpen()) {
drawerLayout.closeDrawer(navDrawer);
- } else if (mPager.getCurrentItem() == 0) {
+ } else if (pager == null || pager.getCurrentItem() == 0) {
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
} else {
// Otherwise, select the previous step.
- mPager.setCurrentItem(mPager.getCurrentItem() - 1);
+ pager.setCurrentItem(pager.getCurrentItem() - 1);
}
}
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 bd7da7c03..9874d83a6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -184,7 +184,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
loadFragment(lastFragment, null);
} else {
try {
- loadFeedFragmentById(Integer.valueOf(lastFragment), null);
+ loadFeedFragmentById(Integer.parseInt(lastFragment), null);
} catch (NumberFormatException e) {
// it's not a number, this happens if we removed
// a label from the NAV_DRAWER_TAGS
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 e890f03b7..dce3d2172 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -31,6 +31,8 @@ import com.bumptech.glide.Glide;
import com.joanzapata.iconify.IconDrawable;
import com.joanzapata.iconify.fonts.FontAwesomeIcons;
+import java.util.Locale;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
@@ -206,8 +208,10 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
@Override
protected void onPause() {
super.onPause();
- controller.reinitServiceIfPaused();
- controller.pause();
+ if(controller != null) {
+ controller.reinitServiceIfPaused();
+ controller.pause();
+ }
}
/**
@@ -229,8 +233,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
protected void onBufferUpdate(float progress) {
if (sbPosition != null) {
- sbPosition.setSecondaryProgress((int) progress
- * sbPosition.getMax());
+ sbPosition.setSecondaryProgress((int) progress * sbPosition.getMax());
}
}
@@ -246,6 +249,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
controller.release();
}
controller = newPlaybackController();
+ if(butPlay != null) {
+ butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+ }
}
@Override
@@ -454,9 +460,10 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
if(controller != null && controller.canSetPlaybackSpeed()) {
float playbackSpeed = (progress + 10) / 20.0f;
controller.setPlaybackSpeed(playbackSpeed);
- String speed = String.format("%.2f", playbackSpeed);
- UserPreferences.setPlaybackSpeed(speed);
- txtvPlaybackSpeed.setText(speed + "x");
+ String speedPref = String.format(Locale.US, "%.2f", playbackSpeed);
+ UserPreferences.setPlaybackSpeed(speedPref);
+ String speedStr = String.format("%.2fx", playbackSpeed);
+ txtvPlaybackSpeed.setText(speedStr);
} else if(fromUser) {
float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
barPlaybackSpeed.post(() -> {
@@ -583,7 +590,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
super.onResume();
Log.d(TAG, "onResume()");
StorageUtils.checkStorageAvailability(this);
- controller.init();
+ if(controller != null) {
+ controller.init();
+ }
}
/**
@@ -597,32 +606,31 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
protected abstract void clearStatusMsg();
protected void onPositionObserverUpdate() {
- if (controller != null) {
- int currentPosition = controller.getPosition();
- int duration = controller.getDuration();
- Log.d(TAG, "currentPosition " + Converter
- .getDurationStringLong(currentPosition));
- if (currentPosition != PlaybackService.INVALID_TIME
- && duration != PlaybackService.INVALID_TIME
- && controller.getMedia() != null) {
- txtvPosition.setText(Converter
- .getDurationStringLong(currentPosition));
- if (showTimeLeft) {
- txtvLength.setText("-" + Converter
- .getDurationStringLong(duration - currentPosition));
- } else {
- txtvLength.setText(Converter
- .getDurationStringLong(duration));
- }
- updateProgressbarPosition(currentPosition, duration);
- } else {
- Log.w(TAG, "Could not react to position observer update because of invalid time");
- }
+ if (controller == null || txtvPosition == null || txtvLength == null) {
+ return;
+ }
+ int currentPosition = controller.getPosition();
+ int duration = controller.getDuration();
+ Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
+ if (currentPosition == PlaybackService.INVALID_TIME ||
+ duration == PlaybackService.INVALID_TIME) {
+ Log.w(TAG, "Could not react to position observer update because of invalid time");
+ return;
}
+ txtvPosition.setText(Converter.getDurationStringLong(currentPosition));
+ if (showTimeLeft) {
+ txtvLength.setText("-" + Converter.getDurationStringLong(duration - currentPosition));
+ } else {
+ txtvLength.setText(Converter.getDurationStringLong(duration));
+ }
+ updateProgressbarPosition(currentPosition, duration);
}
private void updateProgressbarPosition(int position, int duration) {
Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
+ if(sbPosition == null) {
+ return;
+ }
float progress = ((float) position) / duration;
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
}
@@ -639,17 +647,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
if (media != null) {
- txtvPosition.setText(Converter.getDurationStringLong((media.getPosition())));
-
- if (media.getDuration() != 0) {
- txtvLength.setText(Converter.getDurationStringLong(media.getDuration()));
- float progress = ((float) media.getPosition()) / media.getDuration();
- sbPosition.setProgress((int) (progress * sbPosition.getMax()));
- if (showTimeLeft) {
- int timeLeft = media.getDuration() - media.getPosition();
- txtvLength.setText("-" + Converter.getDurationStringLong(timeLeft));
- }
- }
+ onPositionObserverUpdate();
checkFavorite();
if(butPlaybackSpeed != null) {
if (controller == null) {
@@ -763,8 +761,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
if (butRev != null) {
butRev.setOnClickListener(v -> {
- int curr = controller.getPosition();
- controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
+ onRewind();
});
butRev.setOnLongClickListener(new View.OnLongClickListener() {
@@ -802,12 +799,13 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
});
}
- butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+ butPlay.setOnClickListener(v -> {
+ onPlayPause();
+ });
if (butFF != null) {
butFF.setOnClickListener(v -> {
- int curr = controller.getPosition();
- controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
+ onFastForward();
});
butFF.setOnLongClickListener(new View.OnLongClickListener() {
@@ -852,13 +850,35 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
}
}
+ protected void onRewind() {
+ if (controller == null) {
+ return;
+ }
+ int curr = controller.getPosition();
+ controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
+ }
+
+ protected void onPlayPause() {
+ if(controller == null) {
+ return;
+ }
+ controller.playPause();
+ }
+
+ protected void onFastForward() {
+ if (controller == null) {
+ return;
+ }
+ int curr = controller.getPosition();
+ controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
+ }
+
protected abstract int getContentViewResourceId();
void handleError(int errorCode) {
final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this);
errorDialog.setTitle(R.string.error_label);
- errorDialog
- .setMessage(MediaPlayerError.getErrorString(this, errorCode));
+ errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode));
errorDialog.setNeutralButton("OK",
(dialog, which) -> {
dialog.dismiss();
@@ -872,19 +892,28 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
@Override
public void onProgressChanged (SeekBar seekBar,int progress, boolean fromUser) {
- if (controller != null) {
- prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPosition);
- if (showTimeLeft && prog != 0) {
- int duration = controller.getDuration();
- String length = "-" + Converter.getDurationStringLong(duration - (int) (prog * duration));
- txtvLength.setText(length);
- }
+ if (controller == null || txtvLength == null) {
+ return;
+ }
+ prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPosition);
+ if (showTimeLeft && prog != 0) {
+ int duration = controller.getDuration();
+ String length = "-" + Converter.getDurationStringLong(duration - (int) (prog * duration));
+ txtvLength.setText(length);
}
}
private void updateButPlaybackSpeed() {
if (controller != null && butPlaybackSpeed != null) {
- butPlaybackSpeed.setText(UserPreferences.getPlaybackSpeed() + "x");
+ float speed = 1.0f;
+ try {
+ speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
+ } catch(NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed(String.valueOf(speed));
+ }
+ String speedStr = String.format("%.2fx", speed);
+ butPlaybackSpeed.setText(speedStr);
}
}
@@ -904,21 +933,25 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
private void checkFavorite() {
Playable playable = controller.getMedia();
- if (playable != null && playable instanceof FeedMedia) {
- FeedItem feedItem = ((FeedMedia) playable).getItem();
- if (feedItem != null) {
- Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(item -> {
- boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
- if(isFavorite != isFav) {
- isFavorite = isFav;
- invalidateOptionsMenu();
- }
- });
- }
+ if (playable != null && playable instanceof FeedMedia) {
+ FeedItem feedItem = ((FeedMedia) playable).getItem();
+ if (feedItem != null) {
+ Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ item -> {
+ boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
+ if (isFavorite != isFav) {
+ isFavorite = isFav;
+ invalidateOptionsMenu();
+ }
+ }, error -> {
+ Log.e(TAG, Log.getStackTraceString(error));
+ }
+ );
}
+ }
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
index 8a9ec58d3..bc3e686e5 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
@@ -2,23 +2,22 @@ package de.danoeh.antennapod.activity;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.util.SparseBooleanArray;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.opml.OpmlElement;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import java.util.ArrayList;
import java.util.List;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.opml.OpmlElement;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
/**
* Displays the feeds that the OPML-Importer has read and lets the user choose
* which feeds he wants to import.
@@ -33,6 +32,9 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
private ListView feedlist;
private ArrayAdapter<String> listAdapter;
+ private MenuItem selectAll;
+ private MenuItem deselectAll;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
@@ -44,45 +46,54 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
feedlist = (ListView) findViewById(R.id.feedlist);
feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- listAdapter = new ArrayAdapter<String>(this,
+ listAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_multiple_choice,
getTitleList());
feedlist.setAdapter(listAdapter);
-
- butCancel.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(RESULT_CANCELED);
- finish();
+ feedlist.setOnItemClickListener((parent, view, position, id) -> {
+ SparseBooleanArray checked = feedlist.getCheckedItemPositions();
+ int checkedCount = 0;
+ for (int i = 0; i < checked.size(); i++) {
+ if (checked.valueAt(i)) {
+ checkedCount++;
+ }
+ }
+ if(checkedCount == listAdapter.getCount()) {
+ selectAll.setVisible(false);
+ deselectAll.setVisible(true);
+ } else {
+ deselectAll.setVisible(false);
+ selectAll.setVisible(true);
}
});
- butConfirm.setOnClickListener(new OnClickListener() {
+ butCancel.setOnClickListener(v -> {
+ setResult(RESULT_CANCELED);
+ finish();
+ });
- @Override
- public void onClick(View v) {
- Intent intent = new Intent();
- SparseBooleanArray checked = feedlist.getCheckedItemPositions();
+ butConfirm.setOnClickListener(v -> {
+ Intent intent = new Intent();
+ SparseBooleanArray checked = feedlist.getCheckedItemPositions();
- int checkedCount = 0;
- // Get number of checked items
- for (int i = 0; i < checked.size(); i++) {
- if (checked.valueAt(i)) {
- checkedCount++;
- }
+ int checkedCount = 0;
+ // Get number of checked items
+ for (int i = 0; i < checked.size(); i++) {
+ if (checked.valueAt(i)) {
+ checkedCount++;
}
- int[] selection = new int[checkedCount];
- for (int i = 0, collected = 0; collected < checkedCount; i++) {
- if (checked.valueAt(i)) {
- selection[collected] = checked.keyAt(i);
- collected++;
- }
+ }
+ int[] selection = new int[checkedCount];
+ for (int i = 0, collected = 0; collected < checkedCount; i++) {
+ if (checked.valueAt(i)) {
+ selection[collected] = checked.keyAt(i);
+ collected++;
}
- intent.putExtra(EXTRA_SELECTED_ITEMS, selection);
- setResult(RESULT_OK, intent);
- finish();
}
+ intent.putExtra(EXTRA_SELECTED_ITEMS, selection);
+ setResult(RESULT_OK, intent);
+ finish();
});
}
@@ -93,7 +104,6 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
for (OpmlElement element : OpmlImportHolder.getReadElements()) {
result.add(element.getText());
}
-
}
return result;
}
@@ -101,13 +111,11 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.select_all_item, Menu.NONE,
- R.string.select_all_label),
- MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
-
- MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.deselect_all_item, Menu.NONE,
- R.string.deselect_all_label),
- MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.opml_selection_options, menu);
+ selectAll = menu.findItem(R.id.select_all_item);
+ deselectAll = menu.findItem(R.id.deselect_all_item);
+ deselectAll.setVisible(false);
return true;
}
@@ -115,10 +123,14 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.select_all_item:
+ selectAll.setVisible(false);
selectAllItems(true);
+ deselectAll.setVisible(true);
return true;
case R.id.deselect_all_item:
+ deselectAll.setVisible(false);
selectAllItems(false);
+ selectAll.setVisible(true);
return true;
default:
return false;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
index 46dabec12..fb145db1f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -4,6 +4,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
+import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
@@ -31,7 +32,7 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
private OpmlImportWorker importWorker;
private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
- private Uri uri;
+ @Nullable private Uri uri;
/**
* Handles the choices made by the user in the OpmlFeedChooserActivity and
@@ -67,7 +68,14 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
}
}
- protected void importUri(Uri uri) {
+ protected void importUri(@Nullable Uri uri) {
+ if(uri == null) {
+ new MaterialDialog.Builder(this)
+ .content(R.string.opml_import_error_no_file)
+ .positiveText(android.R.string.ok)
+ .show();
+ return;
+ }
this.uri = uri;
if(uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
@@ -127,8 +135,9 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
importWorker.executeAsync();
} catch (Exception e) {
Log.d(TAG, Log.getStackTraceString(e));
+ String message = getString(R.string.opml_reader_error);
new MaterialDialog.Builder(this)
- .content("Cannot open OPML file: " + e.getMessage())
+ .content(message + " " + e.getMessage())
.positiveText(android.R.string.ok)
.show();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
index ee459dbc6..42c9edd99 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -202,6 +202,24 @@ public class VideoplayerActivity extends MediaplayerActivity {
videoControlsShowing = !videoControlsShowing;
}
+ @Override
+ protected void onRewind() {
+ super.onRewind();
+ setupVideoControlsToggler();
+ }
+
+ @Override
+ protected void onPlayPause() {
+ super.onPlayPause();
+ setupVideoControlsToggler();
+ }
+
+ @Override
+ protected void onFastForward() {
+ super.onFastForward();
+ setupVideoControlsToggler();
+ }
+
private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
@Override
@@ -312,7 +330,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
private static class VideoControlsHider extends Handler {
- private static final int DELAY = 5000;
+ private static final int DELAY = 2500;
private WeakReference<VideoplayerActivity> activity;
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 6d4fc6f1e..07f895468 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -202,7 +202,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
@Override
public long getItemId(int position) {
- return position;
+ FeedItem item = itemAccess.getItem(position);
+ return item != null ? item.getId() : RecyclerView.NO_POSITION;
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index 9ff80424c..34999757f 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -13,6 +13,7 @@ import android.widget.Toast;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
+import com.joanzapata.iconify.widget.IconTextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
@@ -48,7 +49,7 @@ public class DownloadLogAdapter extends BaseAdapter {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
- holder.icon = (TextView) convertView.findViewById(R.id.txtvIcon);
+ holder.icon = (IconTextView) convertView.findViewById(R.id.txtvIcon);
holder.retry = (IconButton) convertView.findViewById(R.id.btnRetry);
holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
@@ -78,14 +79,12 @@ public class DownloadLogAdapter extends BaseAdapter {
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
R.color.download_success_green));
holder.icon.setText("{fa-check-circle}");
- Iconify.addIcons(holder.icon);
holder.retry.setVisibility(View.GONE);
holder.reason.setVisibility(View.GONE);
} else {
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
R.color.download_failed_red));
holder.icon.setText("{fa-times-circle}");
- Iconify.addIcons(holder.icon);
String reasonText = status.getReason().getErrorString(context);
if (status.getReasonDetailed() != null) {
reasonText += ": " + status.getReasonDetailed();
@@ -160,7 +159,7 @@ public class DownloadLogAdapter extends BaseAdapter {
}
static class Holder {
- TextView icon;
+ IconTextView icon;
IconButton retry;
TextView title;
TextView type;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
index 269614d35..6d7e6dcac 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -232,7 +232,7 @@ public class NavListAdapter extends BaseAdapter
int spaceUsed = itemAccess.getNumberOfDownloadedItems() -
itemAccess.getReclaimableItems();
- if (spaceUsed >= epCacheSize) {
+ if (epCacheSize > 0 && spaceUsed >= epCacheSize) {
holder.count.setText("{md-disc-full 150%}");
Iconify.addIcons(holder.count);
holder.count.setVisibility(View.VISIBLE);
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 aa3368258..6cf61f90b 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -109,6 +109,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
return selectedItem;
}
+ @Override
+ public long getItemId(int position) {
+ FeedItem item = itemAccess.getItem(position);
+ return item != null ? item.getId() : RecyclerView.NO_POSITION;
+ }
+
public int getItemCount() {
return itemAccess.getCount();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
index 47ac4c757..e9756b467 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -167,7 +167,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
for(int i=0; imageUrl == null && i < images.length(); i++) {
JSONObject image = images.getJSONObject(i);
String height = image.getJSONObject("attributes").getString("height");
- if(Integer.valueOf(height) >= 100) {
+ if(Integer.parseInt(height) >= 100) {
imageUrl = image.getString("label");
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
new file mode 100644
index 000000000..d745bb51c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
@@ -0,0 +1,323 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v4.content.ContextCompat;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.Patterns;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.afollestad.materialdialogs.DialogAction;
+import com.afollestad.materialdialogs.MaterialDialog;
+import com.afollestad.materialdialogs.internal.MDButton;
+import com.squareup.okhttp.Credentials;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.Response;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.util.concurrent.TimeUnit;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.danoeh.antennapod.core.service.download.ProxyConfig;
+import rx.Observable;
+import rx.Subscriber;
+import rx.Subscription;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+
+public class ProxyDialog {
+
+ private static final String TAG = "ProxyDialog";
+
+ private Context context;
+
+ private MaterialDialog dialog;
+
+ private Spinner spType;
+ private EditText etHost;
+ private EditText etPort;
+ private EditText etUsername;
+ private EditText etPassword;
+
+ private boolean testSuccessful = false;
+ private TextView txtvMessage;
+ private Subscription subscription;
+
+ public ProxyDialog(Context context) {
+ this.context = context;
+ }
+
+ public Dialog createDialog() {
+ dialog = new MaterialDialog.Builder(context)
+ .title(R.string.pref_proxy_title)
+ .customView(R.layout.proxy_settings, true)
+ .positiveText(R.string.proxy_test_label)
+ .negativeText(R.string.cancel_label)
+ .onPositive((dialog1, which) -> {
+ if(!testSuccessful) {
+ dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
+ test();
+ return;
+ }
+ String type = (String) ((Spinner) dialog1.findViewById(R.id.spType)).getSelectedItem();
+ ProxyConfig proxy;
+ if(Proxy.Type.valueOf(type) == Proxy.Type.DIRECT) {
+ proxy = ProxyConfig.direct();
+ } else {
+ String host = etHost.getText().toString();
+ String port = etPort.getText().toString();
+ String username = etUsername.getText().toString();
+ if(TextUtils.isEmpty(username)) {
+ username = null;
+ }
+ String password = etPassword.getText().toString();
+ if(TextUtils.isEmpty(password)) {
+ password = null;
+ }
+ int portValue = 0;
+ if(!TextUtils.isEmpty(port)) {
+ portValue = Integer.valueOf(port);
+ }
+ proxy = ProxyConfig.http(host, portValue, username, password);
+ }
+ UserPreferences.setProxyConfig(proxy);
+ AntennapodHttpClient.reinit();
+ dialog.dismiss();
+ })
+ .onNegative((dialog1, which) -> {
+ dialog1.dismiss();
+ })
+ .autoDismiss(false)
+ .build();
+ View view = dialog.getCustomView();
+ spType = (Spinner) view.findViewById(R.id.spType);
+ String[] types = { Proxy.Type.DIRECT.name(), Proxy.Type.HTTP.name() };
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
+ android.R.layout.simple_spinner_item, types);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spType.setAdapter(adapter);
+ ProxyConfig proxyConfig = UserPreferences.getProxyConfig();
+ spType.setSelection(adapter.getPosition(proxyConfig.type.name()));
+ etHost = (EditText) view.findViewById(R.id.etHost);
+ if(!TextUtils.isEmpty(proxyConfig.host)) {
+ etHost.setText(proxyConfig.host);
+ }
+ etHost.addTextChangedListener(requireTestOnChange);
+ etPort = (EditText) view.findViewById(R.id.etPort);
+ if(proxyConfig.port > 0) {
+ etPort.setText(String.valueOf(proxyConfig.port));
+ }
+ etPort.addTextChangedListener(requireTestOnChange);
+ etUsername = (EditText) view.findViewById(R.id.etUsername);
+ if(!TextUtils.isEmpty(proxyConfig.username)) {
+ etUsername.setText(proxyConfig.username);
+ }
+ etUsername.addTextChangedListener(requireTestOnChange);
+ etPassword = (EditText) view.findViewById(R.id.etPassword);
+ if(!TextUtils.isEmpty(proxyConfig.password)) {
+ etPassword.setText(proxyConfig.username);
+ }
+ etPassword.addTextChangedListener(requireTestOnChange);
+ if(proxyConfig.type == Proxy.Type.DIRECT) {
+ enableSettings(false);
+ setTestRequired(false);
+ }
+ spType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ enableSettings(position > 0);
+ setTestRequired(position > 0);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ enableSettings(false);
+ }
+ });
+ txtvMessage = (TextView) view.findViewById(R.id.txtvMessage);
+ checkValidity();
+ return dialog;
+ }
+
+ private final TextWatcher requireTestOnChange = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ setTestRequired(true);
+ }
+ };
+
+ private void enableSettings(boolean enable) {
+ etHost.setEnabled(enable);
+ etPort.setEnabled(enable);
+ etUsername.setEnabled(enable);
+ etPassword.setEnabled(enable);
+ }
+
+ private boolean checkValidity() {
+ boolean valid = true;
+ if(spType.getSelectedItemPosition() > 0) {
+ valid &= checkHost();
+ }
+ valid &= checkPort();
+ return valid;
+ }
+
+ private boolean checkHost() {
+ String host = etHost.getText().toString();
+ if(host.length() == 0) {
+ etHost.setError(context.getString(R.string.proxy_host_empty_error));
+ return false;
+ }
+ if(!"localhost".equals(host) && !Patterns.DOMAIN_NAME.matcher(host).matches()) {
+ etHost.setError(context.getString(R.string.proxy_host_invalid_error));
+ return false;
+ }
+ return true;
+ }
+
+ private boolean checkPort() {
+ int port = getPort();
+ if(port < 0 && port > 65535) {
+ etPort.setError(context.getString(R.string.proxy_port_invalid_error));
+ return false;
+ }
+ return true;
+ }
+
+ private int getPort() {
+ String port = etPort.getText().toString();
+ if(port.length() > 0) {
+ try {
+ int portValue = Integer.parseInt(port);
+ return portValue;
+ } catch(NumberFormatException e) {
+ // ignore
+ }
+ }
+ return 0;
+ }
+
+ private void setTestRequired(boolean required) {
+ if(required) {
+ testSuccessful = false;
+ MDButton button = dialog.getActionButton(DialogAction.POSITIVE);
+ button.setText(context.getText(R.string.proxy_test_label));
+ button.setEnabled(true);
+ } else {
+ testSuccessful = true;
+ MDButton button = dialog.getActionButton(DialogAction.POSITIVE);
+ button.setText(context.getText(android.R.string.ok));
+ button.setEnabled(true);
+ }
+ }
+
+ private void test() {
+ if(subscription != null) {
+ subscription.unsubscribe();
+ }
+ if(!checkValidity()) {
+ setTestRequired(true);
+ return;
+ }
+ TypedArray res = context.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary });
+ int textColorPrimary = res.getColor(0, 0);
+ res.recycle();
+ String checking = context.getString(R.string.proxy_checking);
+ txtvMessage.setTextColor(textColorPrimary);
+ txtvMessage.setText("{fa-circle-o-notch spin} " + checking);
+ txtvMessage.setVisibility(View.VISIBLE);
+ subscription = Observable.create(new Observable.OnSubscribe<Response>() {
+ @Override
+ public void call(Subscriber<? super Response> subscriber) {
+ String type = (String) spType.getSelectedItem();
+ String host = etHost.getText().toString();
+ String port = etPort.getText().toString();
+ String username = etUsername.getText().toString();
+ String password = etPassword.getText().toString();
+ int portValue = 8080;
+ if(!TextUtils.isEmpty(port)) {
+ portValue = Integer.valueOf(port);
+ }
+ SocketAddress address = InetSocketAddress.createUnresolved(host, portValue);
+ Proxy.Type proxyType = Proxy.Type.valueOf(type.toUpperCase());
+ Proxy proxy = new Proxy(proxyType, address);
+ OkHttpClient client = AntennapodHttpClient.newHttpClient();
+ client.setConnectTimeout(10, TimeUnit.SECONDS);
+ client.setProxy(proxy);
+ client.interceptors().clear();
+ if(!TextUtils.isEmpty(username)) {
+ String credentials = Credentials.basic(username, password);
+ client.interceptors().add(chain -> {
+ Request request = chain.request().newBuilder()
+ .header("Proxy-Authorization", credentials).build();
+ return chain.proceed(request);
+ });
+ }
+ Request request = new Request.Builder()
+ .url("http://www.google.com")
+ .head()
+ .build();
+ try {
+ Response response = client.newCall(request).execute();
+ subscriber.onNext(response);
+ } catch(IOException e) {
+ subscriber.onError(e);
+ }
+ subscriber.onCompleted();
+ }
+ })
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ response -> {
+ int colorId;
+ String icon;
+ String result;
+ if(response.isSuccessful()) {
+ colorId = R.color.download_success_green;
+ icon = "{fa-check}";
+ result = context.getString(R.string.proxy_test_successful);
+ } else {
+ colorId = R.color.download_failed_red;
+ icon = "{fa-close}";
+ result = context.getString(R.string.proxy_test_failed);
+ }
+ int color = ContextCompat.getColor(context, colorId);
+ txtvMessage.setTextColor(color);
+ String message = String.format("%s %s: %s", icon, result, response.message());
+ txtvMessage.setText(message);
+ setTestRequired(!response.isSuccessful());
+ },
+ error -> {
+ String icon = "{fa-close}";
+ String result = context.getString(R.string.proxy_test_failed);
+ int color = ContextCompat.getColor(context, R.color.download_failed_red);
+ txtvMessage.setTextColor(color);
+ String message = String.format("%s %s: %s", icon, result, error.getMessage());
+ txtvMessage.setText(message);
+ setTestRequired(true);
+ }
+ );
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
index 930079e40..89e24f882 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -138,7 +138,7 @@ public abstract class SleepTimerDialog {
private long readTimeMillis() {
TimeUnit selectedUnit = units[spTimeUnit.getSelectedItemPosition()];
- long value = Long.valueOf(etxtTime.getText().toString());
+ long value = Long.parseLong(etxtTime.getText().toString());
return selectedUnit.toMillis(value);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index 273c75240..aa2879330 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -337,6 +337,7 @@ public class AllEpisodesFragment extends Fragment {
MainActivity mainActivity = activity.get();
listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess,
new DefaultActionButtonCallback(mainActivity), showOnlyNewEpisodes());
+ listAdapter.setHasStableIds(true);
recyclerView.setAdapter(listAdapter);
}
listAdapter.notifyDataSetChanged();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index 931d14924..d3b97f9df 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -63,12 +63,7 @@ public class CoverFragment extends Fragment implements AudioplayerContentFragmen
}
private void loadMediaInfo() {
- if(imgvCover == null) {
- return;
- }
if (media != null) {
- Log.d(TAG, "feed title: " + media.getFeedTitle());
- Log.d(TAG, "episode title: " + media.getEpisodeTitle());
txtvPodcastTitle.setText(media.getFeedTitle());
txtvEpisodeTitle.setText(media.getEpisodeTitle());
Glide.with(this)
@@ -103,7 +98,7 @@ public class CoverFragment extends Fragment implements AudioplayerContentFragmen
@Override
public void onMediaChanged(Playable media) {
- if(this.media == media) {
+ if(!isAdded() || this.media == media) {
return;
}
this.media = media;
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 80a9bf0b3..3fd69214d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -72,7 +72,11 @@ public class ExternalPlayerFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
controller = setupPlaybackController();
- butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
+ butPlay.setOnClickListener(v -> {
+ if(controller != null) {
+ controller.playPause();
+ }
+ });
}
private PlaybackController setupPlaybackController() {
@@ -88,7 +92,6 @@ public class ExternalPlayerFragment extends Fragment {
return butPlay;
}
-
@Override
public boolean loadMediaInfo() {
ExternalPlayerFragment fragment = ExternalPlayerFragment.this;
@@ -145,8 +148,11 @@ public class ExternalPlayerFragment extends Fragment {
}
controller = setupPlaybackController();
if (butPlay != null) {
- butPlay.setOnClickListener(controller
- .newOnPlayButtonClickListener());
+ butPlay.setOnClickListener(v -> {
+ if(controller != null) {
+ controller.playPause();
+ }
+ });
}
controller.init();
}
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 4c723e5ff..c1c1aab6c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -62,7 +62,6 @@ public class ItemDescriptionFragment extends Fragment implements AudioplayerCont
private static final String ARG_HIGHLIGHT_TIMECODES = "arg.highlightTimecodes";
private WebView webvDescription;
- private String webvData;
private ShownotesProvider shownotesProvider;
private Playable media;
@@ -309,7 +308,6 @@ public class ItemDescriptionFragment extends Fragment implements AudioplayerCont
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
- webvData = data;
webvDescription.loadDataWithBaseURL(null, data, "text/html",
"utf-8", "about:blank");
Log.d(TAG, "Webview loaded");
@@ -384,7 +382,7 @@ public class ItemDescriptionFragment extends Fragment implements AudioplayerCont
@Override
public void onMediaChanged(Playable media) {
- if(this.media == media) {
+ if(this.media == media || webvDescription == null) {
return;
}
this.media = media;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
index eb947dc2b..b736688b9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -124,7 +124,7 @@ public class ItunesSearchFragment extends Fragment {
} else {
gridView.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- rx.Observable.create((Observable.OnSubscribe<String>) subscriber -> {
+ subscription = Observable.create((Observable.OnSubscribe<String>) subscriber -> {
OkHttpClient client = AntennapodHttpClient.getHttpClient();
Request.Builder httpReq = new Request.Builder()
.url(podcast.feedUrl)
@@ -233,7 +233,7 @@ public class ItunesSearchFragment extends Fragment {
butRetry.setVisibility(View.GONE);
txtvEmpty.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
- subscription = rx.Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
+ subscription = Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
String lang = Locale.getDefault().getLanguage();
String url = "https://itunes.apple.com/" + lang + "/rss/toppodcasts/limit=25/explicit=true/json";
OkHttpClient client = AntennapodHttpClient.getHttpClient();
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 b3f6c3534..e5bb1d895 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -474,6 +474,7 @@ public class QueueFragment extends Fragment {
MainActivity activity = (MainActivity) getActivity();
recyclerAdapter = new QueueRecyclerAdapter(activity, itemAccess,
new DefaultActionButtonCallback(activity), itemTouchHelper);
+ recyclerAdapter.setHasStableIds(true);
recyclerView.setAdapter(recyclerAdapter);
}
if(queue == null || queue.size() == 0) {
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
index 6d76047be..152412089 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -59,6 +59,7 @@ import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
+import de.danoeh.antennapod.dialog.ProxyDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
/**
@@ -84,6 +85,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
public static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
public static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname";
public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
+ public static final String PREF_PROXY = "prefProxy";
private final PreferenceUI ui;
@@ -243,7 +245,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
(preference, o) -> {
if (o instanceof String) {
try {
- int value = Integer.valueOf((String) o);
+ int value = Integer.parseInt((String) o);
if (1 <= value && value <= 50) {
setParallelDownloadsText(value);
return true;
@@ -270,7 +272,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
try {
- int value = Integer.valueOf(s.toString());
+ int value = Integer.parseInt(s.toString());
if (value <= 0) {
ev.setText("1");
} else if (value > 50) {
@@ -353,7 +355,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
(preference, o) -> {
if (o instanceof String) {
- int newValue = Integer.valueOf((String) o) * 1024 * 1024;
+ int newValue = Integer.parseInt((String) o) * 1024 * 1024;
if (newValue != UserPreferences.getImageCacheSize()) {
AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
dialog.setTitle(android.R.string.dialog_alert_title);
@@ -366,6 +368,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
return false;
}
);
+ ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
+ ProxyDialog dialog = new ProxyDialog(ui.getActivity());
+ dialog.createDialog().show();
+ return true;
+ });
ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
@@ -792,7 +799,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
}
builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
- int hours = Integer.valueOf(values[which1]);
+ int hours = Integer.parseInt(values[which1]);
UserPreferences.setUpdateInterval(hours);
dialog1.dismiss();
setUpdateIntervalText();
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
index 7000827c6..cf9866097 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.receiver;
+import java.util.Arrays;
+
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
@@ -44,7 +46,7 @@ public class PlayerWidget extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
- Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + appWidgetIds + "]");
+ Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + Arrays.toString(appWidgetIds) + "]");
startUpdate(context);
}
diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml
index 20d879933..7b4773bca 100644
--- a/app/src/main/res/layout/downloadlog_item.xml
+++ b/app/src/main/res/layout/downloadlog_item.xml
@@ -10,14 +10,13 @@
android:paddingBottom="8dp"
tools:background="@android:color/darker_gray">
- <TextView
+ <com.joanzapata.iconify.widget.IconTextView
android:id="@+id/txtvIcon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:textSize="48sp"
- tools:text="[Icon]"
android:gravity="center" />
<com.joanzapata.iconify.widget.IconButton
diff --git a/app/src/main/res/layout/proxy_settings.xml b/app/src/main/res/layout/proxy_settings.xml
new file mode 100644
index 000000000..983325030
--- /dev/null
+++ b/app/src/main/res/layout/proxy_settings.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/txtvType"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/proxy_type_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <Spinner
+ android:id="@+id/spType"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/txtvHost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/host_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etHost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:inputType="textUri"
+ android:hint="www.example.com" />
+
+ <TextView
+ android:id="@+id/txtvPort"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/port_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etPort"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="8080"
+ android:inputType="number" />
+
+ <TextView
+ android:id="@+id/txtvUsername"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:singleLine="true"
+ android:text="@string/username_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etUsername"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/optional_hint" />
+
+ <TextView
+ android:id="@+id/txtvPassword"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/password_label"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <EditText
+ android:id="@+id/etPassword"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/optional_hint"
+ android:inputType="textPassword" />
+
+ <com.joanzapata.iconify.widget.IconTextView
+ android:id="@+id/txtvMessage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:visibility="invisible"
+ android:gravity="center"/>
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml
index 901ac49fc..71bf16d30 100644
--- a/app/src/main/res/layout/queue_fragment.xml
+++ b/app/src/main/res/layout/queue_fragment.xml
@@ -23,7 +23,7 @@
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_below="@id/divider"
android:scrollbars="vertical"/>
diff --git a/app/src/main/res/menu/opml_selection_options.xml b/app/src/main/res/menu/opml_selection_options.xml
new file mode 100644
index 000000000..26d2a0519
--- /dev/null
+++ b/app/src/main/res/menu/opml_selection_options.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@id/select_all_item"
+ android:icon="?attr/ic_check_box_outline"
+ android:title="@string/select_all_label"
+ custom:showAsAction="ifRoom">
+ </item>
+
+ <item
+ android:id="@id/deselect_all_item"
+ android:icon="?attr/ic_check_box"
+ android:title="@string/deselect_all_label"
+ custom:showAsAction="ifRoom">
+ </item>
+
+</menu>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index f290d3031..e0671e67b 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -200,8 +200,11 @@
android:key="prefEnableAutoDownloadWifiFilter"
android:title="@string/pref_autodl_wifi_filter_title"
android:summary="@string/pref_autodl_wifi_filter_sum"/>
-
</PreferenceScreen>
+ <Preference
+ android:key="prefProxy"
+ android:summary="@string/pref_proxy_sum"
+ android:title="@string/pref_proxy_title" />
</PreferenceCategory>
diff --git a/build.gradle b/build.gradle
index 53ea77e5d..dd7cd4385 100644
--- a/build.gradle
+++ b/build.gradle
@@ -41,7 +41,7 @@ project.ext {
minSdkVersion = 10
targetSdkVersion = 23
- supportVersion = "23.1.1"
+ supportVersion = "23.2.1"
commonsioVersion = "2.4"
commonslangVersion = "3.4"
eventbusVersion = "2.4.0"
@@ -49,7 +49,7 @@ project.ext {
glideVersion = "3.6.1"
iconifyVersion = "2.1.1"
jsoupVersion = "1.7.3"
- materialDialogsVersion = "0.8.5.3@aar"
+ materialDialogsVersion = "0.8.5.6@aar"
okhttpVersion = "2.7.4"
okioVersion = "1.6.0"
recyclerviewFlexibledividerVersion = "1.2.6"
@@ -57,7 +57,7 @@ project.ext {
rxJavaVersion = "1.1.0"
rxJavaRulesVersion = "1.1.0.0"
- audioPlayerVersion = "v1.0.12"
+ audioPlayerVersion = "v1.0.14"
}
task wrapper(type: Wrapper) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
index ac032fcc0..c0ec8d08a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
@@ -17,6 +17,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.ClientConfig;
@@ -46,8 +47,8 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
public static enum ExitCode {EXIT_NORMAL, NO_TOKEN, NO_NETWORK, NO_THINGS}
- private volatile int countFailed = 0;
- private volatile int countSuccess = 0;
+ private final AtomicInteger countFailed = new AtomicInteger();
+ private final AtomicInteger countSuccess = new AtomicInteger();
private volatile FlattrThing extraFlattrThing;
@@ -114,12 +115,12 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
FlattrUtils.clickUrl(context, thing.getPaymentLink());
thing.getFlattrStatus().setFlattred();
publishProgress(R.string.flattr_click_success);
- countSuccess++;
+ countSuccess.incrementAndGet();
} catch (FlattrException e) {
e.printStackTrace();
- countFailed++;
- if (countFailed == 1) {
+ int failed = countFailed.incrementAndGet();
+ if (failed == 1) {
exception = e;
}
}
@@ -148,7 +149,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
super.onPostExecute(exitCode);
switch (exitCode) {
case EXIT_NORMAL:
- if (countFailed > 0) {
+ if (countFailed.get() > 0) {
postFlattrFailedNotification();
}
break;
@@ -190,7 +191,8 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
}
private void postFlattrFailedNotification() {
- if (countFailed == 0) {
+ int failed = countFailed.get();
+ if (failed == 0) {
return;
}
@@ -198,15 +200,15 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
String title;
String subtext;
- if (countFailed == 1) {
+ if (failed == 1) {
title = context.getString(R.string.flattrd_failed_label);
String exceptionMsg = (exception.getMessage() != null) ? exception.getMessage() : "";
subtext = context.getString(R.string.flattr_click_failure, extraFlattrThing.getTitle())
+ "\n" + exceptionMsg;
} else {
title = context.getString(R.string.flattrd_label);
- subtext = context.getString(R.string.flattr_click_success_count, countSuccess) + "\n"
- + context.getString(R.string.flattr_click_failure_count, countFailed);
+ subtext = context.getString(R.string.flattr_click_success_count, countSuccess.get()) + "\n"
+ + context.getString(R.string.flattr_click_failure_count, failed);
}
Notification notification = new NotificationCompat.Builder(context)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java
index 2d174a6bc..01c888d6b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java
@@ -63,10 +63,10 @@ public class GpodnetEpisodeAction {
Action action = Action.valueOf(fields[3]);
GpodnetEpisodeAction result = new Builder(podcast, episode, action)
.deviceId(deviceId)
- .timestamp(new Date(Long.valueOf(fields[4])))
- .started(Integer.valueOf(fields[5]))
- .position(Integer.valueOf(fields[6]))
- .total(Integer.valueOf(fields[7]))
+ .timestamp(new Date(Long.parseLong(fields[4])))
+ .started(Integer.parseInt(fields[5]))
+ .position(Integer.parseInt(fields[6]))
+ .total(Integer.parseInt(fields[7]))
.build();
return result;
} catch(IllegalArgumentException e) {
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 6c0aff15e..3631f881b 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
@@ -17,6 +17,7 @@ import org.json.JSONException;
import java.io.File;
import java.io.IOException;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -25,6 +26,7 @@ import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver;
+import de.danoeh.antennapod.core.service.download.ProxyConfig;
import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
@@ -78,6 +80,11 @@ public class UserPreferences {
public static final String PREF_ENABLE_AUTODL_ON_BATTERY = "prefEnableAutoDownloadOnBattery";
public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter";
public static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks";
+ public static final String PREF_PROXY_TYPE = "prefProxyType";
+ public static final String PREF_PROXY_HOST = "prefProxyHost";
+ public static final String PREF_PROXY_PORT = "prefProxyPort";
+ public static final String PREF_PROXY_USER = "prefProxyUser";
+ public static final String PREF_PROXY_PASSWORD = "prefProxyPassword";
// Services
public static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
@@ -158,12 +165,12 @@ public class UserPreferences {
public static int getFeedOrder() {
String value = prefs.getString(PREF_DRAWER_FEED_ORDER, "0");
- return Integer.valueOf(value);
+ return Integer.parseInt(value);
}
public static int getFeedCounterSetting() {
String value = prefs.getString(PREF_DRAWER_FEED_COUNTER, "0");
- return Integer.valueOf(value);
+ return Integer.parseInt(value);
}
/**
@@ -243,7 +250,7 @@ public class UserPreferences {
}
public static int getSmartMarkAsPlayedSecs() {
- return Integer.valueOf(prefs.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30"));
+ return Integer.parseInt(prefs.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30"));
}
public static boolean isAutoFlattr() {
@@ -295,8 +302,8 @@ public class UserPreferences {
String datetime = prefs.getString(PREF_UPDATE_INTERVAL, "");
if(datetime.length() >= 3 && datetime.contains(":")) {
String[] parts = datetime.split(":");
- int hourOfDay = Integer.valueOf(parts[0]);
- int minute = Integer.valueOf(parts[1]);
+ int hourOfDay = Integer.parseInt(parts[0]);
+ int minute = Integer.parseInt(parts[1]);
return new int[] { hourOfDay, minute };
} else {
return new int[0];
@@ -308,7 +315,7 @@ public class UserPreferences {
}
public static int getParallelDownloads() {
- return Integer.valueOf(prefs.getString(PREF_PARALLEL_DOWNLOADS, "4"));
+ return Integer.parseInt(prefs.getString(PREF_PARALLEL_DOWNLOADS, "4"));
}
public static int getEpisodeCacheSizeUnlimited() {
@@ -338,12 +345,12 @@ public class UserPreferences {
public static int getImageCacheSize() {
String cacheSizeString = prefs.getString(PREF_IMAGE_CACHE_SIZE, IMAGE_CACHE_DEFAULT_VALUE);
- int cacheSizeInt = Integer.valueOf(cacheSizeString);
+ int cacheSizeInt = Integer.parseInt(cacheSizeString);
// if the cache size is too small the user won't get any images at all
// that's bad, force it back to the default.
if (cacheSizeInt < IMAGE_CACHE_SIZE_MINIMUM) {
prefs.edit().putString(PREF_IMAGE_CACHE_SIZE, IMAGE_CACHE_DEFAULT_VALUE).apply();
- cacheSizeInt = Integer.valueOf(IMAGE_CACHE_DEFAULT_VALUE);
+ cacheSizeInt = Integer.parseInt(IMAGE_CACHE_DEFAULT_VALUE);
}
int cacheSizeMB = cacheSizeInt * 1024 * 1024;
return cacheSizeMB;
@@ -371,6 +378,42 @@ public class UserPreferences {
return TextUtils.split(selectedNetWorks, ",");
}
+ public static void setProxyConfig(ProxyConfig config) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(PREF_PROXY_TYPE, config.type.name());
+ if(TextUtils.isEmpty(config.host)) {
+ editor.remove(PREF_PROXY_HOST);
+ } else {
+ editor.putString(PREF_PROXY_HOST, config.host);
+ }
+ if(config.port <= 0 || config.port > 65535) {
+ editor.remove(PREF_PROXY_PORT);
+ } else {
+ editor.putInt(PREF_PROXY_PORT, config.port);
+ }
+ if(TextUtils.isEmpty(config.username)) {
+ editor.remove(PREF_PROXY_USER);
+ } else {
+ editor.putString(PREF_PROXY_USER, config.username);
+ }
+ if(TextUtils.isEmpty(config.password)) {
+ editor.remove(PREF_PROXY_PASSWORD);
+ } else {
+ editor.putString(PREF_PROXY_PASSWORD, config.password);
+ }
+ editor.apply();
+ }
+
+ public static ProxyConfig getProxyConfig() {
+ Proxy.Type type = Proxy.Type.valueOf(prefs.getString(PREF_PROXY_TYPE, Proxy.Type.DIRECT.name()));
+ String host = prefs.getString(PREF_PROXY_HOST, null);
+ int port = prefs.getInt(PREF_PROXY_PORT, 0);
+ String username = prefs.getString(PREF_PROXY_USER, null);
+ String password = prefs.getString(PREF_PROXY_PASSWORD, null);
+ ProxyConfig config = new ProxyConfig(type, host, port, username, password);
+ return config;
+ }
+
public static boolean shouldResumeAfterCall() {
return prefs.getBoolean(PREF_RESUME_AFTER_CALL, true);
}
@@ -494,7 +537,7 @@ public class UserPreferences {
if (valueFromPrefs.equals(context.getString(R.string.pref_episode_cache_unlimited))) {
return EPISODE_CACHE_SIZE_UNLIMITED;
} else {
- return Integer.valueOf(valueFromPrefs);
+ return Integer.parseInt(valueFromPrefs);
}
}
@@ -548,7 +591,7 @@ public class UserPreferences {
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
- int cleanupValue = Integer.valueOf(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
+ int cleanupValue = Integer.parseInt(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
if (cleanupValue == EPISODE_CLEANUP_QUEUE) {
return new APQueueCleanupAlgorithm();
} else if (cleanupValue == EPISODE_CLEANUP_NULL) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
index b23819ef7..5dd1e2dfa 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
@@ -2,8 +2,10 @@ package de.danoeh.antennapod.core.service.download;
import android.os.Build;
import android.support.annotation.NonNull;
+import android.text.TextUtils;
import android.util.Log;
+import com.squareup.okhttp.Credentials;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
@@ -14,7 +16,10 @@ import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.HttpURLConnection;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.net.Socket;
+import java.net.SocketAddress;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.concurrent.TimeUnit;
@@ -23,6 +28,7 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBWriter;
/**
@@ -44,12 +50,15 @@ public class AntennapodHttpClient {
*/
public static synchronized OkHttpClient getHttpClient() {
if (httpClient == null) {
-
httpClient = newHttpClient();
}
return httpClient;
}
+ public static synchronized void reinit() {
+ httpClient = newHttpClient();
+ }
+
/**
* Creates a new HTTP client. Most users should just use
* getHttpClient() to get the standard AntennaPod client,
@@ -69,13 +78,13 @@ public class AntennapodHttpClient {
client.networkInterceptors().add(chain -> {
Request request = chain.request();
Response response = chain.proceed(request);
- if(response.code() == HttpURLConnection.HTTP_MOVED_PERM ||
+ if (response.code() == HttpURLConnection.HTTP_MOVED_PERM ||
response.code() == StatusLine.HTTP_PERM_REDIRECT) {
String location = response.header("Location");
- if(location.startsWith("/")) { // URL is not absolute, but relative
+ if (location.startsWith("/")) { // URL is not absolute, but relative
URL url = request.url();
location = url.getProtocol() + "://" + url.getHost() + location;
- } else if(!location.toLowerCase().startsWith("http://") &&
+ } else if (!location.toLowerCase().startsWith("http://") &&
!location.toLowerCase().startsWith("https://")) {
// Reference is relative to current path
URL url = request.url();
@@ -106,6 +115,21 @@ public class AntennapodHttpClient {
client.setFollowRedirects(true);
client.setFollowSslRedirects(true);
+ ProxyConfig config = UserPreferences.getProxyConfig();
+ if (config.type != Proxy.Type.DIRECT) {
+ int port = config.port > 0 ? config.port : ProxyConfig.DEFAULT_PORT;
+ SocketAddress address = InetSocketAddress.createUnresolved(config.host, port);
+ Proxy proxy = new Proxy(config.type, address);
+ client.setProxy(proxy);
+ if (!TextUtils.isEmpty(config.username)) {
+ String credentials = Credentials.basic(config.username, config.password);
+ client.interceptors().add(chain -> {
+ Request request = chain.request().newBuilder()
+ .header("Proxy-Authorization", credentials).build();
+ return chain.proceed(request);
+ });
+ }
+ }
if(16 <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < 21) {
client.setSslSocketFactory(new CustomSslSocketFactory());
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
index 7f40ea6e2..de91916a9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
@@ -128,7 +128,8 @@ public class DownloadRequest implements Parcelable {
DownloadRequest that = (DownloadRequest) o;
- if (lastModified != that.lastModified) return false;
+ if (lastModified != null ? !lastModified.equals(that.lastModified) : that.lastModified != null)
+ return false;
if (deleteOnFailure != that.deleteOnFailure) return false;
if (feedfileId != that.feedfileId) return false;
if (feedfileType != that.feedfileType) return false;
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 090c48ca0..be6cd88cb 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
@@ -188,7 +188,7 @@ public class DownloadService extends Service {
if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
postAuthenticationNotification(downloader.getDownloadRequest());
} else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
- && Integer.valueOf(status.getReasonDetailed()) == 416) {
+ && Integer.parseInt(status.getReasonDetailed()) == 416) {
Log.d(TAG, "Requested invalid range, restarting download from the beginning");
FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination()));
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
index e3a195253..2b26f58c0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
@@ -27,6 +27,7 @@ import java.util.Date;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.feed.FeedImage;
+import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.DownloadError;
import de.danoeh.antennapod.core.util.StorageUtils;
@@ -67,6 +68,12 @@ public class HttpDownloader extends Downloader {
final URI uri = URIUtil.getURIFromRequestUrl(request.getSource());
Request.Builder httpReq = new Request.Builder().url(uri.toURL())
.header("User-Agent", ClientConfig.USER_AGENT);
+ if(request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ // set header explicitly so that okhttp doesn't do transparent gzip
+ Log.d(TAG, "addHeader(\"Accept-Encoding\", \"identity\")");
+ httpReq.addHeader("Accept-Encoding", "identity");
+ }
+
if(!TextUtils.isEmpty(request.getLastModified())) {
String lastModified = request.getLastModified();
Date lastModifiedDate = DateUtils.parse(lastModified);
@@ -117,6 +124,15 @@ public class HttpDownloader extends Downloader {
throw e;
}
}
+
+ if(request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ String contentType = response.header("Content-Type");
+ if(!contentType.startsWith("audio/") && !contentType.startsWith("video/")) {
+ onFail(DownloadError.ERROR_FILE_TYPE, null);
+ return;
+ }
+ }
+
responseBody = response.body();
String contentEncodingHeader = response.header("Content-Encoding");
boolean isGzip = false;
@@ -180,7 +196,7 @@ public class HttpDownloader extends Downloader {
&& !TextUtils.isEmpty(contentRangeHeader)) {
String start = contentRangeHeader.substring("bytes ".length(),
contentRangeHeader.indexOf("-"));
- request.setSoFar(Long.valueOf(start));
+ request.setSoFar(Long.parseLong(start));
Log.d(TAG, "Starting download at position " + request.getSoFar());
out = new RandomAccessFile(destination, "rw");
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
new file mode 100644
index 000000000..e886932f2
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
@@ -0,0 +1,32 @@
+package de.danoeh.antennapod.core.service.download;
+
+import android.support.annotation.Nullable;
+
+import java.net.Proxy;
+
+public class ProxyConfig {
+
+ public final Proxy.Type type;
+ @Nullable public final String host;
+ @Nullable public final int port;
+ @Nullable public final String username;
+ @Nullable public final String password;
+
+ public final static int DEFAULT_PORT = 8080;
+
+ public static ProxyConfig direct() {
+ return new ProxyConfig(Proxy.Type.DIRECT, null, 0, null, null);
+ }
+
+ public static ProxyConfig http(String host, int port, String username, String password) {
+ return new ProxyConfig(Proxy.Type.HTTP, host, port, username, password);
+ }
+
+ public ProxyConfig(Proxy.Type type, String host, int port, String username, String password) {
+ this.type = type;
+ this.host = host;
+ this.port = port;
+ this.username = username;
+ this.password = password;
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index a82e82506..d3a5f576a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -604,7 +604,11 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
* Returns the position of the current media object or INVALID_TIME if the position could not be retrieved.
*/
public int getPosition() {
- if (!playerLock.tryLock()) {
+ try {
+ if (!playerLock.tryLock(50, TimeUnit.MILLISECONDS)) {
+ return INVALID_TIME;
+ }
+ } catch (InterruptedException e) {
return INVALID_TIME;
}
@@ -693,7 +697,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
}
/**
- * Sets the playback speed.
+ * Sets the playback volume.
* This method is executed on an internal executor service.
*/
public void setVolume(final float volumeLeft, float volumeRight) {
@@ -701,7 +705,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
}
/**
- * Sets the playback speed.
+ * Sets the playback volume.
* This method is executed on the caller's thread.
*/
private void setVolumeSync(float volumeLeft, float volumeRight) {
@@ -946,15 +950,16 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
if (pausedBecauseOfTransientAudiofocusLoss) { // we paused => play now
resume();
} else { // we ducked => raise audio level back
- audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_RAISE, 0);
+ setVolumeSync(UserPreferences.getLeftVolume(),
+ UserPreferences.getRightVolume());
}
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
if (playerStatus == PlayerStatus.PLAYING) {
if (!UserPreferences.shouldPauseForFocusLoss()) {
Log.d(TAG, "Lost audio focus temporarily. Ducking...");
- audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
- AudioManager.ADJUST_LOWER, 0);
+ final float DUCK_FACTOR = 0.25f;
+ setVolumeSync(DUCK_FACTOR * UserPreferences.getLeftVolume(),
+ DUCK_FACTOR * UserPreferences.getRightVolume());
pausedBecauseOfTransientAudiofocusLoss = false;
} else {
Log.d(TAG, "Lost audio focus temporarily. Could duck, but won't, pausing...");
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index 68187306d..4f2400e1d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -4,6 +4,7 @@ import android.database.Cursor;
import android.support.v4.util.ArrayMap;
import android.util.Log;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -676,7 +677,7 @@ public final class DBReader {
* as well as chapter marks of the FeedItems will also be loaded from the database.
*/
public static List<FeedItem> getFeedItems(final long... itemIds) {
- Log.d(TAG, "getFeedItems() called with: " + "itemIds = [" + itemIds + "]");
+ Log.d(TAG, "getFeedItems() called with: " + "itemIds = [" + Arrays.toString(itemIds) + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FeedItem> items = getFeedItems(adapter, itemIds);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
index 99c4cd67a..769a796e3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java
@@ -60,12 +60,12 @@ public class NSITunes extends Namespace {
try {
int duration = 0;
if (parts.length == 2) {
- duration += TimeUnit.MINUTES.toMillis(Long.valueOf(parts[0])) +
- TimeUnit.SECONDS.toMillis(Long.valueOf(parts[1]));
+ duration += TimeUnit.MINUTES.toMillis(Long.parseLong(parts[0])) +
+ TimeUnit.SECONDS.toMillis(Long.parseLong(parts[1]));
} else if (parts.length >= 3) {
- duration += TimeUnit.HOURS.toMillis(Long.valueOf(parts[0])) +
- TimeUnit.MINUTES.toMillis(Long.valueOf(parts[1])) +
- TimeUnit.SECONDS.toMillis(Long.valueOf(parts[2]));
+ duration += TimeUnit.HOURS.toMillis(Long.parseLong(parts[0])) +
+ TimeUnit.MINUTES.toMillis(Long.parseLong(parts[1])) +
+ TimeUnit.SECONDS.toMillis(Long.parseLong(parts[2]));
} else {
return;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java
index 1b929b214..2e3afefa9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java
@@ -88,9 +88,9 @@ public final class Converter {
if (parts.length != 3) {
return 0;
}
- return Integer.valueOf(parts[0]) * 3600 * 1000 +
- Integer.valueOf(parts[1]) * 60 * 1000 +
- Integer.valueOf(parts[2]) * 1000;
+ return Integer.parseInt(parts[0]) * 3600 * 1000 +
+ Integer.parseInt(parts[1]) * 60 * 1000 +
+ Integer.parseInt(parts[2]) * 1000;
}
/** Converts short duration string (HH:MM) to milliseconds. */
@@ -99,8 +99,8 @@ public final class Converter {
if (parts.length != 2) {
return 0;
}
- return Integer.valueOf(parts[0]) * 3600 * 1000 +
- Integer.valueOf(parts[1]) * 1000 * 60;
+ return Integer.parseInt(parts[0]) * 3600 * 1000 +
+ Integer.parseInt(parts[1]) * 1000 * 60;
}
/** Converts milliseconds to a localized string containing hours and minutes */
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
index 6b0f423df..314062e52 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
@@ -19,14 +19,8 @@ public class DateUtils {
private static final String TAG = "DateUtils";
- private static final SimpleDateFormat parser = new SimpleDateFormat("", Locale.US);
private static final TimeZone defaultTimezone = TimeZone.getTimeZone("GMT");
- static {
- parser.setLenient(false);
- parser.setTimeZone(defaultTimezone);
- }
-
public static Date parse(final String input) {
if(input == null) {
throw new IllegalArgumentException("Date must not be null");
@@ -86,6 +80,10 @@ public class DateUtils {
"yyyy-MM-dd"
};
+ SimpleDateFormat parser = new SimpleDateFormat("", Locale.US);
+ parser.setLenient(false);
+ parser.setTimeZone(defaultTimezone);
+
ParsePosition pos = new ParsePosition(0);
for(String pattern : patterns) {
parser.applyPattern(pattern);
@@ -117,13 +115,13 @@ public class DateUtils {
int idx = 0;
if (parts.length == 3) {
// string has hours
- result += Integer.valueOf(parts[idx]) * 3600000L;
+ result += Integer.parseInt(parts[idx]) * 3600000L;
idx++;
}
if (parts.length >= 2) {
- result += Integer.valueOf(parts[idx]) * 60000L;
+ result += Integer.parseInt(parts[idx]) * 60000L;
idx++;
- result += (Float.valueOf(parts[idx])) * 1000L;
+ result += (Float.parseFloat(parts[idx])) * 1000L;
}
return result;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java b/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java
index 602c221bf..d3f6c6b79 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/DownloadError.java
@@ -19,7 +19,8 @@ public enum DownloadError {
ERROR_UNKNOWN_HOST(11, R.string.download_error_unknown_host),
ERROR_REQUEST_ERROR(12, R.string.download_error_request_error),
ERROR_DB_ACCESS_ERROR(13, R.string.download_error_db_access),
- ERROR_UNAUTHORIZED(14, R.string.download_error_unauthorized);
+ ERROR_UNAUTHORIZED(14, R.string.download_error_unauthorized),
+ ERROR_FILE_TYPE(15, R.string.download_error_file_type_type);
private final int code;
private final int resId;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java b/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java
index 673c81235..1cbe7fade 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/IntList.java
@@ -35,7 +35,7 @@ public final class IntList {
int hashCode = 1;
for (int i = 0; i < size; i++) {
int value = values[i];
- hashCode = 31 * hashCode + (int)(value ^ (value >>> 32));
+ hashCode = 31 * hashCode + value;
}
return hashCode;
}
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 27935978c..1a011a90b 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
@@ -19,7 +19,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
-import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
@@ -424,6 +423,7 @@ public abstract class PlaybackController {
clearStatusMsg();
checkMediaInfoLoaded();
cancelPositionObserver();
+ onPositionObserverUpdate();
updatePlayButtonAppearance(playResource, playText);
if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) {
setScreenOn(false);
@@ -574,34 +574,32 @@ public abstract class PlaybackController {
}
- public OnClickListener newOnPlayButtonClickListener() {
- return v -> {
- if (playbackService == null) {
- Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!");
- return;
- }
- switch (status) {
- case PLAYING:
- playbackService.pause(true, reinitOnPause);
- break;
- case PAUSED:
- case PREPARED:
- playbackService.resume();
- break;
- case PREPARING:
- playbackService.setStartWhenPrepared(!playbackService
- .isStartWhenPrepared());
- if (reinitOnPause
- && playbackService.isStartWhenPrepared() == false) {
- playbackService.reinit();
- }
- break;
- case INITIALIZED:
- playbackService.setStartWhenPrepared(true);
- playbackService.prepare();
- break;
- }
- };
+ public void playPause() {
+ if (playbackService == null) {
+ Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!");
+ return;
+ }
+ switch (status) {
+ case PLAYING:
+ playbackService.pause(true, reinitOnPause);
+ break;
+ case PAUSED:
+ case PREPARED:
+ playbackService.resume();
+ break;
+ case PREPARING:
+ playbackService.setStartWhenPrepared(!playbackService
+ .isStartWhenPrepared());
+ if (reinitOnPause
+ && playbackService.isStartWhenPrepared() == false) {
+ playbackService.reinit();
+ }
+ break;
+ case INITIALIZED:
+ playbackService.setStartWhenPrepared(true);
+ playbackService.prepare();
+ break;
+ }
}
public boolean serviceAvailable() {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
index 2eee1ac87..8d9151396 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
@@ -2,7 +2,10 @@ package de.danoeh.antennapod.core.util.playback;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
+import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
@@ -14,6 +17,7 @@ import org.jsoup.select.Elements;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.ShownotesProvider;
@@ -32,26 +36,32 @@ public class Timeline {
private ShownotesProvider shownotesProvider;
-
- private final String colorString;
+ private final String noShownotesLabel;
+ private final String colorPrimaryString;
+ private final String colorSecondaryString;
private final int pageMargin;
public Timeline(Context context, ShownotesProvider shownotesProvider) {
if (shownotesProvider == null) throw new IllegalArgumentException("shownotesProvider = null");
this.shownotesProvider = shownotesProvider;
- TypedArray res = context
- .getTheme()
- .obtainStyledAttributes(
- new int[]{android.R.attr.textColorPrimary});
- int colorResource = res.getColor(0, 0);
- colorString = String.format("#%06X",
- 0xFFFFFF & colorResource);
+ noShownotesLabel = context.getString(R.string.no_shownotes_label);
+
+ TypedArray res = context.getTheme().obtainStyledAttributes(
+ new int[]{ android.R.attr.textColorPrimary});
+ @ColorInt int col = res.getColor(0, 0);
+ colorPrimaryString = "rgba(" + Color.red(col) + "," + Color.green(col) + "," +
+ Color.blue(col) + "," + (Color.alpha(col)/256.0) + ")";
+ res.recycle();
+ res = context.getTheme().obtainStyledAttributes(
+ new int[]{android.R.attr.textColorSecondary});
+ col = res.getColor(0, 0);
+ colorSecondaryString = "rgba(" + Color.red(col) + "," + Color.green(col) + "," +
+ Color.blue(col) + "," + (Color.alpha(col)/256.0) + ")";
res.recycle();
- pageMargin = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 8, context.getResources()
- .getDisplayMetrics()
+ pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
+ context.getResources().getDisplayMetrics()
);
}
@@ -82,9 +92,24 @@ public class Timeline {
e.printStackTrace();
return null;
}
- if (shownotes == null) {
- Log.d(TAG, "shownotesProvider contained no shownotes. Returning empty string");
- return "";
+
+ if(TextUtils.isEmpty(shownotes)) {
+ Log.d(TAG, "shownotesProvider contained no shownotes. Returning 'no shownotes' message");
+ shownotes ="<html>" +
+ "<head>" +
+ "<style type='text/css'>" +
+ "html, body { margin: 0; padding: 0; width: 100%; height: 100%; } " +
+ "html { display: table; }" +
+ "body { display: table-cell; vertical-align: middle; text-align:center;" +
+ "-webkit-text-size-adjust: none; font-size: 87%; color: " + colorSecondaryString + ";} " +
+ "</style>" +
+ "</head>" +
+ "<body>" +
+ "<p>" + noShownotesLabel + "</p>" +
+ "</body>" +
+ "</html>";
+ Log.d(TAG, "shownotes: " + shownotes);
+ return shownotes;
}
// replace ASCII line breaks with HTML ones if shownotes don't contain HTML line breaks already
@@ -95,7 +120,7 @@ public class Timeline {
Document document = Jsoup.parse(shownotes);
// apply style
- String styleStr = String.format(WEBVIEW_STYLE, colorString, "100%", pageMargin,
+ String styleStr = String.format(WEBVIEW_STYLE, colorPrimaryString, "100%", pageMargin,
pageMargin, pageMargin, pageMargin);
document.head().appendElement("style").attr("type", "text/css").text(styleStr);
@@ -125,8 +150,7 @@ public class Timeline {
element.html(buffer.toString());
}
}
-
- Log.i(TAG, "Out: " + document.toString());
+
return document.toString();
}
@@ -148,7 +172,7 @@ public class Timeline {
try {
if (m.find()) {
- return Integer.valueOf(m.group(1));
+ return Integer.parseInt(m.group(1));
}
} catch (NumberFormatException e) {
e.printStackTrace();
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index d4891eee8..777db5046 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -178,6 +178,7 @@
<string name="download_error_connection_error">Connection Error</string>
<string name="download_error_unknown_host">Unknown Host</string>
<string name="download_error_unauthorized">Authentication Error</string>
+ <string name="download_error_file_type_type">File Type Error</string>
<string name="cancel_all_downloads_label">Cancel all downloads</string>
<string name="download_canceled_msg">Download canceled</string>
<string name="download_canceled_autodownload_enabled_msg">Download canceled\nDisabled <i>Auto Download</i> for this item</string>
@@ -278,6 +279,8 @@
<string name="no_items_label">There are no items in this list.</string>
<string name="no_feeds_label">You haven\'t subscribed to any feeds yet.</string>
<string name="no_chapters_label">This episode has no chapters.</string>
+ <string name="no_shownotes_label">This episode has no shownotes.</string>
+
<!-- Preferences -->
<string name="other_pref">Other</string>
@@ -388,6 +391,8 @@
<string name="pref_sonic_title">Sonic media player</string>
<string name="pref_sonic_message">Use built-in sonic media player as a replacement for Android\'s native mediaplayer and Prestissimo</string>
<string name="pref_current_value">Current value: %1$s</string>
+ <string name="pref_proxy_title">Proxy</string>
+ <string name="pref_proxy_sum">Set a network proxy</string>
<!-- Auto-Flattr dialog -->
<string name="auto_flattr_enable">Enable automatic flattring</string>
@@ -412,8 +417,8 @@
<string name="opml_import_label">OPML Import</string>
<string name="opml_directory_error">ERROR!</string>
<string name="reading_opml_label">Reading OPML file</string>
- <string name="opml_reader_error">An error has occurred while reading the opml document:</string>
- <string name="opml_import_error_dir_empty">The import directory is empty.</string>
+ <string name="opml_reader_error">An error has occurred while reading the OPML document:</string>
+ <string name="opml_import_error_no_file">No file selected!</string>
<string name="select_all_label">Select all</string>
<string name="deselect_all_label">Deselect all</string>
<string name="select_options_label">Select&#8230;</string>
@@ -594,4 +599,17 @@
<string name="stereo_to_mono">Downmix: Stereo to mono</string>
<string name="sonic_only">Sonic only</string>
+ <!-- proxy settings -->
+ <string name="proxy_type_label">Type</string>
+ <string name="host_label">Host</string>
+ <string name="port_label">Port</string>
+ <string name="optional_hint">(Optional)</string>
+ <string name="proxy_test_label">Test</string>
+ <string name="proxy_checking">Checking&#8230;</string>
+ <string name="proxy_test_successful">Test successful</string>
+ <string name="proxy_test_failed">Test failed</string>
+ <string name="proxy_host_empty_error">Host must not be empty</string>
+ <string name="proxy_host_invalid_error">Host not valid UP or domain</string>
+ <string name="proxy_port_invalid_error">Port not valid</string>
+
</resources>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index c4a731a53..d79ba6b45 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -63,6 +63,7 @@
<style name="Theme.AntennaPod.Dark" parent="Theme.AppCompat">
<item name="colorAccent">@color/holo_blue_dark</item>
+ <item name="colorControlNormal">@color/white</item>
<item name="buttonStyle">@style/Widget.AntennaPod.Button</item>
<item name="progressBarTheme">@style/ProgressBarDark</item>
<item name="alertDialogTheme">@style/AntennaPod.Dialog.Dark</item>
@@ -186,6 +187,7 @@
<item name="windowActionModeOverlay">true</item>
<item name="progressBarTheme">@style/ProgressBarDark</item>
<item name="colorAccent">@color/holo_blue_dark</item>
+ <item name="colorControlNormal">@color/white</item>
<item name="buttonStyle">@style/Widget.AntennaPod.Button</item>
<item name="alertDialogTheme">@style/AntennaPod.Dialog.Dark</item>
<item name="attr/action_about">@drawable/ic_info_white_24dp</item>