Merge branch 'develop' into typos
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="de.danoeh.antennapod"
|
package="de.danoeh.antennapod"
|
||||||
android:versionCode="1050104"
|
android:versionCode="1050200"
|
||||||
android:versionName="1.5.1.4">
|
android:versionName="1.5.2.0">
|
||||||
<!--
|
<!--
|
||||||
Version code schema:
|
Version code schema:
|
||||||
"1.2.3-SNAPSHOT" -> 1020300
|
"1.2.3-SNAPSHOT" -> 1020300
|
||||||
@ -179,7 +179,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".activity.VideoplayerActivity"
|
android:name=".activity.VideoplayerActivity"
|
||||||
android:configChanges="keyboardHidden|orientation"
|
android:configChanges="keyboardHidden|orientation"
|
||||||
android:screenOrientation="landscape">
|
android:screenOrientation="sensorLandscape">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="de.danoeh.antennapod.activity.MainActivity"/>
|
android:value="de.danoeh.antennapod.activity.MainActivity"/>
|
||||||
|
@ -8,11 +8,8 @@ import com.joanzapata.iconify.Iconify;
|
|||||||
import com.joanzapata.iconify.fonts.FontAwesomeModule;
|
import com.joanzapata.iconify.fonts.FontAwesomeModule;
|
||||||
import com.joanzapata.iconify.fonts.MaterialModule;
|
import com.joanzapata.iconify.fonts.MaterialModule;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
|
||||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
|
||||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
|
||||||
import de.danoeh.antennapod.spa.SPAUtil;
|
import de.danoeh.antennapod.spa.SPAUtil;
|
||||||
|
|
||||||
/** Main application class. */
|
/** Main application class. */
|
||||||
@ -56,11 +53,8 @@ public class PodcastApp extends Application {
|
|||||||
|
|
||||||
singleton = this;
|
singleton = this;
|
||||||
|
|
||||||
PodDBAdapter.init(this);
|
ClientConfig.initialize(this);
|
||||||
UserPreferences.init(this);
|
|
||||||
UpdateManager.init(this);
|
|
||||||
PlaybackPreferences.init(this);
|
|
||||||
NetworkUtils.init(this);
|
|
||||||
EventDistributor.getInstance();
|
EventDistributor.getInstance();
|
||||||
Iconify.with(new FontAwesomeModule());
|
Iconify.with(new FontAwesomeModule());
|
||||||
Iconify.with(new MaterialModule());
|
Iconify.with(new MaterialModule());
|
||||||
|
@ -103,6 +103,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
Log.d(TAG, "onStop()");
|
Log.d(TAG, "onStop()");
|
||||||
|
pagerAdapter.setController(null);
|
||||||
if(subscription != null) {
|
if(subscription != null) {
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
@ -112,9 +113,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
Log.d(TAG, "onDestroy()");
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
// don't risk creating memory leaks
|
// don't risk creating memory leaks
|
||||||
|
drawerLayout = null;
|
||||||
navAdapter = null;
|
navAdapter = null;
|
||||||
|
navList = null;
|
||||||
|
navDrawer = null;
|
||||||
drawerToggle = null;
|
drawerToggle = null;
|
||||||
pager = null;
|
pager = null;
|
||||||
pagerAdapter = null;
|
pagerAdapter = null;
|
||||||
@ -171,6 +176,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
|
if(pagerAdapter != null && controller != null && controller.getMedia() != media) {
|
||||||
media = controller.getMedia();
|
media = controller.getMedia();
|
||||||
pagerAdapter.onMediaChanged(media);
|
pagerAdapter.onMediaChanged(media);
|
||||||
|
pagerAdapter.setController(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventDistributor.getInstance().register(contentUpdate);
|
EventDistributor.getInstance().register(contentUpdate);
|
||||||
@ -258,7 +264,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
});
|
});
|
||||||
|
|
||||||
pager = (ViewPager) findViewById(R.id.pager);
|
pager = (ViewPager) findViewById(R.id.pager);
|
||||||
pagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager());
|
pagerAdapter = new AudioplayerPagerAdapter(getSupportFragmentManager(), media);
|
||||||
|
pagerAdapter.setController(controller);
|
||||||
pager.setAdapter(pagerAdapter);
|
pager.setAdapter(pagerAdapter);
|
||||||
CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
|
CirclePageIndicator pageIndicator = (CirclePageIndicator) findViewById(R.id.page_indicator);
|
||||||
pageIndicator.setViewPager(pager);
|
pageIndicator.setViewPager(pager);
|
||||||
@ -537,10 +544,16 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
void onMediaChanged(Playable media);
|
void onMediaChanged(Playable media);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AudioplayerPagerAdapter extends FragmentStatePagerAdapter {
|
private static class AudioplayerPagerAdapter extends FragmentStatePagerAdapter {
|
||||||
|
|
||||||
public AudioplayerPagerAdapter(FragmentManager fm) {
|
private static final String TAG = "AudioplayerPagerAdapter";
|
||||||
|
|
||||||
|
private Playable media;
|
||||||
|
private PlaybackController controller;
|
||||||
|
|
||||||
|
public AudioplayerPagerAdapter(FragmentManager fm, Playable media) {
|
||||||
super(fm);
|
super(fm);
|
||||||
|
this.media = media;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoverFragment coverFragment;
|
private CoverFragment coverFragment;
|
||||||
@ -548,6 +561,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
private ChaptersFragment chaptersFragment;
|
private ChaptersFragment chaptersFragment;
|
||||||
|
|
||||||
public void onMediaChanged(Playable media) {
|
public void onMediaChanged(Playable media) {
|
||||||
|
this.media = media;
|
||||||
if(coverFragment != null) {
|
if(coverFragment != null) {
|
||||||
coverFragment.onMediaChanged(media);
|
coverFragment.onMediaChanged(media);
|
||||||
}
|
}
|
||||||
@ -559,6 +573,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setController(PlaybackController controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
if(chaptersFragment != null) {
|
||||||
|
chaptersFragment.setController(controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public ChaptersFragment getChaptersFragment() {
|
public ChaptersFragment getChaptersFragment() {
|
||||||
return chaptersFragment;
|
return chaptersFragment;
|
||||||
@ -580,7 +601,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe
|
|||||||
return itemDescriptionFragment;
|
return itemDescriptionFragment;
|
||||||
case POS_CHAPTERS:
|
case POS_CHAPTERS:
|
||||||
if(chaptersFragment == null) {
|
if(chaptersFragment == null) {
|
||||||
chaptersFragment = ChaptersFragment.newInstance(media, controller);
|
chaptersFragment = ChaptersFragment.newInstance(media);
|
||||||
|
chaptersFragment.setController(controller);
|
||||||
}
|
}
|
||||||
return chaptersFragment;
|
return chaptersFragment;
|
||||||
default:
|
default:
|
||||||
|
@ -86,6 +86,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
|
|||||||
public static final String EXTRA_NAV_INDEX = "nav_index";
|
public static final String EXTRA_NAV_INDEX = "nav_index";
|
||||||
public static final String EXTRA_FRAGMENT_TAG = "fragment_tag";
|
public static final String EXTRA_FRAGMENT_TAG = "fragment_tag";
|
||||||
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
|
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
|
||||||
|
public static final String EXTRA_FEED_ID = "fragment_feed_id";
|
||||||
|
|
||||||
public static final String SAVE_BACKSTACK_COUNT = "backstackCount";
|
public static final String SAVE_BACKSTACK_COUNT = "backstackCount";
|
||||||
public static final String SAVE_TITLE = "title";
|
public static final String SAVE_TITLE = "title";
|
||||||
@ -184,7 +185,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
|
|||||||
loadFragment(lastFragment, null);
|
loadFragment(lastFragment, null);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
loadFeedFragmentById(Integer.valueOf(lastFragment), null);
|
loadFeedFragmentById(Integer.parseInt(lastFragment), null);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// it's not a number, this happens if we removed
|
// it's not a number, this happens if we removed
|
||||||
// a label from the NAV_DRAWER_TAGS
|
// a label from the NAV_DRAWER_TAGS
|
||||||
@ -464,8 +465,9 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
|
|||||||
StorageUtils.checkStorageAvailability(this);
|
StorageUtils.checkStorageAvailability(this);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (navDrawerData != null && intent.hasExtra(EXTRA_NAV_TYPE) &&
|
if (intent.hasExtra(EXTRA_FEED_ID) ||
|
||||||
(intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG))) {
|
(navDrawerData != null && intent.hasExtra(EXTRA_NAV_TYPE) &&
|
||||||
|
(intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) {
|
||||||
handleNavIntent();
|
handleNavIntent();
|
||||||
}
|
}
|
||||||
loadData();
|
loadData();
|
||||||
@ -709,15 +711,19 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity
|
|||||||
private void handleNavIntent() {
|
private void handleNavIntent() {
|
||||||
Log.d(TAG, "handleNavIntent()");
|
Log.d(TAG, "handleNavIntent()");
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (intent.hasExtra(EXTRA_NAV_TYPE) &&
|
if (intent.hasExtra(EXTRA_FEED_ID) ||
|
||||||
intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)) {
|
(intent.hasExtra(EXTRA_NAV_TYPE) &&
|
||||||
|
(intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG)))) {
|
||||||
int index = intent.getIntExtra(EXTRA_NAV_INDEX, -1);
|
int index = intent.getIntExtra(EXTRA_NAV_INDEX, -1);
|
||||||
String tag = intent.getStringExtra(EXTRA_FRAGMENT_TAG);
|
String tag = intent.getStringExtra(EXTRA_FRAGMENT_TAG);
|
||||||
Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS);
|
Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS);
|
||||||
|
long feedId = intent.getLongExtra(EXTRA_FEED_ID, 0);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
loadFragment(index, args);
|
loadFragment(index, args);
|
||||||
} else if (tag != null) {
|
} else if (tag != null) {
|
||||||
loadFragment(tag, args);
|
loadFragment(tag, args);
|
||||||
|
} else if(feedId > 0) {
|
||||||
|
loadFeedFragmentById(feedId, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIntent(new Intent(MainActivity.this, MainActivity.class)); // to avoid handling the intent twice when the configuration changes
|
setIntent(new Intent(MainActivity.this, MainActivity.class)); // to avoid handling the intent twice when the configuration changes
|
||||||
|
@ -249,9 +249,6 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
controller.release();
|
controller.release();
|
||||||
}
|
}
|
||||||
controller = newPlaybackController();
|
controller = newPlaybackController();
|
||||||
if(butPlay != null) {
|
|
||||||
butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -260,6 +257,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
Log.d(TAG, "onStop()");
|
Log.d(TAG, "onStop()");
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
controller.release();
|
controller.release();
|
||||||
|
controller = null; // prevent leak
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,9 +484,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
|
barPlaybackSpeed.setProgress((int) (20 * currentSpeed) - 10);
|
||||||
|
|
||||||
final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
|
final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
|
||||||
barLeftVolume.setProgress(100);
|
barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
|
||||||
final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
|
final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
|
||||||
barRightVolume.setProgress(100);
|
barRightVolume.setProgress(UserPreferences.getRightVolumePercentage());
|
||||||
final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
|
final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
|
||||||
stereoToMono.setChecked(UserPreferences.stereoToMono());
|
stereoToMono.setChecked(UserPreferences.stereoToMono());
|
||||||
if (controller != null && !controller.canDownmix()) {
|
if (controller != null && !controller.canDownmix()) {
|
||||||
@ -500,14 +498,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
float leftVolume = 1.0f, rightVolume = 1.0f;
|
controller.setVolume(
|
||||||
if (progress < 100) {
|
Converter.getVolumeFromPercentage(progress),
|
||||||
leftVolume = progress / 100.0f;
|
Converter.getVolumeFromPercentage(barRightVolume.getProgress()));
|
||||||
}
|
|
||||||
if (barRightVolume.getProgress() < 100) {
|
|
||||||
rightVolume = barRightVolume.getProgress() / 100.0f;
|
|
||||||
}
|
|
||||||
controller.setVolume(leftVolume, rightVolume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -521,14 +514,9 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
barRightVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
barRightVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
float leftVolume = 1.0f, rightVolume = 1.0f;
|
controller.setVolume(
|
||||||
if (progress < 100) {
|
Converter.getVolumeFromPercentage(barLeftVolume.getProgress()),
|
||||||
rightVolume = progress / 100.0f;
|
Converter.getVolumeFromPercentage(progress));
|
||||||
}
|
|
||||||
if (barLeftVolume.getProgress() < 100) {
|
|
||||||
leftVolume = barLeftVolume.getProgress() / 100.0f;
|
|
||||||
}
|
|
||||||
controller.setVolume(leftVolume, rightVolume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -761,8 +749,7 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
|
|
||||||
if (butRev != null) {
|
if (butRev != null) {
|
||||||
butRev.setOnClickListener(v -> {
|
butRev.setOnClickListener(v -> {
|
||||||
int curr = controller.getPosition();
|
onRewind();
|
||||||
controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
|
|
||||||
});
|
});
|
||||||
butRev.setOnLongClickListener(new View.OnLongClickListener() {
|
butRev.setOnLongClickListener(new View.OnLongClickListener() {
|
||||||
|
|
||||||
@ -800,12 +787,13 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
|
butPlay.setOnClickListener(v -> {
|
||||||
|
onPlayPause();
|
||||||
|
});
|
||||||
|
|
||||||
if (butFF != null) {
|
if (butFF != null) {
|
||||||
butFF.setOnClickListener(v -> {
|
butFF.setOnClickListener(v -> {
|
||||||
int curr = controller.getPosition();
|
onFastForward();
|
||||||
controller.seekTo(curr + UserPreferences.getFastFowardSecs() * 1000);
|
|
||||||
});
|
});
|
||||||
butFF.setOnLongClickListener(new View.OnLongClickListener() {
|
butFF.setOnLongClickListener(new View.OnLongClickListener() {
|
||||||
|
|
||||||
@ -850,6 +838,29 @@ 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();
|
protected abstract int getContentViewResourceId();
|
||||||
|
|
||||||
void handleError(int errorCode) {
|
void handleError(int errorCode) {
|
||||||
@ -882,7 +893,13 @@ public abstract class MediaplayerActivity extends AppCompatActivity implements O
|
|||||||
|
|
||||||
private void updateButPlaybackSpeed() {
|
private void updateButPlaybackSpeed() {
|
||||||
if (controller != null && butPlaybackSpeed != null) {
|
if (controller != null && butPlaybackSpeed != null) {
|
||||||
float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
|
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);
|
String speedStr = String.format("%.2fx", speed);
|
||||||
butPlaybackSpeed.setText(speedStr);
|
butPlaybackSpeed.setText(speedStr);
|
||||||
}
|
}
|
||||||
|
@ -408,18 +408,25 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
|
|||||||
description.setText(feed.getDescription());
|
description.setText(feed.getDescription());
|
||||||
|
|
||||||
subscribeButton.setOnClickListener(v -> {
|
subscribeButton.setOnClickListener(v -> {
|
||||||
try {
|
if(feed != null && feedInFeedlist(feed)) {
|
||||||
|
Intent intent = new Intent(OnlineFeedViewActivity.this, MainActivity.class);
|
||||||
|
// feed.getId() is always 0, we have to retrieve the id from the feed list from
|
||||||
|
// the database
|
||||||
|
intent.putExtra(MainActivity.EXTRA_FEED_ID, getFeedId(feed));
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle());
|
Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle());
|
||||||
f.setPreferences(feed.getPreferences());
|
f.setPreferences(feed.getPreferences());
|
||||||
this.feed = f;
|
this.feed = f;
|
||||||
|
try {
|
||||||
DownloadRequester.getInstance().downloadFeed(this, f);
|
DownloadRequester.getInstance().downloadFeed(this, f);
|
||||||
} catch (DownloadRequestException e) {
|
} catch (DownloadRequestException e) {
|
||||||
e.printStackTrace();
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(OnlineFeedViewActivity.this,
|
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this, e.getMessage());
|
||||||
e.getMessage());
|
}
|
||||||
|
setSubscribeButtonState(feed);
|
||||||
}
|
}
|
||||||
setSubscribeButtonState(feed);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (alternateFeedUrls.isEmpty()) {
|
if (alternateFeedUrls.isEmpty()) {
|
||||||
@ -462,8 +469,8 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
|
|||||||
subscribeButton.setEnabled(false);
|
subscribeButton.setEnabled(false);
|
||||||
subscribeButton.setText(R.string.downloading_label);
|
subscribeButton.setText(R.string.downloading_label);
|
||||||
} else if (feedInFeedlist(feed)) {
|
} else if (feedInFeedlist(feed)) {
|
||||||
subscribeButton.setEnabled(false);
|
subscribeButton.setEnabled(true);
|
||||||
subscribeButton.setText(R.string.subscribed_label);
|
subscribeButton.setText(R.string.open_podcast);
|
||||||
} else {
|
} else {
|
||||||
subscribeButton.setEnabled(true);
|
subscribeButton.setEnabled(true);
|
||||||
subscribeButton.setText(R.string.subscribe_label);
|
subscribeButton.setText(R.string.subscribe_label);
|
||||||
@ -483,6 +490,18 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getFeedId(Feed feed) {
|
||||||
|
if (feeds == null || feed == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (Feed f : feeds) {
|
||||||
|
if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) {
|
||||||
|
return f.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void showErrorDialog(String errorMsg) {
|
private void showErrorDialog(String errorMsg) {
|
||||||
assert(Looper.myLooper() == Looper.getMainLooper()); // run on UI thread
|
assert(Looper.myLooper() == Looper.getMainLooper()); // run on UI thread
|
||||||
if (!isFinishing() && !isPaused) {
|
if (!isFinishing() && !isPaused) {
|
||||||
|
@ -2,23 +2,22 @@ package de.danoeh.antennapod.activity;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.view.MenuItemCompat;
|
|
||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ListView;
|
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.ArrayList;
|
||||||
import java.util.List;
|
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
|
* Displays the feeds that the OPML-Importer has read and lets the user choose
|
||||||
* which feeds he wants to import.
|
* which feeds he wants to import.
|
||||||
@ -33,6 +32,9 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
|
|||||||
private ListView feedlist;
|
private ListView feedlist;
|
||||||
private ArrayAdapter<String> listAdapter;
|
private ArrayAdapter<String> listAdapter;
|
||||||
|
|
||||||
|
private MenuItem selectAll;
|
||||||
|
private MenuItem deselectAll;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
setTheme(UserPreferences.getTheme());
|
setTheme(UserPreferences.getTheme());
|
||||||
@ -44,45 +46,54 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
|
|||||||
feedlist = (ListView) findViewById(R.id.feedlist);
|
feedlist = (ListView) findViewById(R.id.feedlist);
|
||||||
|
|
||||||
feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||||
listAdapter = new ArrayAdapter<String>(this,
|
listAdapter = new ArrayAdapter<>(this,
|
||||||
android.R.layout.simple_list_item_multiple_choice,
|
android.R.layout.simple_list_item_multiple_choice,
|
||||||
getTitleList());
|
getTitleList());
|
||||||
|
|
||||||
feedlist.setAdapter(listAdapter);
|
feedlist.setAdapter(listAdapter);
|
||||||
|
feedlist.setOnItemClickListener((parent, view, position, id) -> {
|
||||||
butCancel.setOnClickListener(new OnClickListener() {
|
SparseBooleanArray checked = feedlist.getCheckedItemPositions();
|
||||||
@Override
|
int checkedCount = 0;
|
||||||
public void onClick(View v) {
|
for (int i = 0; i < checked.size(); i++) {
|
||||||
setResult(RESULT_CANCELED);
|
if (checked.valueAt(i)) {
|
||||||
finish();
|
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
|
butConfirm.setOnClickListener(v -> {
|
||||||
public void onClick(View v) {
|
Intent intent = new Intent();
|
||||||
Intent intent = new Intent();
|
SparseBooleanArray checked = feedlist.getCheckedItemPositions();
|
||||||
SparseBooleanArray checked = feedlist.getCheckedItemPositions();
|
|
||||||
|
|
||||||
int checkedCount = 0;
|
int checkedCount = 0;
|
||||||
// Get number of checked items
|
// Get number of checked items
|
||||||
for (int i = 0; i < checked.size(); i++) {
|
for (int i = 0; i < checked.size(); i++) {
|
||||||
if (checked.valueAt(i)) {
|
if (checked.valueAt(i)) {
|
||||||
checkedCount++;
|
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
intent.putExtra(EXTRA_SELECTED_ITEMS, selection);
|
|
||||||
setResult(RESULT_OK, intent);
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
|
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();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -93,7 +104,6 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
|
|||||||
for (OpmlElement element : OpmlImportHolder.getReadElements()) {
|
for (OpmlElement element : OpmlImportHolder.getReadElements()) {
|
||||||
result.add(element.getText());
|
result.add(element.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -101,13 +111,11 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
super.onCreateOptionsMenu(menu);
|
super.onCreateOptionsMenu(menu);
|
||||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.select_all_item, Menu.NONE,
|
MenuInflater inflater = getMenuInflater();
|
||||||
R.string.select_all_label),
|
inflater.inflate(R.menu.opml_selection_options, menu);
|
||||||
MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
|
selectAll = menu.findItem(R.id.select_all_item);
|
||||||
|
deselectAll = menu.findItem(R.id.deselect_all_item);
|
||||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.deselect_all_item, Menu.NONE,
|
deselectAll.setVisible(false);
|
||||||
R.string.deselect_all_label),
|
|
||||||
MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,10 +123,14 @@ public class OpmlFeedChooserActivity extends ActionBarActivity {
|
|||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.select_all_item:
|
case R.id.select_all_item:
|
||||||
|
selectAll.setVisible(false);
|
||||||
selectAllItems(true);
|
selectAllItems(true);
|
||||||
|
deselectAll.setVisible(true);
|
||||||
return true;
|
return true;
|
||||||
case R.id.deselect_all_item:
|
case R.id.deselect_all_item:
|
||||||
|
deselectAll.setVisible(false);
|
||||||
selectAllItems(false);
|
selectAllItems(false);
|
||||||
|
selectAll.setVisible(true);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,6 +4,7 @@ import android.content.Intent;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -31,7 +32,7 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
|
|||||||
private OpmlImportWorker importWorker;
|
private OpmlImportWorker importWorker;
|
||||||
|
|
||||||
private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
|
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
|
* 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;
|
this.uri = uri;
|
||||||
if(uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
|
if(uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
|
||||||
int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
|
int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||||
@ -127,8 +135,9 @@ public class OpmlImportBaseActivity extends ActionBarActivity {
|
|||||||
importWorker.executeAsync();
|
importWorker.executeAsync();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(TAG, Log.getStackTraceString(e));
|
Log.d(TAG, Log.getStackTraceString(e));
|
||||||
|
String message = getString(R.string.opml_reader_error);
|
||||||
new MaterialDialog.Builder(this)
|
new MaterialDialog.Builder(this)
|
||||||
.content("Cannot open OPML file: " + e.getMessage())
|
.content(message + " " + e.getMessage())
|
||||||
.positiveText(android.R.string.ok)
|
.positiveText(android.R.string.ok)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,24 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||||||
videoControlsShowing = !videoControlsShowing;
|
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() {
|
private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
|
||||||
@Override
|
@Override
|
||||||
@ -312,7 +330,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||||||
|
|
||||||
private static class VideoControlsHider extends Handler {
|
private static class VideoControlsHider extends Handler {
|
||||||
|
|
||||||
private static final int DELAY = 5000;
|
private static final int DELAY = 2500;
|
||||||
|
|
||||||
private WeakReference<VideoplayerActivity> activity;
|
private WeakReference<VideoplayerActivity> activity;
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.joanzapata.iconify.Iconify;
|
import com.joanzapata.iconify.Iconify;
|
||||||
import com.joanzapata.iconify.widget.IconButton;
|
import com.joanzapata.iconify.widget.IconButton;
|
||||||
|
import com.joanzapata.iconify.widget.IconTextView;
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
||||||
@ -48,7 +49,7 @@ public class DownloadLogAdapter extends BaseAdapter {
|
|||||||
LayoutInflater inflater = (LayoutInflater) context
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
|
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.retry = (IconButton) convertView.findViewById(R.id.btnRetry);
|
||||||
holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
|
holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
|
||||||
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
|
||||||
@ -78,14 +79,12 @@ public class DownloadLogAdapter extends BaseAdapter {
|
|||||||
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
|
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
|
||||||
R.color.download_success_green));
|
R.color.download_success_green));
|
||||||
holder.icon.setText("{fa-check-circle}");
|
holder.icon.setText("{fa-check-circle}");
|
||||||
Iconify.addIcons(holder.icon);
|
|
||||||
holder.retry.setVisibility(View.GONE);
|
holder.retry.setVisibility(View.GONE);
|
||||||
holder.reason.setVisibility(View.GONE);
|
holder.reason.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
|
holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(),
|
||||||
R.color.download_failed_red));
|
R.color.download_failed_red));
|
||||||
holder.icon.setText("{fa-times-circle}");
|
holder.icon.setText("{fa-times-circle}");
|
||||||
Iconify.addIcons(holder.icon);
|
|
||||||
String reasonText = status.getReason().getErrorString(context);
|
String reasonText = status.getReason().getErrorString(context);
|
||||||
if (status.getReasonDetailed() != null) {
|
if (status.getReasonDetailed() != null) {
|
||||||
reasonText += ": " + status.getReasonDetailed();
|
reasonText += ": " + status.getReasonDetailed();
|
||||||
@ -160,7 +159,7 @@ public class DownloadLogAdapter extends BaseAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class Holder {
|
static class Holder {
|
||||||
TextView icon;
|
IconTextView icon;
|
||||||
IconButton retry;
|
IconButton retry;
|
||||||
TextView title;
|
TextView title;
|
||||||
TextView type;
|
TextView type;
|
||||||
|
@ -167,7 +167,7 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
|
|||||||
for(int i=0; imageUrl == null && i < images.length(); i++) {
|
for(int i=0; imageUrl == null && i < images.length(); i++) {
|
||||||
JSONObject image = images.getJSONObject(i);
|
JSONObject image = images.getJSONObject(i);
|
||||||
String height = image.getJSONObject("attributes").getString("height");
|
String height = image.getJSONObject("attributes").getString("height");
|
||||||
if(Integer.valueOf(height) >= 100) {
|
if(Integer.parseInt(height) >= 100) {
|
||||||
imageUrl = image.getString("label");
|
imageUrl = image.getString("label");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
323
app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -138,7 +138,7 @@ public abstract class SleepTimerDialog {
|
|||||||
|
|
||||||
private long readTimeMillis() {
|
private long readTimeMillis() {
|
||||||
TimeUnit selectedUnit = units[spTimeUnit.getSelectedItemPosition()];
|
TimeUnit selectedUnit = units[spTimeUnit.getSelectedItemPosition()];
|
||||||
long value = Long.valueOf(etxtTime.getText().toString());
|
long value = Long.parseLong(etxtTime.getText().toString());
|
||||||
return selectedUnit.toMillis(value);
|
return selectedUnit.toMillis(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package de.danoeh.antennapod.fragment;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.ListFragment;
|
import android.support.v4.app.ListFragment;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
@ -15,15 +16,16 @@ import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
|||||||
|
|
||||||
public class ChaptersFragment extends ListFragment implements AudioplayerContentFragment {
|
public class ChaptersFragment extends ListFragment implements AudioplayerContentFragment {
|
||||||
|
|
||||||
|
private static final String TAG = "ChaptersFragment";
|
||||||
|
|
||||||
private Playable media;
|
private Playable media;
|
||||||
private PlaybackController controller;
|
private PlaybackController controller;
|
||||||
|
|
||||||
private ChaptersListAdapter adapter;
|
private ChaptersListAdapter adapter;
|
||||||
|
|
||||||
public static ChaptersFragment newInstance(Playable media, PlaybackController controller) {
|
public static ChaptersFragment newInstance(Playable media) {
|
||||||
ChaptersFragment f = new ChaptersFragment();
|
ChaptersFragment f = new ChaptersFragment();
|
||||||
f.media = media;
|
f.media = media;
|
||||||
f.controller = controller;
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +39,10 @@ public class ChaptersFragment extends ListFragment implements AudioplayerContent
|
|||||||
lv.setPadding(0, vertPadding, 0, vertPadding);
|
lv.setPadding(0, vertPadding, 0, vertPadding);
|
||||||
|
|
||||||
adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
|
adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
|
||||||
|
if(controller == null) {
|
||||||
|
Log.d(TAG, "controller is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Chapter chapter = (Chapter) getListAdapter().getItem(pos);
|
Chapter chapter = (Chapter) getListAdapter().getItem(pos);
|
||||||
controller.seekToChapter(chapter);
|
controller.seekToChapter(chapter);
|
||||||
});
|
});
|
||||||
@ -58,6 +64,7 @@ public class ChaptersFragment extends ListFragment implements AudioplayerContent
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
adapter = null;
|
adapter = null;
|
||||||
|
controller = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -74,4 +81,9 @@ public class ChaptersFragment extends ListFragment implements AudioplayerContent
|
|||||||
setEmptyText(null);
|
setEmptyText(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setController(PlaybackController controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,11 @@ public class ExternalPlayerFragment extends Fragment {
|
|||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
controller = setupPlaybackController();
|
controller = setupPlaybackController();
|
||||||
butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
|
butPlay.setOnClickListener(v -> {
|
||||||
|
if(controller != null) {
|
||||||
|
controller.playPause();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlaybackController setupPlaybackController() {
|
private PlaybackController setupPlaybackController() {
|
||||||
@ -88,7 +92,6 @@ public class ExternalPlayerFragment extends Fragment {
|
|||||||
return butPlay;
|
return butPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean loadMediaInfo() {
|
public boolean loadMediaInfo() {
|
||||||
ExternalPlayerFragment fragment = ExternalPlayerFragment.this;
|
ExternalPlayerFragment fragment = ExternalPlayerFragment.this;
|
||||||
@ -145,8 +148,11 @@ public class ExternalPlayerFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
controller = setupPlaybackController();
|
controller = setupPlaybackController();
|
||||||
if (butPlay != null) {
|
if (butPlay != null) {
|
||||||
butPlay.setOnClickListener(controller
|
butPlay.setOnClickListener(v -> {
|
||||||
.newOnPlayButtonClickListener());
|
if(controller != null) {
|
||||||
|
controller.playPause();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
controller.init();
|
controller.init();
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public class ItemDescriptionFragment extends Fragment implements AudioplayerCont
|
|||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
Log.d(TAG, "Creating view");
|
Log.d(TAG, "Creating view");
|
||||||
webvDescription = new WebView(getActivity());
|
webvDescription = new WebView(getActivity().getApplicationContext());
|
||||||
if (Build.VERSION.SDK_INT >= 11) {
|
if (Build.VERSION.SDK_INT >= 11) {
|
||||||
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,7 @@ public class ItemFragment extends Fragment {
|
|||||||
|
|
||||||
private ViewGroup root;
|
private ViewGroup root;
|
||||||
private WebView webvDescription;
|
private WebView webvDescription;
|
||||||
|
private TextView txtvPodcast;
|
||||||
private TextView txtvTitle;
|
private TextView txtvTitle;
|
||||||
private TextView txtvDuration;
|
private TextView txtvDuration;
|
||||||
private TextView txtvPublished;
|
private TextView txtvPublished;
|
||||||
@ -135,6 +136,7 @@ public class ItemFragment extends Fragment {
|
|||||||
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
|
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
|
||||||
|
|
||||||
root = (ViewGroup) layout.findViewById(R.id.content_root);
|
root = (ViewGroup) layout.findViewById(R.id.content_root);
|
||||||
|
txtvPodcast = (TextView) layout.findViewById(R.id.txtvPodcast);
|
||||||
txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
|
txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
|
||||||
txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
|
txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
|
||||||
txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished);
|
txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished);
|
||||||
@ -219,6 +221,7 @@ public class ItemFragment extends Fragment {
|
|||||||
EventDistributor.getInstance().register(contentUpdate);
|
EventDistributor.getInstance().register(contentUpdate);
|
||||||
EventBus.getDefault().registerSticky(this);
|
EventBus.getDefault().registerSticky(this);
|
||||||
if(itemsLoaded) {
|
if(itemsLoaded) {
|
||||||
|
progbarLoading.setVisibility(View.GONE);
|
||||||
updateAppearance();
|
updateAppearance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,6 +298,7 @@ public class ItemFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getActivity().supportInvalidateOptionsMenu();
|
getActivity().supportInvalidateOptionsMenu();
|
||||||
|
txtvPodcast.setText(item.getFeed().getTitle());
|
||||||
txtvTitle.setText(item.getTitle());
|
txtvTitle.setText(item.getTitle());
|
||||||
|
|
||||||
if (item.getPubDate() != null) {
|
if (item.getPubDate() != null) {
|
||||||
|
@ -52,12 +52,14 @@ import de.danoeh.antennapod.activity.PreferenceActivityGingerbread;
|
|||||||
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
|
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
|
||||||
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
|
import de.danoeh.antennapod.core.service.GpodnetSyncService;
|
||||||
import de.danoeh.antennapod.core.util.Converter;
|
import de.danoeh.antennapod.core.util.Converter;
|
||||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||||
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
|
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
|
||||||
import de.danoeh.antennapod.dialog.AuthenticationDialog;
|
import de.danoeh.antennapod.dialog.AuthenticationDialog;
|
||||||
import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
|
import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
|
||||||
import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
|
import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
|
||||||
|
import de.danoeh.antennapod.dialog.ProxyDialog;
|
||||||
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
|
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,9 +81,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
public static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
|
public static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
|
||||||
public static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate";
|
public static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate";
|
||||||
public static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
|
public static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
|
||||||
|
public static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync";
|
||||||
public static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
|
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_GPODNET_HOSTNAME = "pref_gpodnet_hostname";
|
||||||
public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
|
public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
|
||||||
|
public static final String PREF_PROXY = "prefProxy";
|
||||||
|
|
||||||
private final PreferenceUI ui;
|
private final PreferenceUI ui;
|
||||||
|
|
||||||
@ -241,7 +245,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
(preference, o) -> {
|
(preference, o) -> {
|
||||||
if (o instanceof String) {
|
if (o instanceof String) {
|
||||||
try {
|
try {
|
||||||
int value = Integer.valueOf((String) o);
|
int value = Integer.parseInt((String) o);
|
||||||
if (1 <= value && value <= 50) {
|
if (1 <= value && value <= 50) {
|
||||||
setParallelDownloadsText(value);
|
setParallelDownloadsText(value);
|
||||||
return true;
|
return true;
|
||||||
@ -268,7 +272,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
if (s.length() > 0) {
|
if (s.length() > 0) {
|
||||||
try {
|
try {
|
||||||
int value = Integer.valueOf(s.toString());
|
int value = Integer.parseInt(s.toString());
|
||||||
if (value <= 0) {
|
if (value <= 0) {
|
||||||
ev.setText("1");
|
ev.setText("1");
|
||||||
} else if (value > 50) {
|
} else if (value > 50) {
|
||||||
@ -309,6 +313,14 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
dialog.show();
|
dialog.show();
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).
|
||||||
|
setOnPreferenceClickListener(preference -> {
|
||||||
|
GpodnetSyncService.sendSyncIntent(ui.getActivity().getApplicationContext());
|
||||||
|
Toast toast = Toast.makeText(ui.getActivity(), R.string.pref_gpodnet_sync_started,
|
||||||
|
Toast.LENGTH_SHORT);
|
||||||
|
toast.show();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
|
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(
|
||||||
preference -> {
|
preference -> {
|
||||||
GpodnetPreferences.logout();
|
GpodnetPreferences.logout();
|
||||||
@ -343,7 +355,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
|
ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
|
||||||
(preference, o) -> {
|
(preference, o) -> {
|
||||||
if (o instanceof String) {
|
if (o instanceof String) {
|
||||||
int newValue = Integer.valueOf((String) o) * 1024 * 1024;
|
int newValue = Integer.parseInt((String) o) * 1024 * 1024;
|
||||||
if (newValue != UserPreferences.getImageCacheSize()) {
|
if (newValue != UserPreferences.getImageCacheSize()) {
|
||||||
AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
|
AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
|
||||||
dialog.setTitle(android.R.string.dialog_alert_title);
|
dialog.setTitle(android.R.string.dialog_alert_title);
|
||||||
@ -356,6 +368,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
|
||||||
|
ProxyDialog dialog = new ProxyDialog(ui.getActivity());
|
||||||
|
dialog.createDialog().show();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> {
|
ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> {
|
||||||
Intent emailIntent = new Intent(Intent.ACTION_SEND);
|
Intent emailIntent = new Intent(Intent.ACTION_SEND);
|
||||||
emailIntent.setType("text/plain");
|
emailIntent.setType("text/plain");
|
||||||
@ -423,6 +440,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
final boolean loggedIn = GpodnetPreferences.loggedIn();
|
final boolean loggedIn = GpodnetPreferences.loggedIn();
|
||||||
ui.findPreference(PreferenceController.PREF_GPODNET_LOGIN).setEnabled(!loggedIn);
|
ui.findPreference(PreferenceController.PREF_GPODNET_LOGIN).setEnabled(!loggedIn);
|
||||||
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn);
|
ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setEnabled(loggedIn);
|
||||||
|
ui.findPreference(PreferenceController.PREF_GPODNET_SYNC).setEnabled(loggedIn);
|
||||||
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setEnabled(loggedIn);
|
ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setEnabled(loggedIn);
|
||||||
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
|
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
|
||||||
}
|
}
|
||||||
@ -781,7 +799,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||||||
checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
|
checkedItem = ArrayUtils.indexOf(values, currIntervalStr);
|
||||||
}
|
}
|
||||||
builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
|
builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> {
|
||||||
int hours = Integer.valueOf(values[which1]);
|
int hours = Integer.parseInt(values[which1]);
|
||||||
UserPreferences.setUpdateInterval(hours);
|
UserPreferences.setUpdateInterval(hours);
|
||||||
dialog1.dismiss();
|
dialog1.dismiss();
|
||||||
setUpdateIntervalText();
|
setUpdateIntervalText();
|
||||||
|
@ -8,6 +8,7 @@ import android.net.NetworkInfo;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||||
@ -20,7 +21,8 @@ public class ConnectivityActionReceiver extends BroadcastReceiver {
|
|||||||
if (TextUtils.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) {
|
if (TextUtils.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) {
|
||||||
Log.d(TAG, "Received intent");
|
Log.d(TAG, "Received intent");
|
||||||
|
|
||||||
if (NetworkUtils.autodownloadNetworkAvailable()) {
|
ClientConfig.initialize(context);
|
||||||
|
if (NetworkUtils.autodownloadNetworkAvailable()) {
|
||||||
Log.d(TAG, "auto-dl network available, starting auto-download");
|
Log.d(TAG, "auto-dl network available, starting auto-download");
|
||||||
DBTasks.autodownloadUndownloadedItems(context);
|
DBTasks.autodownloadUndownloadedItems(context);
|
||||||
} else { // if new network is Wi-Fi, finish ongoing downloads,
|
} else { // if new network is Wi-Fi, finish ongoing downloads,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package de.danoeh.antennapod.receiver;
|
package de.danoeh.antennapod.receiver;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.appwidget.AppWidgetProvider;
|
import android.appwidget.AppWidgetProvider;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -44,7 +46,7 @@ public class PlayerWidget extends AppWidgetProvider {
|
|||||||
@Override
|
@Override
|
||||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
|
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
|
||||||
int[] appWidgetIds) {
|
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);
|
startUpdate(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,10 +3,9 @@ package de.danoeh.antennapod.receiver;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.BatteryManager;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import de.danoeh.antennapod.core.BuildConfig;
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||||
@ -25,6 +24,7 @@ public class PowerConnectionReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
Log.d(TAG, "charging intent: " + action);
|
Log.d(TAG, "charging intent: " + action);
|
||||||
|
|
||||||
|
ClientConfig.initialize(context);
|
||||||
if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
|
if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
|
||||||
Log.d(TAG, "charging, starting auto-download");
|
Log.d(TAG, "charging, starting auto-download");
|
||||||
// we're plugged in, this is a great time to auto-download if everything else is
|
// we're plugged in, this is a great time to auto-download if everything else is
|
||||||
|
@ -9,8 +9,8 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import de.danoeh.antennapod.BuildConfig;
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.feed.Feed;
|
import de.danoeh.antennapod.core.feed.Feed;
|
||||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||||
@ -27,29 +27,30 @@ public class SPAReceiver extends BroadcastReceiver{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (TextUtils.equals(intent.getAction(), ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) {
|
if (!TextUtils.equals(intent.getAction(), ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) {
|
||||||
if (BuildConfig.DEBUG) Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE");
|
return;
|
||||||
if (intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) {
|
}
|
||||||
String[] feedUrls = intent.getStringArrayExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA);
|
Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE");
|
||||||
if (feedUrls != null) {
|
if (!intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) {
|
||||||
if (BuildConfig.DEBUG) Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls));
|
Log.e(TAG, "Received invalid SP_APPS_QUERY_RESPONSE: Contains no extra");
|
||||||
for (String url : feedUrls) {
|
return;
|
||||||
Feed f = new Feed(url, null);
|
}
|
||||||
try {
|
String[] feedUrls = intent.getStringArrayExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA);
|
||||||
DownloadRequester.getInstance().downloadFeed(context, f);
|
if (feedUrls == null) {
|
||||||
} catch (DownloadRequestException e) {
|
Log.e(TAG, "Received invalid SP_APPS_QUERY_REPSONSE: extra was null");
|
||||||
Log.e(TAG, "Error while trying to add feed " + url);
|
return;
|
||||||
e.printStackTrace();
|
}
|
||||||
}
|
Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls));
|
||||||
}
|
ClientConfig.initialize(context);
|
||||||
Toast.makeText(context, R.string.sp_apps_importing_feeds_msg, Toast.LENGTH_LONG).show();
|
for (String url : feedUrls) {
|
||||||
|
Feed f = new Feed(url, null);
|
||||||
} else {
|
try {
|
||||||
Log.e(TAG, "Received invalid SP_APPS_QUERY_REPSONSE: extra was null");
|
DownloadRequester.getInstance().downloadFeed(context, f);
|
||||||
}
|
} catch (DownloadRequestException e) {
|
||||||
} else {
|
Log.e(TAG, "Error while trying to add feed " + url);
|
||||||
Log.e(TAG, "Received invalid SP_APPS_QUERY_RESPONSE: Contains no extra");
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Toast.makeText(context, R.string.sp_apps_importing_feeds_msg, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,14 +10,13 @@
|
|||||||
android:paddingBottom="8dp"
|
android:paddingBottom="8dp"
|
||||||
tools:background="@android:color/darker_gray">
|
tools:background="@android:color/darker_gray">
|
||||||
|
|
||||||
<TextView
|
<com.joanzapata.iconify.widget.IconTextView
|
||||||
android:id="@+id/txtvIcon"
|
android:id="@+id/txtvIcon"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:textSize="48sp"
|
android:textSize="48sp"
|
||||||
tools:text="[Icon]"
|
|
||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
|
|
||||||
<com.joanzapata.iconify.widget.IconButton
|
<com.joanzapata.iconify.widget.IconButton
|
||||||
|
@ -31,24 +31,34 @@
|
|||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
android:contentDescription="@string/cover_label"
|
android:contentDescription="@string/cover_label"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
tools:src="@drawable/ic_stat_antenna_default"
|
tools:src="@drawable/ic_stat_antenna_default"
|
||||||
tools:background="@android:color/holo_green_dark" />
|
tools:background="@android:color/holo_green_dark" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/txtvPodcast"
|
||||||
|
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignTop="@id/imgvCover"
|
||||||
|
android:layout_toRightOf="@id/imgvCover"
|
||||||
|
tools:text="Podcast title"
|
||||||
|
tools:background="@android:color/holo_green_dark" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/txtvTitle"
|
android:id="@+id/txtvTitle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="16dp"
|
android:layout_below="@id/txtvPodcast"
|
||||||
android:layout_alignTop="@id/imgvCover"
|
|
||||||
android:layout_toRightOf="@id/imgvCover"
|
android:layout_toRightOf="@id/imgvCover"
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="5"
|
android:maxLines="5"
|
||||||
tools:text="Podcast title"
|
tools:text="Episode title"
|
||||||
tools:background="@android:color/holo_green_dark" />
|
tools:background="@android:color/holo_green_dark" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -58,7 +68,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_toRightOf="@id/imgvCover"
|
android:layout_toRightOf="@id/imgvCover"
|
||||||
android:layout_below="@id/txtvTitle"
|
android:layout_below="@id/txtvTitle"
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
tools:text="00:42:23"
|
tools:text="00:42:23"
|
||||||
tools:background="@android:color/holo_green_dark"/>
|
tools:background="@android:color/holo_green_dark"/>
|
||||||
|
|
||||||
@ -70,7 +79,7 @@
|
|||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_below="@id/txtvTitle"
|
android:layout_below="@id/txtvTitle"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
tools:text="Jan\n23"
|
tools:text="Jan 23"
|
||||||
tools:background="@android:color/holo_green_dark" />
|
tools:background="@android:color/holo_green_dark" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
90
app/src/main/res/layout/proxy_settings.xml
Normal file
@ -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>
|
19
app/src/main/res/menu/opml_selection_options.xml
Normal file
@ -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>
|
@ -200,8 +200,11 @@
|
|||||||
android:key="prefEnableAutoDownloadWifiFilter"
|
android:key="prefEnableAutoDownloadWifiFilter"
|
||||||
android:title="@string/pref_autodl_wifi_filter_title"
|
android:title="@string/pref_autodl_wifi_filter_title"
|
||||||
android:summary="@string/pref_autodl_wifi_filter_sum"/>
|
android:summary="@string/pref_autodl_wifi_filter_sum"/>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
<Preference
|
||||||
|
android:key="prefProxy"
|
||||||
|
android:summary="@string/pref_proxy_sum"
|
||||||
|
android:title="@string/pref_proxy_title" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
@ -239,6 +242,10 @@
|
|||||||
android:key="pref_gpodnet_setlogin_information"
|
android:key="pref_gpodnet_setlogin_information"
|
||||||
android:title="@string/pref_gpodnet_setlogin_information_title"
|
android:title="@string/pref_gpodnet_setlogin_information_title"
|
||||||
android:summary="@string/pref_gpodnet_setlogin_information_sum"/>
|
android:summary="@string/pref_gpodnet_setlogin_information_sum"/>
|
||||||
|
<Preference
|
||||||
|
android:key="pref_gpodnet_sync"
|
||||||
|
android:title="@string/pref_gpodnet_sync_title"
|
||||||
|
android:summary="@string/pref_gpodnet_sync_sum"/>
|
||||||
<Preference
|
<Preference
|
||||||
android:key="pref_gpodnet_logout"
|
android:key="pref_gpodnet_logout"
|
||||||
android:title="@string/pref_gpodnet_logout_title"/>
|
android:title="@string/pref_gpodnet_logout_title"/>
|
||||||
|
10
build.gradle
@ -41,18 +41,20 @@ project.ext {
|
|||||||
minSdkVersion = 10
|
minSdkVersion = 10
|
||||||
targetSdkVersion = 23
|
targetSdkVersion = 23
|
||||||
|
|
||||||
supportVersion = "23.2.0"
|
supportVersion = "23.2.1"
|
||||||
commonsioVersion = "2.4"
|
commonsioVersion = "2.4"
|
||||||
commonslangVersion = "3.4"
|
commonslangVersion = "3.4"
|
||||||
eventbusVersion = "2.4.0"
|
eventbusVersion = "2.4.0"
|
||||||
flattr4jVersion = "2.12"
|
flattr4jVersion = "2.12"
|
||||||
glideVersion = "3.6.1"
|
glideVersion = "3.7.0"
|
||||||
iconifyVersion = "2.1.1"
|
glideOkhttpIntegrationVersion = "1.4.0"
|
||||||
|
iconifyVersion = "2.2.1"
|
||||||
jsoupVersion = "1.7.3"
|
jsoupVersion = "1.7.3"
|
||||||
materialDialogsVersion = "0.8.5.6@aar"
|
materialDialogsVersion = "0.8.5.6@aar"
|
||||||
okhttpVersion = "2.7.4"
|
okhttpVersion = "2.7.5"
|
||||||
okioVersion = "1.6.0"
|
okioVersion = "1.6.0"
|
||||||
recyclerviewFlexibledividerVersion = "1.2.6"
|
recyclerviewFlexibledividerVersion = "1.2.6"
|
||||||
|
robotiumSoloVersion = "5.5.3"
|
||||||
rxAndroidVersion = "1.1.0"
|
rxAndroidVersion = "1.1.0"
|
||||||
rxJavaVersion = "1.1.0"
|
rxJavaVersion = "1.1.0"
|
||||||
rxJavaRulesVersion = "1.1.0.0"
|
rxJavaRulesVersion = "1.1.0.0"
|
||||||
|
@ -9,7 +9,7 @@ dependencies:
|
|||||||
- ~/.android
|
- ~/.android
|
||||||
- ~/android
|
- ~/android
|
||||||
pre:
|
pre:
|
||||||
- echo y | android update sdk --no-ui --all --filter "tools,platform-tools,android-23"
|
- echo y | android update sdk --no-ui --all --filter "tool,extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository,android-23"
|
||||||
- echo y | android update sdk --no-ui --all --filter "build-tools-23.0.2"
|
- echo y | android update sdk --no-ui --all --filter "build-tools-23.0.2"
|
||||||
override:
|
override:
|
||||||
- echo override dependencies
|
- echo override dependencies
|
||||||
|
@ -45,10 +45,10 @@ dependencies {
|
|||||||
exclude group: "org.json", module: "json"
|
exclude group: "org.json", module: "json"
|
||||||
}
|
}
|
||||||
compile "commons-io:commons-io:$commonsioVersion"
|
compile "commons-io:commons-io:$commonsioVersion"
|
||||||
compile "com.jayway.android.robotium:robotium-solo:5.5.3"
|
compile "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion"
|
||||||
compile "org.jsoup:jsoup:$jsoupVersion"
|
compile "org.jsoup:jsoup:$jsoupVersion"
|
||||||
compile "com.github.bumptech.glide:glide:$glideVersion"
|
compile "com.github.bumptech.glide:glide:$glideVersion"
|
||||||
compile "com.github.bumptech.glide:okhttp-integration:1.3.1"
|
compile "com.github.bumptech.glide:okhttp-integration:$glideOkhttpIntegrationVersion"
|
||||||
compile "com.squareup.okhttp:okhttp:$okhttpVersion"
|
compile "com.squareup.okhttp:okhttp:$okhttpVersion"
|
||||||
compile "com.squareup.okhttp:okhttp-urlconnection:$okhttpVersion"
|
compile "com.squareup.okhttp:okhttp-urlconnection:$okhttpVersion"
|
||||||
compile "com.squareup.okio:okio:$okioVersion"
|
compile "com.squareup.okio:okio:$okioVersion"
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
package de.danoeh.antennapod.core;
|
package de.danoeh.antennapod.core;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||||
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
|
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||||
|
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores callbacks for core classes like Services, DB classes etc. and other configuration variables.
|
* Stores callbacks for core classes like Services, DB classes etc. and other configuration variables.
|
||||||
* Apps using the core module of AntennaPod should register implementations of all interfaces here.
|
* Apps using the core module of AntennaPod should register implementations of all interfaces here.
|
||||||
@ -22,4 +29,19 @@ public class ClientConfig {
|
|||||||
public static FlattrCallbacks flattrCallbacks;
|
public static FlattrCallbacks flattrCallbacks;
|
||||||
|
|
||||||
public static DBTasksCallbacks dbTasksCallbacks;
|
public static DBTasksCallbacks dbTasksCallbacks;
|
||||||
|
|
||||||
|
private static boolean initialized = false;
|
||||||
|
|
||||||
|
public static synchronized void initialize(Context context) {
|
||||||
|
if(initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PodDBAdapter.init(context);
|
||||||
|
UserPreferences.init(context);
|
||||||
|
UpdateManager.init(context);
|
||||||
|
PlaybackPreferences.init(context);
|
||||||
|
NetworkUtils.init(context);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package de.danoeh.antennapod;
|
package de.danoeh.antennapod.core;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
@ -17,6 +17,7 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import de.danoeh.antennapod.core.BuildConfig;
|
import de.danoeh.antennapod.core.BuildConfig;
|
||||||
import de.danoeh.antennapod.core.ClientConfig;
|
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}
|
public static enum ExitCode {EXIT_NORMAL, NO_TOKEN, NO_NETWORK, NO_THINGS}
|
||||||
|
|
||||||
private volatile int countFailed = 0;
|
private final AtomicInteger countFailed = new AtomicInteger();
|
||||||
private volatile int countSuccess = 0;
|
private final AtomicInteger countSuccess = new AtomicInteger();
|
||||||
|
|
||||||
private volatile FlattrThing extraFlattrThing;
|
private volatile FlattrThing extraFlattrThing;
|
||||||
|
|
||||||
@ -114,12 +115,12 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
|
|||||||
FlattrUtils.clickUrl(context, thing.getPaymentLink());
|
FlattrUtils.clickUrl(context, thing.getPaymentLink());
|
||||||
thing.getFlattrStatus().setFlattred();
|
thing.getFlattrStatus().setFlattred();
|
||||||
publishProgress(R.string.flattr_click_success);
|
publishProgress(R.string.flattr_click_success);
|
||||||
countSuccess++;
|
countSuccess.incrementAndGet();
|
||||||
|
|
||||||
} catch (FlattrException e) {
|
} catch (FlattrException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
countFailed++;
|
int failed = countFailed.incrementAndGet();
|
||||||
if (countFailed == 1) {
|
if (failed == 1) {
|
||||||
exception = e;
|
exception = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +149,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
|
|||||||
super.onPostExecute(exitCode);
|
super.onPostExecute(exitCode);
|
||||||
switch (exitCode) {
|
switch (exitCode) {
|
||||||
case EXIT_NORMAL:
|
case EXIT_NORMAL:
|
||||||
if (countFailed > 0) {
|
if (countFailed.get() > 0) {
|
||||||
postFlattrFailedNotification();
|
postFlattrFailedNotification();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -190,7 +191,8 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void postFlattrFailedNotification() {
|
private void postFlattrFailedNotification() {
|
||||||
if (countFailed == 0) {
|
int failed = countFailed.get();
|
||||||
|
if (failed == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,15 +200,15 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
|
|||||||
String title;
|
String title;
|
||||||
String subtext;
|
String subtext;
|
||||||
|
|
||||||
if (countFailed == 1) {
|
if (failed == 1) {
|
||||||
title = context.getString(R.string.flattrd_failed_label);
|
title = context.getString(R.string.flattrd_failed_label);
|
||||||
String exceptionMsg = (exception.getMessage() != null) ? exception.getMessage() : "";
|
String exceptionMsg = (exception.getMessage() != null) ? exception.getMessage() : "";
|
||||||
subtext = context.getString(R.string.flattr_click_failure, extraFlattrThing.getTitle())
|
subtext = context.getString(R.string.flattr_click_failure, extraFlattrThing.getTitle())
|
||||||
+ "\n" + exceptionMsg;
|
+ "\n" + exceptionMsg;
|
||||||
} else {
|
} else {
|
||||||
title = context.getString(R.string.flattrd_label);
|
title = context.getString(R.string.flattrd_label);
|
||||||
subtext = context.getString(R.string.flattr_click_success_count, countSuccess) + "\n"
|
subtext = context.getString(R.string.flattr_click_success_count, countSuccess.get()) + "\n"
|
||||||
+ context.getString(R.string.flattr_click_failure_count, countFailed);
|
+ context.getString(R.string.flattr_click_failure_count, failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification notification = new NotificationCompat.Builder(context)
|
Notification notification = new NotificationCompat.Builder(context)
|
||||||
|
@ -63,10 +63,10 @@ public class GpodnetEpisodeAction {
|
|||||||
Action action = Action.valueOf(fields[3]);
|
Action action = Action.valueOf(fields[3]);
|
||||||
GpodnetEpisodeAction result = new Builder(podcast, episode, action)
|
GpodnetEpisodeAction result = new Builder(podcast, episode, action)
|
||||||
.deviceId(deviceId)
|
.deviceId(deviceId)
|
||||||
.timestamp(new Date(Long.valueOf(fields[4])))
|
.timestamp(new Date(Long.parseLong(fields[4])))
|
||||||
.started(Integer.valueOf(fields[5]))
|
.started(Integer.parseInt(fields[5]))
|
||||||
.position(Integer.valueOf(fields[6]))
|
.position(Integer.parseInt(fields[6]))
|
||||||
.total(Integer.valueOf(fields[7]))
|
.total(Integer.parseInt(fields[7]))
|
||||||
.build();
|
.build();
|
||||||
return result;
|
return result;
|
||||||
} catch(IllegalArgumentException e) {
|
} catch(IllegalArgumentException e) {
|
||||||
|
@ -17,6 +17,7 @@ import org.json.JSONException;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.Proxy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -25,10 +26,12 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import de.danoeh.antennapod.core.R;
|
import de.danoeh.antennapod.core.R;
|
||||||
import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver;
|
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.APCleanupAlgorithm;
|
||||||
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
||||||
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
||||||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
|
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
|
||||||
|
import de.danoeh.antennapod.core.util.Converter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to preferences set by the user in the settings screen. A
|
* Provides access to preferences set by the user in the settings screen. A
|
||||||
@ -78,6 +81,11 @@ public class UserPreferences {
|
|||||||
public static final String PREF_ENABLE_AUTODL_ON_BATTERY = "prefEnableAutoDownloadOnBattery";
|
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_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter";
|
||||||
public static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks";
|
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
|
// Services
|
||||||
public static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
|
public static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
|
||||||
@ -158,12 +166,12 @@ public class UserPreferences {
|
|||||||
|
|
||||||
public static int getFeedOrder() {
|
public static int getFeedOrder() {
|
||||||
String value = prefs.getString(PREF_DRAWER_FEED_ORDER, "0");
|
String value = prefs.getString(PREF_DRAWER_FEED_ORDER, "0");
|
||||||
return Integer.valueOf(value);
|
return Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getFeedCounterSetting() {
|
public static int getFeedCounterSetting() {
|
||||||
String value = prefs.getString(PREF_DRAWER_FEED_COUNTER, "0");
|
String value = prefs.getString(PREF_DRAWER_FEED_COUNTER, "0");
|
||||||
return Integer.valueOf(value);
|
return Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -243,7 +251,7 @@ public class UserPreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int getSmartMarkAsPlayedSecs() {
|
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() {
|
public static boolean isAutoFlattr() {
|
||||||
@ -260,20 +268,20 @@ public class UserPreferences {
|
|||||||
|
|
||||||
public static float getLeftVolume() {
|
public static float getLeftVolume() {
|
||||||
int volume = prefs.getInt(PREF_LEFT_VOLUME, 100);
|
int volume = prefs.getInt(PREF_LEFT_VOLUME, 100);
|
||||||
if(volume == 100) {
|
return Converter.getVolumeFromPercentage(volume);
|
||||||
return 1.0f;
|
|
||||||
} else {
|
|
||||||
return (float) (1 - (Math.log(100 - volume) / Math.log(100)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float getRightVolume() {
|
public static float getRightVolume() {
|
||||||
int volume = prefs.getInt(PREF_RIGHT_VOLUME, 100);
|
int volume = prefs.getInt(PREF_RIGHT_VOLUME, 100);
|
||||||
if(volume == 100) {
|
return Converter.getVolumeFromPercentage(volume);
|
||||||
return 1.0f;
|
}
|
||||||
} else {
|
|
||||||
return (float) (1 - (Math.log(100 - volume) / Math.log(100)));
|
public static int getLeftVolumePercentage() {
|
||||||
}
|
return prefs.getInt(PREF_LEFT_VOLUME, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getRightVolumePercentage() {
|
||||||
|
return prefs.getInt(PREF_RIGHT_VOLUME, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldPauseForFocusLoss() {
|
public static boolean shouldPauseForFocusLoss() {
|
||||||
@ -295,8 +303,8 @@ public class UserPreferences {
|
|||||||
String datetime = prefs.getString(PREF_UPDATE_INTERVAL, "");
|
String datetime = prefs.getString(PREF_UPDATE_INTERVAL, "");
|
||||||
if(datetime.length() >= 3 && datetime.contains(":")) {
|
if(datetime.length() >= 3 && datetime.contains(":")) {
|
||||||
String[] parts = datetime.split(":");
|
String[] parts = datetime.split(":");
|
||||||
int hourOfDay = Integer.valueOf(parts[0]);
|
int hourOfDay = Integer.parseInt(parts[0]);
|
||||||
int minute = Integer.valueOf(parts[1]);
|
int minute = Integer.parseInt(parts[1]);
|
||||||
return new int[] { hourOfDay, minute };
|
return new int[] { hourOfDay, minute };
|
||||||
} else {
|
} else {
|
||||||
return new int[0];
|
return new int[0];
|
||||||
@ -308,7 +316,7 @@ public class UserPreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int getParallelDownloads() {
|
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() {
|
public static int getEpisodeCacheSizeUnlimited() {
|
||||||
@ -338,12 +346,12 @@ public class UserPreferences {
|
|||||||
|
|
||||||
public static int getImageCacheSize() {
|
public static int getImageCacheSize() {
|
||||||
String cacheSizeString = prefs.getString(PREF_IMAGE_CACHE_SIZE, IMAGE_CACHE_DEFAULT_VALUE);
|
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
|
// 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.
|
// that's bad, force it back to the default.
|
||||||
if (cacheSizeInt < IMAGE_CACHE_SIZE_MINIMUM) {
|
if (cacheSizeInt < IMAGE_CACHE_SIZE_MINIMUM) {
|
||||||
prefs.edit().putString(PREF_IMAGE_CACHE_SIZE, IMAGE_CACHE_DEFAULT_VALUE).apply();
|
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;
|
int cacheSizeMB = cacheSizeInt * 1024 * 1024;
|
||||||
return cacheSizeMB;
|
return cacheSizeMB;
|
||||||
@ -371,6 +379,42 @@ public class UserPreferences {
|
|||||||
return TextUtils.split(selectedNetWorks, ",");
|
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() {
|
public static boolean shouldResumeAfterCall() {
|
||||||
return prefs.getBoolean(PREF_RESUME_AFTER_CALL, true);
|
return prefs.getBoolean(PREF_RESUME_AFTER_CALL, true);
|
||||||
}
|
}
|
||||||
@ -494,7 +538,7 @@ public class UserPreferences {
|
|||||||
if (valueFromPrefs.equals(context.getString(R.string.pref_episode_cache_unlimited))) {
|
if (valueFromPrefs.equals(context.getString(R.string.pref_episode_cache_unlimited))) {
|
||||||
return EPISODE_CACHE_SIZE_UNLIMITED;
|
return EPISODE_CACHE_SIZE_UNLIMITED;
|
||||||
} else {
|
} else {
|
||||||
return Integer.valueOf(valueFromPrefs);
|
return Integer.parseInt(valueFromPrefs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,15 +546,7 @@ public class UserPreferences {
|
|||||||
String[] selectedSpeeds = null;
|
String[] selectedSpeeds = null;
|
||||||
// If this preference hasn't been set yet, return the default options
|
// If this preference hasn't been set yet, return the default options
|
||||||
if (valueFromPrefs == null) {
|
if (valueFromPrefs == null) {
|
||||||
String[] allSpeeds = context.getResources().getStringArray(R.array.playback_speed_values);
|
selectedSpeeds = new String[] { "1.00", "1.25", "1.50", "1.75", "2.00" };
|
||||||
List<String> speedList = new ArrayList<>();
|
|
||||||
for (String speedStr : allSpeeds) {
|
|
||||||
float speed = Float.parseFloat(speedStr);
|
|
||||||
if (speed < 2.0001 && speed * 10 % 1 == 0) {
|
|
||||||
speedList.add(speedStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selectedSpeeds = speedList.toArray(new String[speedList.size()]);
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
JSONArray jsonArray = new JSONArray(valueFromPrefs);
|
JSONArray jsonArray = new JSONArray(valueFromPrefs);
|
||||||
@ -548,7 +584,7 @@ public class UserPreferences {
|
|||||||
|
|
||||||
|
|
||||||
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
|
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) {
|
if (cleanupValue == EPISODE_CLEANUP_QUEUE) {
|
||||||
return new APQueueCleanupAlgorithm();
|
return new APQueueCleanupAlgorithm();
|
||||||
} else if (cleanupValue == EPISODE_CLEANUP_NULL) {
|
} else if (cleanupValue == EPISODE_CLEANUP_NULL) {
|
||||||
|
@ -6,7 +6,7 @@ import android.content.Intent;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
|
|
||||||
/** Listens for events that make it necessary to reset the update alarm. */
|
/** Listens for events that make it necessary to reset the update alarm. */
|
||||||
@ -22,8 +22,7 @@ public class AlarmUpdateReceiver extends BroadcastReceiver {
|
|||||||
} else if (TextUtils.equals(intent.getAction(), Intent.ACTION_PACKAGE_REPLACED)) {
|
} else if (TextUtils.equals(intent.getAction(), Intent.ACTION_PACKAGE_REPLACED)) {
|
||||||
Log.d(TAG, "Resetting update alarm after app upgrade");
|
Log.d(TAG, "Resetting update alarm after app upgrade");
|
||||||
}
|
}
|
||||||
PlaybackPreferences.init(context);
|
ClientConfig.initialize(context);
|
||||||
UserPreferences.init(context);
|
|
||||||
UserPreferences.restartUpdateAlarm(false);
|
UserPreferences.restartUpdateAlarm(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||||
@ -19,6 +20,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Log.d(TAG, "Received intent");
|
Log.d(TAG, "Received intent");
|
||||||
|
ClientConfig.initialize(context);
|
||||||
if (NetworkUtils.isDownloadAllowed()) {
|
if (NetworkUtils.isDownloadAllowed()) {
|
||||||
DBTasks.refreshAllFeeds(context, null);
|
DBTasks.refreshAllFeeds(context, null);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,7 +5,8 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import de.danoeh.antennapod.core.BuildConfig;
|
|
||||||
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||||
|
|
||||||
/** Receives media button events. */
|
/** Receives media button events. */
|
||||||
@ -17,10 +18,10 @@ public class MediaButtonReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (BuildConfig.DEBUG) Log.d(TAG, "Received intent");
|
Log.d(TAG, "Received intent");
|
||||||
KeyEvent event = (KeyEvent) intent.getExtras().get(
|
KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
|
||||||
Intent.EXTRA_KEY_EVENT);
|
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
|
ClientConfig.initialize(context);
|
||||||
Intent serviceIntent = new Intent(context, PlaybackService.class);
|
Intent serviceIntent = new Intent(context, PlaybackService.class);
|
||||||
int keycode = event.getKeyCode();
|
int keycode = event.getKeyCode();
|
||||||
serviceIntent.putExtra(EXTRA_KEYCODE, keycode);
|
serviceIntent.putExtra(EXTRA_KEYCODE, keycode);
|
||||||
|
@ -2,8 +2,10 @@ package de.danoeh.antennapod.core.service.download;
|
|||||||
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.squareup.okhttp.Credentials;
|
||||||
import com.squareup.okhttp.OkHttpClient;
|
import com.squareup.okhttp.OkHttpClient;
|
||||||
import com.squareup.okhttp.Request;
|
import com.squareup.okhttp.Request;
|
||||||
import com.squareup.okhttp.Response;
|
import com.squareup.okhttp.Response;
|
||||||
@ -14,7 +16,10 @@ import java.net.CookieManager;
|
|||||||
import java.net.CookiePolicy;
|
import java.net.CookiePolicy;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Proxy;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -23,6 +28,7 @@ import javax.net.ssl.SSLContext;
|
|||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,12 +50,15 @@ public class AntennapodHttpClient {
|
|||||||
*/
|
*/
|
||||||
public static synchronized OkHttpClient getHttpClient() {
|
public static synchronized OkHttpClient getHttpClient() {
|
||||||
if (httpClient == null) {
|
if (httpClient == null) {
|
||||||
|
|
||||||
httpClient = newHttpClient();
|
httpClient = newHttpClient();
|
||||||
}
|
}
|
||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static synchronized void reinit() {
|
||||||
|
httpClient = newHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new HTTP client. Most users should just use
|
* Creates a new HTTP client. Most users should just use
|
||||||
* getHttpClient() to get the standard AntennaPod client,
|
* getHttpClient() to get the standard AntennaPod client,
|
||||||
@ -69,13 +78,13 @@ public class AntennapodHttpClient {
|
|||||||
client.networkInterceptors().add(chain -> {
|
client.networkInterceptors().add(chain -> {
|
||||||
Request request = chain.request();
|
Request request = chain.request();
|
||||||
Response response = chain.proceed(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) {
|
response.code() == StatusLine.HTTP_PERM_REDIRECT) {
|
||||||
String location = response.header("Location");
|
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();
|
URL url = request.url();
|
||||||
location = url.getProtocol() + "://" + url.getHost() + location;
|
location = url.getProtocol() + "://" + url.getHost() + location;
|
||||||
} else if(!location.toLowerCase().startsWith("http://") &&
|
} else if (!location.toLowerCase().startsWith("http://") &&
|
||||||
!location.toLowerCase().startsWith("https://")) {
|
!location.toLowerCase().startsWith("https://")) {
|
||||||
// Reference is relative to current path
|
// Reference is relative to current path
|
||||||
URL url = request.url();
|
URL url = request.url();
|
||||||
@ -106,6 +115,21 @@ public class AntennapodHttpClient {
|
|||||||
client.setFollowRedirects(true);
|
client.setFollowRedirects(true);
|
||||||
client.setFollowSslRedirects(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) {
|
if(16 <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < 21) {
|
||||||
client.setSslSocketFactory(new CustomSslSocketFactory());
|
client.setSslSocketFactory(new CustomSslSocketFactory());
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,8 @@ public class DownloadRequest implements Parcelable {
|
|||||||
|
|
||||||
DownloadRequest that = (DownloadRequest) o;
|
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 (deleteOnFailure != that.deleteOnFailure) return false;
|
||||||
if (feedfileId != that.feedfileId) return false;
|
if (feedfileId != that.feedfileId) return false;
|
||||||
if (feedfileType != that.feedfileType) return false;
|
if (feedfileType != that.feedfileType) return false;
|
||||||
|
@ -188,7 +188,7 @@ public class DownloadService extends Service {
|
|||||||
if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
|
if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
|
||||||
postAuthenticationNotification(downloader.getDownloadRequest());
|
postAuthenticationNotification(downloader.getDownloadRequest());
|
||||||
} else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
|
} 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");
|
Log.d(TAG, "Requested invalid range, restarting download from the beginning");
|
||||||
FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination()));
|
FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination()));
|
||||||
|
@ -27,6 +27,7 @@ import java.util.Date;
|
|||||||
import de.danoeh.antennapod.core.ClientConfig;
|
import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.R;
|
import de.danoeh.antennapod.core.R;
|
||||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
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.DateUtils;
|
||||||
import de.danoeh.antennapod.core.util.DownloadError;
|
import de.danoeh.antennapod.core.util.DownloadError;
|
||||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||||
@ -67,6 +68,12 @@ public class HttpDownloader extends Downloader {
|
|||||||
final URI uri = URIUtil.getURIFromRequestUrl(request.getSource());
|
final URI uri = URIUtil.getURIFromRequestUrl(request.getSource());
|
||||||
Request.Builder httpReq = new Request.Builder().url(uri.toURL())
|
Request.Builder httpReq = new Request.Builder().url(uri.toURL())
|
||||||
.header("User-Agent", ClientConfig.USER_AGENT);
|
.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())) {
|
if(!TextUtils.isEmpty(request.getLastModified())) {
|
||||||
String lastModified = request.getLastModified();
|
String lastModified = request.getLastModified();
|
||||||
Date lastModifiedDate = DateUtils.parse(lastModified);
|
Date lastModifiedDate = DateUtils.parse(lastModified);
|
||||||
@ -117,6 +124,15 @@ public class HttpDownloader extends Downloader {
|
|||||||
throw e;
|
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();
|
responseBody = response.body();
|
||||||
String contentEncodingHeader = response.header("Content-Encoding");
|
String contentEncodingHeader = response.header("Content-Encoding");
|
||||||
boolean isGzip = false;
|
boolean isGzip = false;
|
||||||
@ -180,7 +196,7 @@ public class HttpDownloader extends Downloader {
|
|||||||
&& !TextUtils.isEmpty(contentRangeHeader)) {
|
&& !TextUtils.isEmpty(contentRangeHeader)) {
|
||||||
String start = contentRangeHeader.substring("bytes ".length(),
|
String start = contentRangeHeader.substring("bytes ".length(),
|
||||||
contentRangeHeader.indexOf("-"));
|
contentRangeHeader.indexOf("-"));
|
||||||
request.setSoFar(Long.valueOf(start));
|
request.setSoFar(Long.parseLong(start));
|
||||||
Log.d(TAG, "Starting download at position " + request.getSoFar());
|
Log.d(TAG, "Starting download at position " + request.getSoFar());
|
||||||
|
|
||||||
out = new RandomAccessFile(destination, "rw");
|
out = new RandomAccessFile(destination, "rw");
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
* Returns the position of the current media object or INVALID_TIME if the position could not be retrieved.
|
||||||
*/
|
*/
|
||||||
public int getPosition() {
|
public int getPosition() {
|
||||||
if (!playerLock.tryLock()) {
|
try {
|
||||||
|
if (!playerLock.tryLock(50, TimeUnit.MILLISECONDS)) {
|
||||||
|
return INVALID_TIME;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
return INVALID_TIME;
|
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.
|
* This method is executed on an internal executor service.
|
||||||
*/
|
*/
|
||||||
public void setVolume(final float volumeLeft, float volumeRight) {
|
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.
|
* This method is executed on the caller's thread.
|
||||||
*/
|
*/
|
||||||
private void setVolumeSync(float volumeLeft, float volumeRight) {
|
private void setVolumeSync(float volumeLeft, float volumeRight) {
|
||||||
@ -946,15 +950,16 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
if (pausedBecauseOfTransientAudiofocusLoss) { // we paused => play now
|
if (pausedBecauseOfTransientAudiofocusLoss) { // we paused => play now
|
||||||
resume();
|
resume();
|
||||||
} else { // we ducked => raise audio level back
|
} else { // we ducked => raise audio level back
|
||||||
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
|
setVolumeSync(UserPreferences.getLeftVolume(),
|
||||||
AudioManager.ADJUST_RAISE, 0);
|
UserPreferences.getRightVolume());
|
||||||
}
|
}
|
||||||
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
|
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
|
||||||
if (playerStatus == PlayerStatus.PLAYING) {
|
if (playerStatus == PlayerStatus.PLAYING) {
|
||||||
if (!UserPreferences.shouldPauseForFocusLoss()) {
|
if (!UserPreferences.shouldPauseForFocusLoss()) {
|
||||||
Log.d(TAG, "Lost audio focus temporarily. Ducking...");
|
Log.d(TAG, "Lost audio focus temporarily. Ducking...");
|
||||||
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
|
final float DUCK_FACTOR = 0.25f;
|
||||||
AudioManager.ADJUST_LOWER, 0);
|
setVolumeSync(DUCK_FACTOR * UserPreferences.getLeftVolume(),
|
||||||
|
DUCK_FACTOR * UserPreferences.getRightVolume());
|
||||||
pausedBecauseOfTransientAudiofocusLoss = false;
|
pausedBecauseOfTransientAudiofocusLoss = false;
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Lost audio focus temporarily. Could duck, but won't, pausing...");
|
Log.d(TAG, "Lost audio focus temporarily. Could duck, but won't, pausing...");
|
||||||
@ -1204,6 +1209,71 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
|
|
||||||
private static final String TAG = "MediaSessionCompat";
|
private static final String TAG = "MediaSessionCompat";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlay() {
|
||||||
|
Log.d(TAG, "onPlay()");
|
||||||
|
if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
|
||||||
|
resume();
|
||||||
|
} else if (playerStatus == PlayerStatus.INITIALIZED) {
|
||||||
|
setStartWhenPrepared(true);
|
||||||
|
prepare();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
Log.d(TAG, "onPause()");
|
||||||
|
if (playerStatus == PlayerStatus.PLAYING) {
|
||||||
|
pause(false, true);
|
||||||
|
}
|
||||||
|
if (UserPreferences.isPersistNotify()) {
|
||||||
|
pause(false, true);
|
||||||
|
} else {
|
||||||
|
pause(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
Log.d(TAG, "onStop()");
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSkipToPrevious() {
|
||||||
|
Log.d(TAG, "onSkipToPrevious()");
|
||||||
|
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRewind() {
|
||||||
|
Log.d(TAG, "onRewind()");
|
||||||
|
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFastForward() {
|
||||||
|
Log.d(TAG, "onFastForward()");
|
||||||
|
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSkipToNext() {
|
||||||
|
Log.d(TAG, "onSkipToNext()");
|
||||||
|
if(UserPreferences.shouldHardwareButtonSkip()) {
|
||||||
|
endPlayback(true);
|
||||||
|
} else {
|
||||||
|
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSeekTo(long pos) {
|
||||||
|
Log.d(TAG, "onSeekTo()");
|
||||||
|
seekTo((int) pos);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onMediaButtonEvent(final Intent mediaButton) {
|
public boolean onMediaButtonEvent(final Intent mediaButton) {
|
||||||
Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
|
Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
|
||||||
@ -1240,42 +1310,27 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_MEDIA_PLAY: {
|
case KeyEvent.KEYCODE_MEDIA_PLAY: {
|
||||||
Log.d(TAG, "Received Play event from RemoteControlClient");
|
sessionCallback.onPlay();
|
||||||
if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
|
|
||||||
resume();
|
|
||||||
} else if (playerStatus == PlayerStatus.INITIALIZED) {
|
|
||||||
setStartWhenPrepared(true);
|
|
||||||
prepare();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_MEDIA_PAUSE: {
|
case KeyEvent.KEYCODE_MEDIA_PAUSE: {
|
||||||
Log.d(TAG, "Received Pause event from RemoteControlClient");
|
sessionCallback.onPause();
|
||||||
if (playerStatus == PlayerStatus.PLAYING) {
|
|
||||||
pause(false, true);
|
|
||||||
}
|
|
||||||
if (UserPreferences.isPersistNotify()) {
|
|
||||||
pause(false, true);
|
|
||||||
} else {
|
|
||||||
pause(true, true);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_MEDIA_STOP: {
|
case KeyEvent.KEYCODE_MEDIA_STOP: {
|
||||||
Log.d(TAG, "Received Stop event from RemoteControlClient");
|
sessionCallback.onStop();
|
||||||
stop();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS: {
|
case KeyEvent.KEYCODE_MEDIA_PREVIOUS: {
|
||||||
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
sessionCallback.onSkipToPrevious();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_MEDIA_REWIND: {
|
case KeyEvent.KEYCODE_MEDIA_REWIND: {
|
||||||
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
sessionCallback.onRewind();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
|
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
|
||||||
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
sessionCallback.onFastForward();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case KeyEvent.KEYCODE_MEDIA_NEXT: {
|
case KeyEvent.KEYCODE_MEDIA_NEXT: {
|
||||||
|
@ -4,6 +4,7 @@ import android.database.Cursor;
|
|||||||
import android.support.v4.util.ArrayMap;
|
import android.support.v4.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -590,17 +591,18 @@ public final class DBReader {
|
|||||||
FeedItem item = null;
|
FeedItem item = null;
|
||||||
|
|
||||||
Cursor itemCursor = adapter.getFeedItemCursor(Long.toString(itemId));
|
Cursor itemCursor = adapter.getFeedItemCursor(Long.toString(itemId));
|
||||||
if (itemCursor.moveToFirst()) {
|
if (!itemCursor.moveToFirst()) {
|
||||||
List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor);
|
return null;
|
||||||
if (list.size() > 0) {
|
}
|
||||||
item = list.get(0);
|
List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor);
|
||||||
loadAdditionalFeedItemListData(list);
|
itemCursor.close();
|
||||||
if (item.hasChapters()) {
|
if (list.size() > 0) {
|
||||||
loadChaptersOfFeedItem(adapter, item);
|
item = list.get(0);
|
||||||
}
|
loadAdditionalFeedItemListData(list);
|
||||||
|
if (item.hasChapters()) {
|
||||||
|
loadChaptersOfFeedItem(adapter, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
itemCursor.close();
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,7 +678,7 @@ public final class DBReader {
|
|||||||
* as well as chapter marks of the FeedItems will also be loaded from the database.
|
* as well as chapter marks of the FeedItems will also be loaded from the database.
|
||||||
*/
|
*/
|
||||||
public static List<FeedItem> getFeedItems(final long... itemIds) {
|
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();
|
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||||
adapter.open();
|
adapter.open();
|
||||||
List<FeedItem> items = getFeedItems(adapter, itemIds);
|
List<FeedItem> items = getFeedItems(adapter, itemIds);
|
||||||
@ -898,19 +900,23 @@ public final class DBReader {
|
|||||||
adapter.open();
|
adapter.open();
|
||||||
Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId);
|
Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId);
|
||||||
|
|
||||||
FeedMedia media = null;
|
if (!mediaCursor.moveToFirst()) {
|
||||||
if (mediaCursor.moveToFirst()) {
|
return null;
|
||||||
int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
|
}
|
||||||
final long itemId = mediaCursor.getLong(indexFeedItem);
|
|
||||||
media = FeedMedia.fromCursor(mediaCursor);
|
int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
|
||||||
|
long itemId = mediaCursor.getLong(indexFeedItem);
|
||||||
|
FeedMedia media = FeedMedia.fromCursor(mediaCursor);
|
||||||
|
mediaCursor.close();
|
||||||
|
|
||||||
|
if(media != null) {
|
||||||
FeedItem item = getFeedItem(itemId);
|
FeedItem item = getFeedItem(itemId);
|
||||||
if (media != null && item != null) {
|
if (item != null) {
|
||||||
media.setItem(item);
|
media.setItem(item);
|
||||||
item.setMedia(media);
|
item.setMedia(media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaCursor.close();
|
|
||||||
adapter.close();
|
adapter.close();
|
||||||
|
|
||||||
return media;
|
return media;
|
||||||
|
@ -60,12 +60,12 @@ public class NSITunes extends Namespace {
|
|||||||
try {
|
try {
|
||||||
int duration = 0;
|
int duration = 0;
|
||||||
if (parts.length == 2) {
|
if (parts.length == 2) {
|
||||||
duration += TimeUnit.MINUTES.toMillis(Long.valueOf(parts[0])) +
|
duration += TimeUnit.MINUTES.toMillis(Long.parseLong(parts[0])) +
|
||||||
TimeUnit.SECONDS.toMillis(Long.valueOf(parts[1]));
|
TimeUnit.SECONDS.toMillis(Long.parseLong(parts[1]));
|
||||||
} else if (parts.length >= 3) {
|
} else if (parts.length >= 3) {
|
||||||
duration += TimeUnit.HOURS.toMillis(Long.valueOf(parts[0])) +
|
duration += TimeUnit.HOURS.toMillis(Long.parseLong(parts[0])) +
|
||||||
TimeUnit.MINUTES.toMillis(Long.valueOf(parts[1])) +
|
TimeUnit.MINUTES.toMillis(Long.parseLong(parts[1])) +
|
||||||
TimeUnit.SECONDS.toMillis(Long.valueOf(parts[2]));
|
TimeUnit.SECONDS.toMillis(Long.parseLong(parts[2]));
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -88,9 +88,9 @@ public final class Converter {
|
|||||||
if (parts.length != 3) {
|
if (parts.length != 3) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return Integer.valueOf(parts[0]) * 3600 * 1000 +
|
return Integer.parseInt(parts[0]) * 3600 * 1000 +
|
||||||
Integer.valueOf(parts[1]) * 60 * 1000 +
|
Integer.parseInt(parts[1]) * 60 * 1000 +
|
||||||
Integer.valueOf(parts[2]) * 1000;
|
Integer.parseInt(parts[2]) * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts short duration string (HH:MM) to milliseconds. */
|
/** Converts short duration string (HH:MM) to milliseconds. */
|
||||||
@ -99,8 +99,8 @@ public final class Converter {
|
|||||||
if (parts.length != 2) {
|
if (parts.length != 2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return Integer.valueOf(parts[0]) * 3600 * 1000 +
|
return Integer.parseInt(parts[0]) * 3600 * 1000 +
|
||||||
Integer.valueOf(parts[1]) * 1000 * 60;
|
Integer.parseInt(parts[1]) * 1000 * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts milliseconds to a localized string containing hours and minutes */
|
/** Converts milliseconds to a localized string containing hours and minutes */
|
||||||
@ -118,5 +118,16 @@ public final class Converter {
|
|||||||
result += minutes;
|
result += minutes;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the volume as read as the progress from a SeekBar scaled to 100 and as saved in
|
||||||
|
* UserPreferences to the format taken by setVolume methods.
|
||||||
|
* @param progress integer between 0 to 100 taken from the SeekBar progress
|
||||||
|
* @return the appropriate volume as float taken by setVolume methods
|
||||||
|
*/
|
||||||
|
public static float getVolumeFromPercentage(int progress){
|
||||||
|
if (progress==100)
|
||||||
|
return 1f;
|
||||||
|
return (float) (1 - (Math.log(101 - progress) / Math.log(101)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,13 +115,13 @@ public class DateUtils {
|
|||||||
int idx = 0;
|
int idx = 0;
|
||||||
if (parts.length == 3) {
|
if (parts.length == 3) {
|
||||||
// string has hours
|
// string has hours
|
||||||
result += Integer.valueOf(parts[idx]) * 3600000L;
|
result += Integer.parseInt(parts[idx]) * 3600000L;
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
if (parts.length >= 2) {
|
if (parts.length >= 2) {
|
||||||
result += Integer.valueOf(parts[idx]) * 60000L;
|
result += Integer.parseInt(parts[idx]) * 60000L;
|
||||||
idx++;
|
idx++;
|
||||||
result += (Float.valueOf(parts[idx])) * 1000L;
|
result += (Float.parseFloat(parts[idx])) * 1000L;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@ public enum DownloadError {
|
|||||||
ERROR_UNKNOWN_HOST(11, R.string.download_error_unknown_host),
|
ERROR_UNKNOWN_HOST(11, R.string.download_error_unknown_host),
|
||||||
ERROR_REQUEST_ERROR(12, R.string.download_error_request_error),
|
ERROR_REQUEST_ERROR(12, R.string.download_error_request_error),
|
||||||
ERROR_DB_ACCESS_ERROR(13, R.string.download_error_db_access),
|
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 code;
|
||||||
private final int resId;
|
private final int resId;
|
||||||
|
@ -35,7 +35,7 @@ public final class IntList {
|
|||||||
int hashCode = 1;
|
int hashCode = 1;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
int value = values[i];
|
int value = values[i];
|
||||||
hashCode = 31 * hashCode + (int)(value ^ (value >>> 32));
|
hashCode = 31 * hashCode + value;
|
||||||
}
|
}
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
package de.danoeh.antennapod.core.util.gui;
|
|
||||||
|
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by an UndoBarController for saving a removed FeedItem
|
|
||||||
*/
|
|
||||||
public class FeedItemUndoToken implements Parcelable {
|
|
||||||
private long itemId;
|
|
||||||
private long feedId;
|
|
||||||
private int position;
|
|
||||||
|
|
||||||
public FeedItemUndoToken(FeedItem item, int position) {
|
|
||||||
this.itemId = item.getId();
|
|
||||||
this.feedId = item.getFeed().getId();
|
|
||||||
this.position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FeedItemUndoToken(Parcel in) {
|
|
||||||
itemId = in.readLong();
|
|
||||||
feedId = in.readLong();
|
|
||||||
position = in.readInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Parcelable.Creator<FeedItemUndoToken> CREATOR = new Parcelable.Creator<FeedItemUndoToken>() {
|
|
||||||
public FeedItemUndoToken createFromParcel(Parcel in) {
|
|
||||||
return new FeedItemUndoToken(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FeedItemUndoToken[] newArray(int size) {
|
|
||||||
return new FeedItemUndoToken[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeToParcel(Parcel out, int flags) {
|
|
||||||
out.writeLong(itemId);
|
|
||||||
out.writeLong(feedId);
|
|
||||||
out.writeInt(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getFeedItemId() {
|
|
||||||
return itemId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPosition() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,7 +19,6 @@ import android.text.TextUtils;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@ -424,6 +423,7 @@ public abstract class PlaybackController {
|
|||||||
clearStatusMsg();
|
clearStatusMsg();
|
||||||
checkMediaInfoLoaded();
|
checkMediaInfoLoaded();
|
||||||
cancelPositionObserver();
|
cancelPositionObserver();
|
||||||
|
onPositionObserverUpdate();
|
||||||
updatePlayButtonAppearance(playResource, playText);
|
updatePlayButtonAppearance(playResource, playText);
|
||||||
if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) {
|
if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) {
|
||||||
setScreenOn(false);
|
setScreenOn(false);
|
||||||
@ -574,34 +574,32 @@ public abstract class PlaybackController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnClickListener newOnPlayButtonClickListener() {
|
public void playPause() {
|
||||||
return v -> {
|
if (playbackService == null) {
|
||||||
if (playbackService == null) {
|
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!");
|
||||||
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!");
|
return;
|
||||||
return;
|
}
|
||||||
}
|
switch (status) {
|
||||||
switch (status) {
|
case PLAYING:
|
||||||
case PLAYING:
|
playbackService.pause(true, reinitOnPause);
|
||||||
playbackService.pause(true, reinitOnPause);
|
break;
|
||||||
break;
|
case PAUSED:
|
||||||
case PAUSED:
|
case PREPARED:
|
||||||
case PREPARED:
|
playbackService.resume();
|
||||||
playbackService.resume();
|
break;
|
||||||
break;
|
case PREPARING:
|
||||||
case PREPARING:
|
playbackService.setStartWhenPrepared(!playbackService
|
||||||
playbackService.setStartWhenPrepared(!playbackService
|
.isStartWhenPrepared());
|
||||||
.isStartWhenPrepared());
|
if (reinitOnPause
|
||||||
if (reinitOnPause
|
&& playbackService.isStartWhenPrepared() == false) {
|
||||||
&& playbackService.isStartWhenPrepared() == false) {
|
playbackService.reinit();
|
||||||
playbackService.reinit();
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case INITIALIZED:
|
||||||
case INITIALIZED:
|
playbackService.setStartWhenPrepared(true);
|
||||||
playbackService.setStartWhenPrepared(true);
|
playbackService.prepare();
|
||||||
playbackService.prepare();
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean serviceAvailable() {
|
public boolean serviceAvailable() {
|
||||||
|
@ -2,7 +2,10 @@ package de.danoeh.antennapod.core.util.playback;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
|
|
||||||
@ -14,6 +17,7 @@ import org.jsoup.select.Elements;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.R;
|
||||||
import de.danoeh.antennapod.core.util.Converter;
|
import de.danoeh.antennapod.core.util.Converter;
|
||||||
import de.danoeh.antennapod.core.util.ShownotesProvider;
|
import de.danoeh.antennapod.core.util.ShownotesProvider;
|
||||||
|
|
||||||
@ -32,26 +36,32 @@ public class Timeline {
|
|||||||
|
|
||||||
private ShownotesProvider shownotesProvider;
|
private ShownotesProvider shownotesProvider;
|
||||||
|
|
||||||
|
private final String noShownotesLabel;
|
||||||
private final String colorString;
|
private final String colorPrimaryString;
|
||||||
|
private final String colorSecondaryString;
|
||||||
private final int pageMargin;
|
private final int pageMargin;
|
||||||
|
|
||||||
public Timeline(Context context, ShownotesProvider shownotesProvider) {
|
public Timeline(Context context, ShownotesProvider shownotesProvider) {
|
||||||
if (shownotesProvider == null) throw new IllegalArgumentException("shownotesProvider = null");
|
if (shownotesProvider == null) throw new IllegalArgumentException("shownotesProvider = null");
|
||||||
this.shownotesProvider = shownotesProvider;
|
this.shownotesProvider = shownotesProvider;
|
||||||
|
|
||||||
TypedArray res = context
|
noShownotesLabel = context.getString(R.string.no_shownotes_label);
|
||||||
.getTheme()
|
|
||||||
.obtainStyledAttributes(
|
TypedArray res = context.getTheme().obtainStyledAttributes(
|
||||||
new int[]{android.R.attr.textColorPrimary});
|
new int[]{ android.R.attr.textColorPrimary});
|
||||||
int colorResource = res.getColor(0, 0);
|
@ColorInt int col = res.getColor(0, 0);
|
||||||
colorString = String.format("#%06X",
|
colorPrimaryString = "rgba(" + Color.red(col) + "," + Color.green(col) + "," +
|
||||||
0xFFFFFF & colorResource);
|
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();
|
res.recycle();
|
||||||
|
|
||||||
pageMargin = (int) TypedValue.applyDimension(
|
pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
|
||||||
TypedValue.COMPLEX_UNIT_DIP, 8, context.getResources()
|
context.getResources().getDisplayMetrics()
|
||||||
.getDisplayMetrics()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,9 +92,24 @@ public class Timeline {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (shownotes == null) {
|
|
||||||
Log.d(TAG, "shownotesProvider contained no shownotes. Returning empty string");
|
if(TextUtils.isEmpty(shownotes)) {
|
||||||
return "";
|
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
|
// 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);
|
Document document = Jsoup.parse(shownotes);
|
||||||
|
|
||||||
// apply style
|
// apply style
|
||||||
String styleStr = String.format(WEBVIEW_STYLE, colorString, "100%", pageMargin,
|
String styleStr = String.format(WEBVIEW_STYLE, colorPrimaryString, "100%", pageMargin,
|
||||||
pageMargin, pageMargin, pageMargin);
|
pageMargin, pageMargin, pageMargin);
|
||||||
document.head().appendElement("style").attr("type", "text/css").text(styleStr);
|
document.head().appendElement("style").attr("type", "text/css").text(styleStr);
|
||||||
|
|
||||||
@ -125,8 +150,7 @@ public class Timeline {
|
|||||||
element.html(buffer.toString());
|
element.html(buffer.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "Out: " + document.toString());
|
|
||||||
return document.toString();
|
return document.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +172,7 @@ public class Timeline {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
return Integer.valueOf(m.group(1));
|
return Integer.parseInt(m.group(1));
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 467 B After Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 222 B After Width: | Height: | Size: 125 B |
Before Width: | Height: | Size: 223 B After Width: | Height: | Size: 124 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 429 B |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 408 B |
Before Width: | Height: | Size: 522 B After Width: | Height: | Size: 415 B |
Before Width: | Height: | Size: 510 B After Width: | Height: | Size: 394 B |
Before Width: | Height: | Size: 584 B After Width: | Height: | Size: 278 B |
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 180 B |
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 170 B |
Before Width: | Height: | Size: 505 B After Width: | Height: | Size: 260 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 167 B |
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 164 B |
Before Width: | Height: | Size: 248 B After Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 246 B After Width: | Height: | Size: 158 B |
Before Width: | Height: | Size: 425 B |
Before Width: | Height: | Size: 424 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 175 B |
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 169 B |
Before Width: | Height: | Size: 389 B After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 195 B |
Before Width: | Height: | Size: 324 B After Width: | Height: | Size: 189 B |
Before Width: | Height: | Size: 366 B After Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 360 B After Width: | Height: | Size: 253 B |
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 395 B After Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 480 B After Width: | Height: | Size: 331 B |
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 261 B |
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 727 B After Width: | Height: | Size: 458 B |
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 154 B |
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 150 B |
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 111 B |
Before Width: | Height: | Size: 131 B After Width: | Height: | Size: 110 B |
Before Width: | Height: | Size: 583 B After Width: | Height: | Size: 478 B |
Before Width: | Height: | Size: 602 B After Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 636 B After Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 638 B After Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 179 B |
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 171 B |