Merge pull request #5055 from ByteHamster/spotbugs
Add SpotBugs CI check
This commit is contained in:
commit
7465b747f3
|
@ -90,3 +90,9 @@ workflows:
|
|||
- run:
|
||||
name: Lint
|
||||
command: ./gradlew lintPlayRelease
|
||||
- build:
|
||||
name: SpotBugs
|
||||
build-steps:
|
||||
- run:
|
||||
name: SpotBugs
|
||||
command: ./gradlew spotbugsPlayDebug spotbugsDebug 2>&1 | grep -i "spotbugs"
|
||||
|
|
|
@ -53,6 +53,9 @@ public class ViewPagerBottomSheetBehavior<V extends View> extends BottomSheetBeh
|
|||
}
|
||||
|
||||
public void updateScrollingChild() {
|
||||
if (viewRef == null) {
|
||||
return;
|
||||
}
|
||||
final View scrollingChild = findScrollingChild(viewRef.get());
|
||||
nestedScrollingChildRef = new WeakReference<>(scrollingChild);
|
||||
}
|
||||
|
|
|
@ -99,7 +99,10 @@ public class BugReportActivity extends AppCompatActivity {
|
|||
private void exportLog() {
|
||||
try {
|
||||
File filename = new File(UserPreferences.getDataFolder(null), "full-logs.txt");
|
||||
filename.createNewFile();
|
||||
boolean success = filename.createNewFile();
|
||||
if (!success) {
|
||||
throw new IOException("Unable to create output file");
|
||||
}
|
||||
String cmd = "logcat -d -f " + filename.getAbsolutePath();
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
//share file
|
||||
|
|
|
@ -188,7 +188,9 @@ public class MainActivity extends CastEnabledActivity {
|
|||
|
||||
public void setupToolbarToggle(@NonNull Toolbar toolbar, boolean displayUpArrow) {
|
||||
if (drawerLayout != null) { // Tablet layout does not have a drawer
|
||||
drawerLayout.removeDrawerListener(drawerToggle);
|
||||
if (drawerToggle != null) {
|
||||
drawerLayout.removeDrawerListener(drawerToggle);
|
||||
}
|
||||
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
|
||||
R.string.drawer_open, R.string.drawer_close);
|
||||
drawerLayout.addDrawerListener(drawerToggle);
|
||||
|
|
|
@ -2,7 +2,6 @@ package de.danoeh.antennapod.activity;
|
|||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
@ -479,7 +478,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
|||
cardViewSeek = findViewById(R.id.cardViewSeek);
|
||||
txtvSeek = findViewById(R.id.txtvSeek);
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||
showTimeLeft = UserPreferences.shouldShowRemainingTime();
|
||||
Log.d("timeleft", showTimeLeft ? "true" : "false");
|
||||
txtvLength = findViewById(R.id.txtvLength);
|
||||
|
|
|
@ -58,9 +58,8 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
|
|||
*/
|
||||
public static final String SUBSCRIPTION_LIST_TAG = "SubscriptionList";
|
||||
|
||||
private static List<String> fragmentTags;
|
||||
private static String[] titles;
|
||||
|
||||
private final List<String> fragmentTags = new ArrayList<>();
|
||||
private final String[] titles;
|
||||
private final ItemAccess itemAccess;
|
||||
private final WeakReference<Activity> activity;
|
||||
public boolean showSubscriptionList = true;
|
||||
|
@ -98,7 +97,8 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
|
|||
showSubscriptionList = false;
|
||||
}
|
||||
|
||||
fragmentTags = newTags;
|
||||
fragmentTags.clear();
|
||||
fragmentTags.addAll(newTags);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.net.Uri;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
@ -37,9 +36,6 @@ public class DocumentFileExportWorker {
|
|||
OutputStreamWriter writer = null;
|
||||
try {
|
||||
Uri uri = output.getUri();
|
||||
if (uri == null) {
|
||||
throw new FileNotFoundException("Export file not found.");
|
||||
}
|
||||
outputStream = context.getContentResolver().openOutputStream(uri);
|
||||
if (outputStream == null) {
|
||||
throw new IOException();
|
||||
|
|
|
@ -41,8 +41,8 @@ public class ExportWorker {
|
|||
|
||||
public Observable<File> exportObservable() {
|
||||
if (output.exists()) {
|
||||
Log.w(TAG, "Overwriting previously exported file.");
|
||||
output.delete();
|
||||
boolean success = output.delete();
|
||||
Log.w(TAG, "Overwriting previously exported file: " + success);
|
||||
}
|
||||
return Observable.create(subscriber -> {
|
||||
OutputStreamWriter writer = null;
|
||||
|
|
|
@ -206,7 +206,7 @@ public class ProxyDialog {
|
|||
|
||||
private boolean checkPort() {
|
||||
int port = getPort();
|
||||
if(port < 0 && port > 65535) {
|
||||
if (port < 0 || port > 65535) {
|
||||
etPort.setError(context.getString(R.string.proxy_port_invalid_error));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package de.danoeh.antennapod.discovery;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
|
@ -24,8 +23,6 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
public class ItunesTopListLoader {
|
||||
private static final String TAG = "ITunesTopListLoader";
|
||||
private final Context context;
|
||||
|
@ -38,13 +35,6 @@ public class ItunesTopListLoader {
|
|||
this.context = context;
|
||||
}
|
||||
|
||||
public Single<List<PodcastSearchResult>> loadToplist() {
|
||||
String defaultCountry = Locale.getDefault().getCountry();
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||
String countryCode = prefs.getString(PREF_KEY_COUNTRY_CODE, COUNTRY_CODE_UNSET);
|
||||
return this.loadToplist(countryCode, 25);
|
||||
}
|
||||
|
||||
public Single<List<PodcastSearchResult>> loadToplist(String country, int limit) {
|
||||
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) emitter -> {
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
|
|
|
@ -12,7 +12,7 @@ public class PodcastSearcherRegistry {
|
|||
private PodcastSearcherRegistry() {
|
||||
}
|
||||
|
||||
public static List<SearcherInfo> getSearchProviders() {
|
||||
public static synchronized List<SearcherInfo> getSearchProviders() {
|
||||
if (searchProviders == null) {
|
||||
searchProviders = new ArrayList<>();
|
||||
searchProviders.add(new SearcherInfo(new CombinedSearcher(), 1.0f));
|
||||
|
|
|
@ -7,7 +7,6 @@ import de.danoeh.antennapod.BuildConfig;
|
|||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -40,7 +39,7 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
|
|||
File path = getFile();
|
||||
PrintWriter out = null;
|
||||
try {
|
||||
out = new PrintWriter(new FileWriter(path));
|
||||
out = new PrintWriter(path, "UTF-8");
|
||||
out.println("## Crash info");
|
||||
out.println("Time: " + new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.getDefault()).format(new Date()));
|
||||
out.println("AntennaPod version: " + BuildConfig.VERSION_NAME);
|
||||
|
|
|
@ -27,7 +27,7 @@ public class AllEpisodesFragment extends EpisodesListFragment {
|
|||
private static final String PREF_NAME = "PrefAllEpisodesFragment";
|
||||
private static final String PREF_FILTER = "filter";
|
||||
|
||||
private static FeedItemFilter feedItemFilter = new FeedItemFilter("");
|
||||
private FeedItemFilter feedItemFilter = new FeedItemFilter("");
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
@ -14,12 +15,12 @@ public abstract class PagedToolbarFragment extends Fragment {
|
|||
|
||||
/**
|
||||
* Invalidate the toolbar menu if the current child fragment is visible.
|
||||
* @param child The fragment, or null to force-refresh whatever the active fragment is.
|
||||
* @param child The fragment to invalidate
|
||||
*/
|
||||
void invalidateOptionsMenuIfActive(Fragment child) {
|
||||
void invalidateOptionsMenuIfActive(@NonNull Fragment child) {
|
||||
Fragment visibleChild = getChildFragmentManager().findFragmentByTag("f" + viewPager.getCurrentItem());
|
||||
if (visibleChild == child || child == null) {
|
||||
child.onPrepareOptionsMenu(toolbar.getMenu());
|
||||
if (visibleChild == child) {
|
||||
visibleChild.onPrepareOptionsMenu(toolbar.getMenu());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -291,6 +291,9 @@ public class SubscriptionFragment extends Fragment implements Toolbar.OnMenuItem
|
|||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
if (menuInfo == null) {
|
||||
return;
|
||||
}
|
||||
AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
int position = adapterInfo.position;
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package de.danoeh.antennapod.fragment.gpodnet;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetTag;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
|
||||
|
@ -24,8 +24,7 @@ public class TagFragment extends PodcastListFragment {
|
|||
|
||||
private GpodnetTag tag;
|
||||
|
||||
public static TagFragment newInstance(GpodnetTag tag) {
|
||||
Validate.notNull(tag);
|
||||
public static TagFragment newInstance(@NonNull GpodnetTag tag) {
|
||||
TagFragment fragment = new TagFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable("tag", tag);
|
||||
|
@ -38,7 +37,9 @@ public class TagFragment extends PodcastListFragment {
|
|||
super.onCreate(savedInstanceState);
|
||||
|
||||
Bundle args = getArguments();
|
||||
Validate.isTrue(args != null && args.getParcelable("tag") != null, "args invalid");
|
||||
if (args == null || args.getParcelable("tag") == null) {
|
||||
throw new IllegalArgumentException("Arguments not given");
|
||||
}
|
||||
tag = args.getParcelable("tag");
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public class DevelopersFragment extends ListFragment {
|
|||
developersLoader = Single.create((SingleOnSubscribe<ArrayList<SimpleIconListAdapter.ListItem>>) emitter -> {
|
||||
ArrayList<SimpleIconListAdapter.ListItem> developers = new ArrayList<>();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
getContext().getAssets().open("developers.csv")));
|
||||
getContext().getAssets().open("developers.csv"), "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] info = line.split(";");
|
||||
|
|
|
@ -95,7 +95,7 @@ public class LicensesFragment extends ListFragment {
|
|||
private void showLicenseText(String licenseTextFile) {
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
getContext().getAssets().open(licenseTextFile)));
|
||||
getContext().getAssets().open(licenseTextFile), "UTF-8"));
|
||||
StringBuilder licenseText = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
|
|
|
@ -29,7 +29,7 @@ public class SpecialThanksFragment extends ListFragment {
|
|||
translatorsLoader = Single.create((SingleOnSubscribe<ArrayList<SimpleIconListAdapter.ListItem>>) emitter -> {
|
||||
ArrayList<SimpleIconListAdapter.ListItem> translators = new ArrayList<>();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
getContext().getAssets().open("special_thanks.csv")));
|
||||
getContext().getAssets().open("special_thanks.csv"), "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] info = line.split(";");
|
||||
|
|
|
@ -29,7 +29,7 @@ public class TranslatorsFragment extends ListFragment {
|
|||
translatorsLoader = Single.create((SingleOnSubscribe<ArrayList<SimpleIconListAdapter.ListItem>>) emitter -> {
|
||||
ArrayList<SimpleIconListAdapter.ListItem> translators = new ArrayList<>();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
getContext().getAssets().open("translators.csv")));
|
||||
getContext().getAssets().open("translators.csv"), "UTF-8"));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] info = line.split(";");
|
||||
|
|
33
build.gradle
33
build.gradle
|
@ -9,6 +9,7 @@ buildscript {
|
|||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:1.0.2'
|
||||
classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3'
|
||||
classpath "gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +26,38 @@ allprojects {
|
|||
options.compilerArgs << "-Xlint"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.github.spotbugs'
|
||||
|
||||
spotbugs {
|
||||
effort = 'max'
|
||||
reportLevel = 'medium'
|
||||
excludeFilter = rootProject.file('config/spotbugs/exclude.xml')
|
||||
ignoreFailures = true // Handled by printing task
|
||||
}
|
||||
|
||||
gradle.taskGraph.beforeTask { task ->
|
||||
if (task.name.toLowerCase().contains('spotbugs')) {
|
||||
task.doLast {
|
||||
def reportFile = task.project.file("build/reports/spotbugs/playDebug.xml")
|
||||
if (!reportFile.exists()) return
|
||||
def slurped = new XmlSlurper().parse(reportFile)
|
||||
|
||||
def foundErrors = false
|
||||
slurped['BugInstance'].each { bug ->
|
||||
logger.error "[SpotBugs] ${bug['LongMessage']} [${bug.@'type'}]"
|
||||
bug['SourceLine'].each { line ->
|
||||
logger.error "[SpotBugs] ${line['Message']}"
|
||||
foundErrors = true
|
||||
}
|
||||
}
|
||||
if (foundErrors) {
|
||||
throw new TaskExecutionException(task,
|
||||
new Exception("SpotBugs violations were found. See output above for details."))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable predex if requested (we can"t predex in Circle CI
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
<Match>
|
||||
<Bug pattern="BC_UNCONFIRMED_CAST"/>
|
||||
<Class name="de.danoeh.antennapod.adapter.NavListAdapter"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="BC_UNCONFIRMED_CAST_OF_RETURN_VALUE"/>
|
||||
<Class name="de.danoeh.antennapod.net.ssl.NoV1SslSocketFactory"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="DM_DEFAULT_ENCODING"/>
|
||||
<Class name="de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReader"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="HSC_HUGE_SHARED_STRING_CONSTANT"/>
|
||||
<Class name="de.danoeh.antennapod.net.ssl.BackportCaCerts"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="MS_CANNOT_BE_FINAL"/>
|
||||
<Class name="de.danoeh.antennapod.core.service.playback.PlaybackService"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="MS_MUTABLE_ARRAY"/>
|
||||
<Class name="de.danoeh.antennapod.fragment.NavDrawerFragment"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="NM_SAME_SIMPLE_NAME_AS_SUPERCLASS"/>
|
||||
<Class name="de.danoeh.antennapod.menuhandler.MenuItemUtils"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="NP_NONNULL_PARAM_VIOLATION"/>
|
||||
<Class name="de.danoeh.antennapod.activity.MainActivity"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="NP_NULL_ON_SOME_PATH"/>
|
||||
<Class name="de.danoeh.antennapod.activity.MainActivity"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="NP_NULL_ON_SOME_PATH"/>
|
||||
<Class name="de.danoeh.antennapod.core.feed.FeedMedia"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="NP_NULL_PARAM_DEREF"/>
|
||||
<Class name="de.danoeh.antennapod.core.feed.FeedMedia"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE"/>
|
||||
<Class name="de.danoeh.antennapod.preferences.PreferenceUpgrader"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/>
|
||||
<Class name="de.danoeh.antennapod.PodcastApp"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/>
|
||||
<Class name="de.danoeh.antennapod.core.service.download.DownloadService"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/>
|
||||
<Class name="de.danoeh.antennapod.core.service.playback.PlaybackService"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD"/>
|
||||
<Class name="de.danoeh.antennapod.core.storage.NavDrawerData$FolderDrawerItem"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<Bug pattern="UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD"/>
|
||||
<Class name="de.danoeh.antennapod.core.cast.CastButtonVisibilityManager"/>
|
||||
</Match>
|
||||
|
||||
<Match><Class name="de.danoeh.antennapod.core.ClientConfig"/></Match>
|
||||
|
||||
<Match><Package name="de.danoeh.antennapod.core.glide"/></Match>
|
||||
<Match><Package name="de.danoeh.antennapod.databinding"/></Match>
|
||||
|
||||
<Match><Bug pattern="EI_EXPOSE_REP"/></Match>
|
||||
<Match><Bug pattern="EI_EXPOSE_REP2"/></Match>
|
||||
<Match><Bug pattern="HE_EQUALS_NO_HASHCODE"/></Match>
|
||||
<Match><Bug pattern="ICAST_INTEGER_MULTIPLY_CAST_TO_LONG"/></Match>
|
||||
<Match><Bug pattern="IS2_INCONSISTENT_SYNC"/></Match>
|
||||
<Match><Bug pattern="NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION"/></Match>
|
||||
<Match><Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/></Match>
|
||||
<Match><Bug pattern="OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE"/></Match>
|
||||
<Match><Bug pattern="OS_OPEN_STREAM"/></Match>
|
||||
<Match><Bug pattern="OS_OPEN_STREAM_EXCEPTION_PATH"/></Match>
|
||||
<Match><Bug pattern="RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN"/></Match>
|
||||
<Match><Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/></Match>
|
||||
<Match><Bug pattern="RV_RETURN_VALUE_IGNORED"/></Match>
|
||||
<Match><Bug pattern="SE_COMPARATOR_SHOULD_BE_SERIALIZABLE"/></Match>
|
||||
<Match><Bug pattern="SE_NO_SERIALVERSIONID"/></Match>
|
||||
<Match><Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/></Match>
|
||||
<Match><Bug pattern="SF_SWITCH_NO_DEFAULT"/></Match>
|
||||
<Match><Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/></Match>
|
||||
<Match><Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"/></Match>
|
||||
<Match><Bug pattern="WMI_WRONG_MAP_ITERATOR"/></Match>
|
||||
</FindBugsFilter>
|
|
@ -94,7 +94,7 @@ public class OpmlBackupAgent extends BackupAgentHelper {
|
|||
|
||||
if (len != -1) {
|
||||
byte[] oldChecksum = new byte[len];
|
||||
inState.read(oldChecksum);
|
||||
IOUtils.read(inState, oldChecksum, 0, len);
|
||||
Log.d(TAG, "Old checksum: " + new BigInteger(1, oldChecksum).toString(16));
|
||||
|
||||
if (Arrays.equals(oldChecksum, newChecksum)) {
|
||||
|
|
|
@ -43,7 +43,7 @@ public abstract class Chapter extends FeedComponent {
|
|||
String imageUrl = cursor.getString(indexImage);
|
||||
int chapterType = cursor.getInt(indexChapterType);
|
||||
|
||||
Chapter chapter = null;
|
||||
Chapter chapter;
|
||||
switch (chapterType) {
|
||||
case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER:
|
||||
chapter = new SimpleChapter(start, title, link, imageUrl);
|
||||
|
@ -54,6 +54,8 @@ public abstract class Chapter extends FeedComponent {
|
|||
case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER:
|
||||
chapter = new VorbisCommentChapter(start, title, link, imageUrl);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown chapter type");
|
||||
}
|
||||
chapter.setId(id);
|
||||
return chapter;
|
||||
|
|
|
@ -43,7 +43,7 @@ public class FeedItem extends FeedComponent implements Serializable {
|
|||
private Date pubDate;
|
||||
private FeedMedia media;
|
||||
|
||||
private Feed feed;
|
||||
private transient Feed feed;
|
||||
private long feedId;
|
||||
|
||||
private int state;
|
||||
|
@ -65,7 +65,7 @@ public class FeedItem extends FeedComponent implements Serializable {
|
|||
* The list of chapters of this item. This might be null even if there are chapters of this item
|
||||
* in the database. The 'hasChapters' attribute should be used to check if this item has any chapters.
|
||||
* */
|
||||
private List<Chapter> chapters;
|
||||
private transient List<Chapter> chapters;
|
||||
private String imageUrl;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package de.danoeh.antennapod.core.glide;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.bumptech.glide.Priority;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.Options;
|
||||
|
@ -36,7 +35,6 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LoadData<ByteBuffer> buildLoadData(@NonNull EmbeddedChapterImage model,
|
||||
int width,
|
||||
|
@ -65,9 +63,9 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte
|
|||
if (image.getMedia().localFileAvailable()) {
|
||||
File localFile = new File(image.getMedia().getLocalMediaUrl());
|
||||
stream = new BufferedInputStream(new FileInputStream(localFile));
|
||||
stream.skip(image.getPosition());
|
||||
IOUtils.skip(stream, image.getPosition());
|
||||
byte[] imageContent = new byte[image.getLength()];
|
||||
stream.read(imageContent, 0, image.getLength());
|
||||
IOUtils.read(stream, imageContent, 0, image.getLength());
|
||||
callback.onDataReady(ByteBuffer.wrap(imageContent));
|
||||
} else {
|
||||
Request.Builder httpReq = new Request.Builder();
|
||||
|
@ -88,10 +86,13 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte
|
|||
}
|
||||
}
|
||||
|
||||
@Override public void cleanup() {
|
||||
@Override
|
||||
public void cleanup() {
|
||||
// nothing to clean up
|
||||
}
|
||||
@Override public void cancel() {
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
// cannot cancel
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.util.Log;
|
|||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class FastBlurTransformation extends BitmapTransformation {
|
||||
|
@ -43,7 +44,7 @@ public class FastBlurTransformation extends BitmapTransformation {
|
|||
|
||||
@Override
|
||||
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
|
||||
messageDigest.update(TAG.getBytes());
|
||||
messageDigest.update(TAG.getBytes(Charset.defaultCharset()));
|
||||
}
|
||||
|
||||
private static Bitmap fastBlur(Bitmap bitmap, int radius) {
|
||||
|
|
|
@ -120,7 +120,7 @@ public class AntennapodHttpClient {
|
|||
SocketAddress address = InetSocketAddress.createUnresolved(config.host, port);
|
||||
Proxy proxy = new Proxy(config.type, address);
|
||||
builder.proxy(proxy);
|
||||
if (!TextUtils.isEmpty(config.username)) {
|
||||
if (!TextUtils.isEmpty(config.username) && config.password != null) {
|
||||
String credentials = Credentials.basic(config.username, config.password);
|
||||
builder.interceptors().add(chain -> {
|
||||
Request request = chain.request().newBuilder()
|
||||
|
|
|
@ -188,8 +188,11 @@ public class HttpDownloader extends Downloader {
|
|||
out = new RandomAccessFile(destination, "rw");
|
||||
out.seek(request.getSoFar());
|
||||
} else {
|
||||
destination.delete();
|
||||
destination.createNewFile();
|
||||
boolean success = destination.delete();
|
||||
success |= destination.createNewFile();
|
||||
if (!success) {
|
||||
throw new IOException("Unable to recreate partially downloaded file");
|
||||
}
|
||||
out = new RandomAccessFile(destination, "rw");
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ public abstract class PlaybackServiceMediaPlayer {
|
|||
* could result in nonsensical results (like a status of PLAYING, but a null playable)
|
||||
* @return the current player status
|
||||
*/
|
||||
public PlayerStatus getPlayerStatus() {
|
||||
public synchronized PlayerStatus getPlayerStatus() {
|
||||
return playerStatus;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,10 @@ public class DatabaseExporter {
|
|||
db.close();
|
||||
|
||||
File currentDB = context.getDatabasePath(PodDBAdapter.DATABASE_NAME);
|
||||
currentDB.delete();
|
||||
boolean success = currentDB.delete();
|
||||
if (!success) {
|
||||
throw new IOException("Unable to delete old database");
|
||||
}
|
||||
FileUtils.moveFile(tempDB, currentDB);
|
||||
} catch (IOException | SQLiteException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
|
|
|
@ -331,7 +331,7 @@ public class PodDBAdapter {
|
|||
PodDBAdapter.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
public static PodDBAdapter getInstance() {
|
||||
public static synchronized PodDBAdapter getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new PodDBAdapter();
|
||||
}
|
||||
|
|
|
@ -667,11 +667,11 @@ public class GpodnetService implements ISyncService {
|
|||
while ((count = in.read(buffer)) > 0) {
|
||||
outputStream.write(buffer, 0, count);
|
||||
}
|
||||
return outputStream.toString("UTF-8");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new GpodnetServiceException(e);
|
||||
}
|
||||
return outputStream.toString();
|
||||
}
|
||||
|
||||
private void checkStatusCode(@NonNull Response response) throws GpodnetServiceException {
|
||||
|
|
|
@ -34,8 +34,7 @@ import java.util.regex.Pattern;
|
|||
public class HtmlToPlainText {
|
||||
|
||||
/**
|
||||
* Use this method to strip off HTML encoding from given text
|
||||
* <p>
|
||||
* Use this method to strip off HTML encoding from given text.
|
||||
* Replaces bullet points with *, ignores colors/bold/...
|
||||
*
|
||||
* @param str String with any encoding
|
||||
|
@ -60,10 +59,8 @@ public class HtmlToPlainText {
|
|||
* @return <b>True</b> if text contains any HTML tags<br /><b>False</b> is no HTML tag is found
|
||||
*/
|
||||
private static boolean isHtml(String str) {
|
||||
final String HTML_TAG_PATTERN = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>";
|
||||
Pattern htmlValidator = TextUtils.isEmpty(HTML_TAG_PATTERN) ? null : Pattern.compile(HTML_TAG_PATTERN);
|
||||
|
||||
return htmlValidator.matcher(str).find();
|
||||
final String htmlTagPattern = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>";
|
||||
return Pattern.compile(htmlTagPattern).matcher(str).find();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,13 +23,11 @@
|
|||
package de.danoeh.antennapod.core.cast;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.ActionProvider;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.mediarouter.media.MediaRouter;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.google.android.gms.cast.ApplicationMetadata;
|
||||
|
@ -46,7 +44,6 @@ import com.google.android.gms.common.ConnectionResult;
|
|||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.CastConfiguration;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.MediaQueue;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.exceptions.OnFailedListener;
|
||||
|
@ -58,9 +55,7 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
|
@ -97,32 +92,14 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
|
||||
public static final String CAST_APP_ID = CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID;
|
||||
|
||||
public static final double DEFAULT_VOLUME_STEP = 0.05;
|
||||
public static final long DEFAULT_LIVE_STREAM_DURATION_MS = TimeUnit.HOURS.toMillis(2);
|
||||
private double volumeStep = DEFAULT_VOLUME_STEP;
|
||||
private MediaQueue mediaQueue;
|
||||
private MediaStatus mediaStatus;
|
||||
|
||||
private static CastManager INSTANCE;
|
||||
private RemoteMediaPlayer remoteMediaPlayer;
|
||||
private int state = MediaStatus.PLAYER_STATE_IDLE;
|
||||
private int idleReason;
|
||||
private final Set<CastConsumer> castConsumers = new CopyOnWriteArraySet<>();
|
||||
private long liveStreamDuration = DEFAULT_LIVE_STREAM_DURATION_MS;
|
||||
private MediaQueueItem preLoadingItem;
|
||||
|
||||
public static final int QUEUE_OPERATION_LOAD = 1;
|
||||
public static final int QUEUE_OPERATION_INSERT_ITEMS = 2;
|
||||
public static final int QUEUE_OPERATION_UPDATE_ITEMS = 3;
|
||||
public static final int QUEUE_OPERATION_JUMP = 4;
|
||||
public static final int QUEUE_OPERATION_REMOVE_ITEM = 5;
|
||||
public static final int QUEUE_OPERATION_REMOVE_ITEMS = 6;
|
||||
public static final int QUEUE_OPERATION_REORDER = 7;
|
||||
public static final int QUEUE_OPERATION_MOVE = 8;
|
||||
public static final int QUEUE_OPERATION_APPEND = 9;
|
||||
public static final int QUEUE_OPERATION_NEXT = 10;
|
||||
public static final int QUEUE_OPERATION_PREV = 11;
|
||||
public static final int QUEUE_OPERATION_SET_REPEAT = 12;
|
||||
|
||||
private CastManager(Context context, CastConfiguration castConfiguration) {
|
||||
super(context, castConfiguration);
|
||||
|
@ -176,19 +153,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
return remoteMediaPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the media that is loaded remotely is a live stream or not.
|
||||
*
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public final boolean isRemoteStreamLive() throws TransientNetworkDisconnectionException,
|
||||
NoConnectionException {
|
||||
checkConnectivity();
|
||||
MediaInfo info = getRemoteMediaInformation();
|
||||
return (info != null) && (info.getStreamType() == MediaInfo.STREAM_TYPE_LIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple check to make sure remoteMediaPlayer is not null
|
||||
*/
|
||||
|
@ -198,25 +162,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url for the media that is currently playing on the remote device. If there is no
|
||||
* connection, this will return <code>null</code>.
|
||||
*
|
||||
* @throws NoConnectionException If no connectivity to the device exists
|
||||
* @throws TransientNetworkDisconnectionException If framework is still trying to recover from
|
||||
* a possibly transient loss of network
|
||||
*/
|
||||
public String getRemoteMediaUrl() throws TransientNetworkDisconnectionException,
|
||||
NoConnectionException {
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer != null && remoteMediaPlayer.getMediaInfo() != null) {
|
||||
MediaInfo info = remoteMediaPlayer.getMediaInfo();
|
||||
remoteMediaPlayer.getMediaStatus().getPlayerState();
|
||||
return info.getContentId();
|
||||
}
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the remote media is currently playing (or buffering).
|
||||
*
|
||||
|
@ -255,20 +200,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
return isRemoteMediaPaused() || isRemoteMediaPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MediaInfo} for the current media
|
||||
*
|
||||
* @throws NoConnectionException If no connectivity to the device exists
|
||||
* @throws TransientNetworkDisconnectionException If framework is still trying to recover from
|
||||
* a possibly transient loss of network
|
||||
*/
|
||||
public MediaInfo getRemoteMediaInformation() throws TransientNetworkDisconnectionException,
|
||||
NoConnectionException {
|
||||
checkConnectivity();
|
||||
checkRemoteMediaPlayerAvailable();
|
||||
return remoteMediaPlayer.getMediaInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the remote's system volume. It internally detects what type of volume is used.
|
||||
*
|
||||
|
@ -326,30 +257,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
return remoteMediaPlayer.getMediaStatus().isMute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if remote device is muted.
|
||||
*
|
||||
* @throws NoConnectionException
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
*/
|
||||
public boolean isMute() throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
return isStreamMute() || isDeviceMute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes or un-mutes the stream volume.
|
||||
*
|
||||
* @throws CastException
|
||||
* @throws NoConnectionException
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
*/
|
||||
public void setStreamMute(boolean mute) throws CastException, TransientNetworkDisconnectionException,
|
||||
NoConnectionException {
|
||||
checkConnectivity();
|
||||
checkRemoteMediaPlayerAvailable();
|
||||
remoteMediaPlayer.setStreamMute(mApiClient, mute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the media that is loaded, in milliseconds.
|
||||
*
|
||||
|
@ -363,23 +270,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
return remoteMediaPlayer.getStreamDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time left (in milliseconds) of the current media. If there is no
|
||||
* {@code RemoteMediaPlayer}, it returns -1.
|
||||
*
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public long getMediaTimeRemaining()
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
return -1;
|
||||
}
|
||||
return isRemoteStreamLive() ? liveStreamDuration : remoteMediaPlayer.getStreamDuration()
|
||||
- remoteMediaPlayer.getApproximateStreamPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current (approximate) position of the current media, in milliseconds.
|
||||
*
|
||||
|
@ -670,435 +560,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a list of new media items into the queue.
|
||||
*
|
||||
* @param itemsToInsert List of items to insert into the queue, in the order that they should be
|
||||
* played. The itemId field of the items should be unassigned or the
|
||||
* request will fail with an INVALID_PARAMS error. Must not be {@code null}
|
||||
* or empty.
|
||||
* @param insertBeforeItemId ID of the item that will be located immediately after the inserted
|
||||
* list. If the value is {@link MediaQueueItem#INVALID_ITEM_ID} or
|
||||
* invalid, the inserted list will be appended to the end of the
|
||||
* queue.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public void queueInsertItems(final MediaQueueItem[] itemsToInsert, final int insertBeforeItemId,
|
||||
final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
Log.d(TAG, "queueInsertItems");
|
||||
checkConnectivity();
|
||||
if (itemsToInsert == null || itemsToInsert.length == 0) {
|
||||
throw new IllegalArgumentException("items cannot be empty or null");
|
||||
}
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to insert into queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueInsertItems(mApiClient, itemsToInsert, insertBeforeItemId, customData)
|
||||
.setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(
|
||||
QUEUE_OPERATION_INSERT_ITEMS,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties of a subset of the existing items in the media queue.
|
||||
*
|
||||
* @param itemsToUpdate List of queue items to be updated. The items will retain the existing
|
||||
* order and will be fully replaced with the ones provided, including the
|
||||
* media information. Any other items currently in the queue will remain
|
||||
* unchanged. The tracks information can not change once the item is loaded
|
||||
* (if the item is the currentItem). If any of the items does not exist it
|
||||
* will be ignored.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public void queueUpdateItems(final MediaQueueItem[] itemsToUpdate, final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to update the queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueUpdateItems(mApiClient, itemsToUpdate, customData).setResultCallback(
|
||||
result -> {
|
||||
Log.d(TAG, "queueUpdateItems() " + result.getStatus() + result.getStatus()
|
||||
.isSuccess());
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_UPDATE_ITEMS,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the item with {@code itemId} in the queue.
|
||||
* <p>
|
||||
* If {@code itemId} is not found in the queue, this method will report success without sending
|
||||
* a request to the receiver.
|
||||
*
|
||||
* @param itemId The ID of the item to which to jump.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public void queueJumpToItem(int itemId, final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException,
|
||||
IllegalArgumentException {
|
||||
checkConnectivity();
|
||||
if (itemId == MediaQueueItem.INVALID_ITEM_ID) {
|
||||
throw new IllegalArgumentException("itemId is not valid");
|
||||
}
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to jump in a queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueJumpToItem(mApiClient, itemId, customData).setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_JUMP,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a list of items from the queue. If the remaining queue is empty, the media session
|
||||
* will be terminated.
|
||||
*
|
||||
* @param itemIdsToRemove The list of media item IDs to remove. Must not be {@code null} or
|
||||
* empty.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public void queueRemoveItems(final int[] itemIdsToRemove, final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException,
|
||||
IllegalArgumentException {
|
||||
Log.d(TAG, "queueRemoveItems");
|
||||
checkConnectivity();
|
||||
if (itemIdsToRemove == null || itemIdsToRemove.length == 0) {
|
||||
throw new IllegalArgumentException("itemIds cannot be empty or null");
|
||||
}
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to remove items from queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueRemoveItems(mApiClient, itemIdsToRemove, customData).setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REMOVE_ITEMS,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the item with {@code itemId} from the queue.
|
||||
* <p>
|
||||
* If {@code itemId} is not found in the queue, this method will silently return without sending
|
||||
* a request to the receiver. A {@code itemId} may not be in the queue because it wasn't
|
||||
* originally in the queue, or it was removed by another sender.
|
||||
*
|
||||
* @param itemId The ID of the item to be removed.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public void queueRemoveItem(final int itemId, final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException,
|
||||
IllegalArgumentException {
|
||||
Log.d(TAG, "queueRemoveItem");
|
||||
checkConnectivity();
|
||||
if (itemId == MediaQueueItem.INVALID_ITEM_ID) {
|
||||
throw new IllegalArgumentException("itemId is invalid");
|
||||
}
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to remove an item from queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueRemoveItem(mApiClient, itemId, customData).setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REMOVE_ITEM,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder a list of media items in the queue.
|
||||
*
|
||||
* @param itemIdsToReorder The list of media item IDs to reorder, in the new order. Any other
|
||||
* items currently in the queue will maintain their existing order. The
|
||||
* list will be inserted just before the item specified by
|
||||
* {@code insertBeforeItemId}, or at the end of the queue if
|
||||
* {@code insertBeforeItemId} is {@link MediaQueueItem#INVALID_ITEM_ID}.
|
||||
* <p>
|
||||
* For example:
|
||||
* <p>
|
||||
* If insertBeforeItemId is not specified <br>
|
||||
* Existing queue: "A","D","G","H","B","E" <br>
|
||||
* itemIds: "D","H","B" <br>
|
||||
* New Order: "A","G","E","D","H","B" <br>
|
||||
* <p>
|
||||
* If insertBeforeItemId is "A" <br>
|
||||
* Existing queue: "A","D","G","H","B" <br>
|
||||
* itemIds: "D","H","B" <br>
|
||||
* New Order: "D","H","B","A","G","E" <br>
|
||||
* <p>
|
||||
* If insertBeforeItemId is "G" <br>
|
||||
* Existing queue: "A","D","G","H","B" <br>
|
||||
* itemIds: "D","H","B" <br>
|
||||
* New Order: "A","D","H","B","G","E" <br>
|
||||
* <p>
|
||||
* If any of the items does not exist it will be ignored.
|
||||
* Must not be {@code null} or empty.
|
||||
* @param insertBeforeItemId ID of the item that will be located immediately after the reordered
|
||||
* list. If set to {@link MediaQueueItem#INVALID_ITEM_ID}, the
|
||||
* reordered list will be appended at the end of the queue.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public void queueReorderItems(final int[] itemIdsToReorder, final int insertBeforeItemId,
|
||||
final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException,
|
||||
IllegalArgumentException {
|
||||
Log.d(TAG, "queueReorderItems");
|
||||
checkConnectivity();
|
||||
if (itemIdsToReorder == null || itemIdsToReorder.length == 0) {
|
||||
throw new IllegalArgumentException("itemIdsToReorder cannot be empty or null");
|
||||
}
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to reorder items in a queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueReorderItems(mApiClient, itemIdsToReorder, insertBeforeItemId, customData)
|
||||
.setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REORDER,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the item with {@code itemId} to a new position in the queue.
|
||||
* <p>
|
||||
* If {@code itemId} is not found in the queue, either because it wasn't there originally or it
|
||||
* was removed by another sender before calling this function, this function will silently
|
||||
* return without sending a request to the receiver.
|
||||
*
|
||||
* @param itemId The ID of the item to be moved.
|
||||
* @param newIndex The new index of the item. If the value is negative, an error will be
|
||||
* returned. If the value is out of bounds, or becomes out of bounds because the
|
||||
* queue was shortened by another sender while this request is in progress, the
|
||||
* item will be moved to the end of the queue.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public void queueMoveItemToNewIndex(int itemId, int newIndex, final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
Log.d(TAG, "queueMoveItemToNewIndex");
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to mote item to new index with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueMoveItemToNewIndex(mApiClient, itemId, newIndex, customData)
|
||||
.setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_MOVE,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a new media item to the end of the queue.
|
||||
*
|
||||
* @param item The item to append. Must not be {@code null}.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public void queueAppendItem(MediaQueueItem item, final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
Log.d(TAG, "queueAppendItem");
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to append item with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueAppendItem(mApiClient, item, customData)
|
||||
.setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_APPEND,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Jumps to the next item in the queue.
|
||||
*
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public void queueNext(final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
Log.d(TAG, "queueNext");
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to update the queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueNext(mApiClient, customData).setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_NEXT,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Jumps to the previous item in the queue.
|
||||
*
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public void queuePrev(final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
Log.d(TAG, "queuePrev");
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to update the queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queuePrev(mApiClient, customData).setResultCallback(
|
||||
result -> {
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_PREV,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an item in the queue and starts the playback of that newly inserted item. It is
|
||||
* assumed that we are inserting before the "current item"
|
||||
*
|
||||
* @param item The item to be inserted
|
||||
* @param insertBeforeItemId ID of the item that will be located immediately after the inserted
|
||||
* and is assumed to be the "current item"
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public void queueInsertBeforeCurrentAndPlay(MediaQueueItem item, int insertBeforeItemId,
|
||||
final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
Log.d(TAG, "queueInsertBeforeCurrentAndPlay");
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to insert into queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
if (item == null || insertBeforeItemId == MediaQueueItem.INVALID_ITEM_ID) {
|
||||
throw new IllegalArgumentException(
|
||||
"item cannot be empty or insertBeforeItemId cannot be invalid");
|
||||
}
|
||||
remoteMediaPlayer.queueInsertItems(mApiClient, new MediaQueueItem[]{item},
|
||||
insertBeforeItemId, customData).setResultCallback(
|
||||
result -> {
|
||||
if (result.getStatus().isSuccess()) {
|
||||
|
||||
try {
|
||||
queuePrev(customData);
|
||||
} catch (TransientNetworkDisconnectionException |
|
||||
NoConnectionException e) {
|
||||
Log.e(TAG, "queuePrev() Failed to skip to previous", e);
|
||||
}
|
||||
}
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_INSERT_ITEMS,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the repeat mode of the queue.
|
||||
*
|
||||
* @param repeatMode The repeat playback mode for the queue.
|
||||
* @param customData Custom application-specific data to pass along with the request. May be
|
||||
* {@code null}.
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
* @throws NoConnectionException
|
||||
*/
|
||||
public void queueSetRepeatMode(final int repeatMode, final JSONObject customData)
|
||||
throws TransientNetworkDisconnectionException, NoConnectionException {
|
||||
Log.d(TAG, "queueSetRepeatMode");
|
||||
checkConnectivity();
|
||||
if (remoteMediaPlayer == null) {
|
||||
Log.e(TAG, "Trying to update the queue with no active media session");
|
||||
throw new NoConnectionException();
|
||||
}
|
||||
remoteMediaPlayer
|
||||
.queueSetRepeatMode(mApiClient, repeatMode, customData).setResultCallback(
|
||||
result -> {
|
||||
if (!result.getStatus().isSuccess()) {
|
||||
Log.d(TAG, "Failed with status: " + result.getStatus());
|
||||
}
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueOperationResult(QUEUE_OPERATION_SET_REPEAT,
|
||||
result.getStatus().getStatusCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the loaded media.
|
||||
*
|
||||
|
@ -1294,29 +755,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the playback of the media.
|
||||
*
|
||||
* @throws CastException
|
||||
* @throws NoConnectionException
|
||||
* @throws TransientNetworkDisconnectionException
|
||||
*/
|
||||
public void togglePlayback() throws CastException, TransientNetworkDisconnectionException,
|
||||
NoConnectionException {
|
||||
checkConnectivity();
|
||||
boolean isPlaying = isRemoteMediaPlaying();
|
||||
if (isPlaying) {
|
||||
pause();
|
||||
} else {
|
||||
if (state == MediaStatus.PLAYER_STATE_IDLE
|
||||
&& idleReason == MediaStatus.IDLE_REASON_FINISHED) {
|
||||
loadMedia(getRemoteMediaInformation(), true, 0);
|
||||
} else {
|
||||
play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void attachMediaChannel() throws TransientNetworkDisconnectionException,
|
||||
NoConnectionException {
|
||||
Log.d(TAG, "attachMediaChannel()");
|
||||
|
@ -1399,22 +837,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the playback status of the remote device.
|
||||
*
|
||||
* @return Returns one of the values
|
||||
* <ul>
|
||||
* <li> <code>MediaStatus.PLAYER_STATE_UNKNOWN</code></li>
|
||||
* <li> <code>MediaStatus.PLAYER_STATE_IDLE</code></li>
|
||||
* <li> <code>MediaStatus.PLAYER_STATE_PLAYING</code></li>
|
||||
* <li> <code>MediaStatus.PLAYER_STATE_PAUSED</code></li>
|
||||
* <li> <code>MediaStatus.PLAYER_STATE_BUFFERING</code></li>
|
||||
* </ul>
|
||||
*/
|
||||
public int getPlaybackStatus() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latest retrieved value for the {@link MediaStatus}. This value is updated
|
||||
* whenever the onStatusUpdated callback is called.
|
||||
|
@ -1423,24 +845,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
return mediaStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Idle reason, defined in <code>MediaStatus.IDLE_*</code>. Note that the returned
|
||||
* value is only meaningful if the status is truly <code>MediaStatus.PLAYER_STATE_IDLE
|
||||
* </code>
|
||||
*
|
||||
* <p>Possible values are:
|
||||
* <ul>
|
||||
* <li>IDLE_REASON_NONE</li>
|
||||
* <li>IDLE_REASON_FINISHED</li>
|
||||
* <li>IDLE_REASON_CANCELED</li>
|
||||
* <li>IDLE_REASON_INTERRUPTED</li>
|
||||
* <li>IDLE_REASON_ERROR</li>
|
||||
* </ul>
|
||||
*/
|
||||
public int getIdleReason() {
|
||||
return idleReason;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by onStatusUpdated() of the RemoteMediaPlayer
|
||||
*/
|
||||
|
@ -1465,7 +869,7 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
onQueueUpdated(null, null, MediaStatus.REPEAT_MODE_REPEAT_OFF, false);
|
||||
}
|
||||
state = mediaStatus.getPlayerState();
|
||||
idleReason = mediaStatus.getIdleReason();
|
||||
int idleReason = mediaStatus.getIdleReason();
|
||||
|
||||
if (state == MediaStatus.PLAYER_STATE_PLAYING) {
|
||||
Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = playing");
|
||||
|
@ -1503,17 +907,12 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
if (mediaStatus != null) {
|
||||
item = mediaStatus.getQueueItemById(mediaStatus.getPreloadedItemId());
|
||||
}
|
||||
preLoadingItem = item;
|
||||
Log.d(TAG, "onRemoteMediaPreloadStatusUpdated() " + item);
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onRemoteMediaPreloadStatusUpdated(item);
|
||||
}
|
||||
}
|
||||
|
||||
public MediaQueueItem getPreLoadingItem() {
|
||||
return preLoadingItem;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by onQueueStatusUpdated() of RemoteMediaPlayer
|
||||
*/
|
||||
|
@ -1522,13 +921,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
Log.d(TAG, "onQueueUpdated() reached");
|
||||
Log.d(TAG, String.format(Locale.US, "Queue Items size: %d, Item: %s, Repeat Mode: %d, Shuffle: %s",
|
||||
queueItems == null ? 0 : queueItems.size(), item, repeatMode, shuffle));
|
||||
if (queueItems != null) {
|
||||
mediaQueue = new MediaQueue(new CopyOnWriteArrayList<>(queueItems), item, shuffle,
|
||||
repeatMode);
|
||||
} else {
|
||||
mediaQueue = new MediaQueue(new CopyOnWriteArrayList<>(), null, false,
|
||||
MediaStatus.REPEAT_MODE_REPEAT_OFF);
|
||||
}
|
||||
for (CastConsumer consumer : castConsumers) {
|
||||
consumer.onMediaQueueUpdated(queueItems, item, repeatMode, shuffle);
|
||||
}
|
||||
|
@ -1599,7 +991,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
super.onDisconnected(stopAppOnExit, clearPersistedConnectionData, setDefaultRoute);
|
||||
state = MediaStatus.PLAYER_STATE_IDLE;
|
||||
mediaStatus = null;
|
||||
mediaQueue = null;
|
||||
}
|
||||
|
||||
class CastListener extends Cast.Listener {
|
||||
|
@ -1634,77 +1025,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
|
|||
super.onFailed(resourceId, statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clients can call this method to delegate handling of the volume. Clients should override
|
||||
* {@code dispatchEvent} and call this method:
|
||||
* <pre>
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (mCastManager.onDispatchVolumeKeyEvent(event, VOLUME_DELTA)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
* </pre>
|
||||
* @param event The dispatched event.
|
||||
* @param volumeDelta The amount by which volume should be increased or decreased in each step
|
||||
* @return <code>true</code> if volume is handled by the library, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean onDispatchVolumeKeyEvent(KeyEvent event, double volumeDelta) {
|
||||
if (isConnected()) {
|
||||
boolean isKeyDown = event.getAction() == KeyEvent.ACTION_DOWN;
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
return changeVolume(volumeDelta, isKeyDown);
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
return changeVolume(-volumeDelta, isKeyDown);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean changeVolume(double volumeIncrement, boolean isKeyDown) {
|
||||
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||
&& getPlaybackStatus() == MediaStatus.PLAYER_STATE_PLAYING
|
||||
&& isFeatureEnabled(CastConfiguration.FEATURE_LOCKSCREEN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isKeyDown) {
|
||||
try {
|
||||
adjustDeviceVolume(volumeIncrement);
|
||||
} catch (CastException | TransientNetworkDisconnectionException |
|
||||
NoConnectionException e) {
|
||||
Log.e(TAG, "Failed to change volume", e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the volume step, i.e. the fraction by which volume will increase or decrease each time
|
||||
* user presses the hard volume buttons on the device.
|
||||
*
|
||||
* @param volumeStep Should be a double between 0 and 1, inclusive.
|
||||
*/
|
||||
public CastManager setVolumeStep(double volumeStep) {
|
||||
if ((volumeStep > 1) || (volumeStep < 0)) {
|
||||
throw new IllegalArgumentException("Volume Step should be between 0 and 1, inclusive");
|
||||
}
|
||||
this.volumeStep = volumeStep;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the volume step. The default value is {@code DEFAULT_VOLUME_STEP}.
|
||||
*/
|
||||
public double getVolumeStep() {
|
||||
return volumeStep;
|
||||
}
|
||||
|
||||
public final MediaQueue getMediaQueue() {
|
||||
return mediaQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the selected Cast Device has the specified audio or video capabilities.
|
||||
*
|
||||
|
|
|
@ -35,7 +35,6 @@ public class CastUtils {
|
|||
public static final String KEY_FEED_URL = "de.danoeh.antennapod.core.cast.FeedUrl";
|
||||
public static final String KEY_FEED_WEBSITE = "de.danoeh.antennapod.core.cast.FeedWebsite";
|
||||
public static final String KEY_EPISODE_NOTES = "de.danoeh.antennapod.core.cast.EpisodeNotes";
|
||||
public static final int EPISODE_NOTES_MAX_LENGTH = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* The field <code>AntennaPod.FormatVersion</code> specifies which version of MediaMetaData
|
||||
|
|
|
@ -39,9 +39,6 @@ public class MediaInfoCreator {
|
|||
}
|
||||
String notes = media.getNotes();
|
||||
if (notes != null) {
|
||||
if (notes.length() > CastUtils.EPISODE_NOTES_MAX_LENGTH) {
|
||||
notes = notes.substring(0, CastUtils.EPISODE_NOTES_MAX_LENGTH);
|
||||
}
|
||||
metadata.putString(CastUtils.KEY_EPISODE_NOTES, notes);
|
||||
}
|
||||
// Default id value
|
||||
|
|
|
@ -6,10 +6,12 @@ import javax.net.ssl.TrustManager;
|
|||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -52,7 +54,7 @@ public class BackportTrustManager {
|
|||
managers.add(getSystemTrustManager(keystore));
|
||||
managers.add(getSystemTrustManager(null));
|
||||
return new CompositeX509TrustManager(managers);
|
||||
} catch (Exception e) {
|
||||
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue