2017-02-27 21:14:03 +01:00
|
|
|
package org.schabi.newpipe;
|
|
|
|
|
2021-10-02 19:21:25 +02:00
|
|
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
|
|
|
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
|
|
|
|
|
2018-06-17 13:55:43 +02:00
|
|
|
import android.annotation.SuppressLint;
|
2018-02-12 19:44:35 +01:00
|
|
|
import android.app.IntentService;
|
2018-04-06 11:02:51 +02:00
|
|
|
import android.content.Context;
|
2018-02-12 19:44:35 +01:00
|
|
|
import android.content.DialogInterface;
|
2017-02-27 21:14:03 +01:00
|
|
|
import android.content.Intent;
|
2018-02-12 19:44:35 +01:00
|
|
|
import android.content.SharedPreferences;
|
2018-06-20 14:46:57 +02:00
|
|
|
import android.content.pm.PackageManager;
|
2022-12-02 18:31:01 +01:00
|
|
|
import android.os.Build;
|
2017-02-27 21:14:03 +01:00
|
|
|
import android.os.Bundle;
|
2018-01-23 01:40:00 +01:00
|
|
|
import android.text.TextUtils;
|
2018-02-12 19:44:35 +01:00
|
|
|
import android.view.ContextThemeWrapper;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
2022-10-15 21:10:37 +02:00
|
|
|
import android.view.WindowManager;
|
2018-02-12 19:44:35 +01:00
|
|
|
import android.widget.Button;
|
|
|
|
import android.widget.RadioButton;
|
|
|
|
import android.widget.RadioGroup;
|
2017-02-27 21:14:03 +01:00
|
|
|
import android.widget.Toast;
|
|
|
|
|
2020-03-27 03:18:14 +01:00
|
|
|
import androidx.annotation.DrawableRes;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2022-05-02 22:37:51 +02:00
|
|
|
import androidx.annotation.StringRes;
|
2020-03-27 03:18:14 +01:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
|
|
|
import androidx.appcompat.app.AppCompatActivity;
|
2020-04-01 15:15:38 +02:00
|
|
|
import androidx.appcompat.content.res.AppCompatResources;
|
2020-03-27 03:18:14 +01:00
|
|
|
import androidx.core.app.NotificationCompat;
|
2020-12-19 12:22:17 +01:00
|
|
|
import androidx.core.app.ServiceCompat;
|
2022-07-18 05:30:11 +02:00
|
|
|
import androidx.core.math.MathUtils;
|
2022-12-02 10:25:06 +01:00
|
|
|
import androidx.fragment.app.DialogFragment;
|
2022-10-15 20:32:41 +02:00
|
|
|
import androidx.fragment.app.Fragment;
|
2019-10-04 14:59:08 +02:00
|
|
|
import androidx.fragment.app.FragmentManager;
|
2022-12-07 14:43:27 +01:00
|
|
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
|
|
|
import androidx.lifecycle.Lifecycle;
|
|
|
|
import androidx.lifecycle.LifecycleOwner;
|
2020-10-22 02:15:27 +02:00
|
|
|
import androidx.preference.PreferenceManager;
|
2019-10-04 14:59:08 +02:00
|
|
|
|
2021-10-09 18:46:20 +02:00
|
|
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
2020-10-31 10:06:12 +01:00
|
|
|
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
|
|
|
|
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
|
2018-06-17 13:55:43 +02:00
|
|
|
import org.schabi.newpipe.download.DownloadDialog;
|
2023-09-18 01:54:03 +02:00
|
|
|
import org.schabi.newpipe.download.LoadingDialog;
|
2020-12-11 14:55:47 +01:00
|
|
|
import org.schabi.newpipe.error.ErrorInfo;
|
2021-12-01 09:43:24 +01:00
|
|
|
import org.schabi.newpipe.error.ErrorUtil;
|
2020-12-11 14:55:47 +01:00
|
|
|
import org.schabi.newpipe.error.ReCaptchaActivity;
|
|
|
|
import org.schabi.newpipe.error.UserAction;
|
2018-02-12 19:44:35 +01:00
|
|
|
import org.schabi.newpipe.extractor.Info;
|
|
|
|
import org.schabi.newpipe.extractor.NewPipe;
|
|
|
|
import org.schabi.newpipe.extractor.StreamingService;
|
|
|
|
import org.schabi.newpipe.extractor.StreamingService.LinkType;
|
|
|
|
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
2020-12-11 14:55:47 +01:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
2018-01-23 01:40:00 +01:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
2020-12-11 14:55:47 +01:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.PaidContentException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.PrivateContentException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException;
|
2023-04-14 10:19:58 +02:00
|
|
|
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
2018-02-12 19:44:35 +01:00
|
|
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
|
|
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
2020-12-11 14:55:47 +01:00
|
|
|
import org.schabi.newpipe.ktx.ExceptionUtils;
|
2021-10-09 18:46:20 +02:00
|
|
|
import org.schabi.newpipe.local.dialog.PlaylistDialog;
|
2022-07-10 23:05:37 +02:00
|
|
|
import org.schabi.newpipe.player.PlayerType;
|
2020-09-09 20:45:42 +02:00
|
|
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
2020-10-18 20:33:08 +02:00
|
|
|
import org.schabi.newpipe.player.helper.PlayerHolder;
|
2023-04-14 10:19:58 +02:00
|
|
|
import org.schabi.newpipe.player.playqueue.ChannelTabPlayQueue;
|
2018-04-21 23:10:01 +02:00
|
|
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
|
|
|
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
|
|
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
2023-04-14 10:19:58 +02:00
|
|
|
import org.schabi.newpipe.util.ChannelTabHelper;
|
2018-12-24 19:11:21 +01:00
|
|
|
import org.schabi.newpipe.util.Constants;
|
2020-10-22 02:15:27 +02:00
|
|
|
import org.schabi.newpipe.util.DeviceUtils;
|
2018-01-23 01:40:00 +01:00
|
|
|
import org.schabi.newpipe.util.ExtractorHelper;
|
2022-05-04 19:09:41 +02:00
|
|
|
import org.schabi.newpipe.util.Localization;
|
2017-04-09 19:34:00 +02:00
|
|
|
import org.schabi.newpipe.util.NavigationHelper;
|
2018-02-12 19:44:35 +01:00
|
|
|
import org.schabi.newpipe.util.PermissionHelper;
|
|
|
|
import org.schabi.newpipe.util.ThemeHelper;
|
2021-10-02 19:21:25 +02:00
|
|
|
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
2020-03-27 03:18:14 +01:00
|
|
|
import org.schabi.newpipe.util.urlfinder.UrlFinder;
|
2020-05-01 20:13:01 +02:00
|
|
|
import org.schabi.newpipe.views.FocusOverlayView;
|
2017-02-27 21:14:03 +01:00
|
|
|
|
2018-02-12 19:44:35 +01:00
|
|
|
import java.io.Serializable;
|
2023-01-11 15:26:46 +01:00
|
|
|
import java.lang.ref.Reference;
|
2022-12-02 15:22:00 +01:00
|
|
|
import java.lang.ref.WeakReference;
|
2018-04-06 11:02:51 +02:00
|
|
|
import java.util.ArrayList;
|
2018-02-12 19:44:35 +01:00
|
|
|
import java.util.Arrays;
|
2018-04-06 11:02:51 +02:00
|
|
|
import java.util.List;
|
2023-01-11 15:08:10 +01:00
|
|
|
import java.util.Optional;
|
|
|
|
import java.util.function.Consumer;
|
2017-02-27 21:14:03 +01:00
|
|
|
|
2018-01-23 01:40:00 +01:00
|
|
|
import icepick.Icepick;
|
|
|
|
import icepick.State;
|
2020-10-31 21:55:45 +01:00
|
|
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
|
|
import io.reactivex.rxjava3.core.Observable;
|
|
|
|
import io.reactivex.rxjava3.core.Single;
|
|
|
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
|
|
import io.reactivex.rxjava3.disposables.Disposable;
|
|
|
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
2018-01-23 01:40:00 +01:00
|
|
|
|
2017-02-27 21:14:03 +01:00
|
|
|
/**
|
2020-03-31 19:20:15 +02:00
|
|
|
* Get the url from the intent and open it in the chosen preferred player.
|
2017-02-27 21:14:03 +01:00
|
|
|
*/
|
2017-09-03 08:04:18 +02:00
|
|
|
public class RouterActivity extends AppCompatActivity {
|
2020-03-31 19:20:15 +02:00
|
|
|
protected final CompositeDisposable disposables = new CompositeDisposable();
|
2019-08-15 04:00:11 +02:00
|
|
|
@State
|
|
|
|
protected int currentServiceId = -1;
|
|
|
|
@State
|
|
|
|
protected LinkType currentLinkType;
|
|
|
|
@State
|
|
|
|
protected int selectedRadioPosition = -1;
|
2018-02-12 19:44:35 +01:00
|
|
|
protected int selectedPreviously = -1;
|
2018-01-23 01:40:00 +01:00
|
|
|
protected String currentUrl;
|
2020-03-31 19:20:15 +02:00
|
|
|
private StreamingService currentService;
|
2018-06-20 14:46:57 +02:00
|
|
|
private boolean selectionIsDownload = false;
|
2021-10-02 19:21:25 +02:00
|
|
|
private boolean selectionIsAddToPlaylist = false;
|
2021-05-25 07:49:49 +02:00
|
|
|
private AlertDialog alertDialogChoice = null;
|
2022-12-02 10:25:06 +01:00
|
|
|
private FragmentManager.FragmentLifecycleCallbacks dismissListener = null;
|
2018-06-17 13:55:43 +02:00
|
|
|
|
2017-02-27 21:14:03 +01:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
protected void onCreate(final Bundle savedInstanceState) {
|
2022-10-15 17:34:39 +02:00
|
|
|
ThemeHelper.setDayNightMode(this);
|
|
|
|
setTheme(ThemeHelper.isLightThemeSelected(this)
|
|
|
|
? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
|
|
|
|
Localization.assureCorrectAppLanguage(this);
|
|
|
|
|
2022-10-15 21:10:37 +02:00
|
|
|
// Pass-through touch events to background activities
|
|
|
|
// so that our transparent window won't lock UI in the mean time
|
|
|
|
// network request is underway before showing PlaylistDialog or DownloadDialog
|
2022-12-02 07:13:54 +01:00
|
|
|
// (ref: https://stackoverflow.com/a/10606141)
|
2022-10-15 21:10:37 +02:00
|
|
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
|
|
|
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
|
|
|
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
|
|
|
|
|
2022-12-02 07:13:54 +01:00
|
|
|
// Android never fails to impress us with a list of new restrictions per API.
|
|
|
|
// Starting with S (Android 12) one of the prerequisite conditions has to be met
|
|
|
|
// before the FLAG_NOT_TOUCHABLE flag is allowed to kick in:
|
|
|
|
// @see WindowManager.LayoutParams#FLAG_NOT_TOUCHABLE
|
|
|
|
// For our present purpose it seems we can just set LayoutParams.alpha to 0
|
|
|
|
// on the strength of "4. Fully transparent windows" without affecting the scrim of dialogs
|
|
|
|
final WindowManager.LayoutParams params = getWindow().getAttributes();
|
|
|
|
params.alpha = 0f;
|
|
|
|
getWindow().setAttributes(params);
|
|
|
|
|
2017-02-27 21:14:03 +01:00
|
|
|
super.onCreate(savedInstanceState);
|
2018-01-23 01:40:00 +01:00
|
|
|
Icepick.restoreInstanceState(this, savedInstanceState);
|
2017-06-05 21:33:01 +02:00
|
|
|
|
2022-12-02 10:25:06 +01:00
|
|
|
// FragmentManager will take care to recreate (Playlist|Download)Dialog when screen rotates
|
|
|
|
// We used to .setOnDismissListener(dialog -> finish()); when creating these DialogFragments
|
|
|
|
// but those callbacks won't survive a config change
|
|
|
|
// Try an alternate approach to hook into FragmentManager instead, to that effect
|
|
|
|
// (ref: https://stackoverflow.com/a/44028453)
|
|
|
|
final FragmentManager fm = getSupportFragmentManager();
|
|
|
|
if (dismissListener == null) {
|
|
|
|
dismissListener = new FragmentManager.FragmentLifecycleCallbacks() {
|
|
|
|
@Override
|
|
|
|
public void onFragmentDestroyed(@NonNull final FragmentManager fm,
|
|
|
|
@NonNull final Fragment f) {
|
|
|
|
super.onFragmentDestroyed(fm, f);
|
|
|
|
if (f instanceof DialogFragment && fm.getFragments().isEmpty()) {
|
|
|
|
// No more DialogFragments, we're done
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
fm.registerFragmentLifecycleCallbacks(dismissListener, false);
|
|
|
|
|
2018-01-23 01:40:00 +01:00
|
|
|
if (TextUtils.isEmpty(currentUrl)) {
|
|
|
|
currentUrl = getUrl(getIntent());
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(currentUrl)) {
|
2018-12-24 19:11:21 +01:00
|
|
|
handleText();
|
2018-01-23 01:40:00 +01:00
|
|
|
finish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-25 07:49:49 +02:00
|
|
|
@Override
|
|
|
|
protected void onStop() {
|
|
|
|
super.onStop();
|
|
|
|
// we need to dismiss the dialog before leaving the activity or we get leaks
|
|
|
|
if (alertDialogChoice != null) {
|
|
|
|
alertDialogChoice.dismiss();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 01:40:00 +01:00
|
|
|
@Override
|
2020-12-11 14:55:47 +01:00
|
|
|
protected void onSaveInstanceState(@NonNull final Bundle outState) {
|
2018-06-20 14:46:57 +02:00
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
Icepick.saveInstanceState(this, outState);
|
2018-01-23 01:40:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onStart() {
|
|
|
|
super.onStart();
|
2018-12-24 19:11:21 +01:00
|
|
|
|
2022-10-15 20:32:41 +02:00
|
|
|
// Don't overlap the DialogFragment after rotating the screen
|
|
|
|
// If there's no DialogFragment, we're either starting afresh
|
|
|
|
// or we didn't make it to PlaylistDialog or DownloadDialog before the orientation change
|
2022-12-02 10:25:06 +01:00
|
|
|
if (getSupportFragmentManager().getFragments().isEmpty()) {
|
2022-10-15 20:32:41 +02:00
|
|
|
// Start over from scratch
|
|
|
|
handleUrl(currentUrl);
|
|
|
|
}
|
2017-02-27 21:14:03 +01:00
|
|
|
}
|
|
|
|
|
2018-02-12 19:44:35 +01:00
|
|
|
@Override
|
|
|
|
protected void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
|
2022-12-02 10:25:06 +01:00
|
|
|
if (dismissListener != null) {
|
|
|
|
getSupportFragmentManager().unregisterFragmentLifecycleCallbacks(dismissListener);
|
|
|
|
}
|
2022-12-07 14:43:27 +01:00
|
|
|
|
2018-02-12 19:44:35 +01:00
|
|
|
disposables.clear();
|
|
|
|
}
|
|
|
|
|
2022-10-15 19:01:19 +02:00
|
|
|
@Override
|
|
|
|
public void finish() {
|
|
|
|
// allow the activity to recreate in case orientation changes
|
|
|
|
if (!isChangingConfigurations()) {
|
|
|
|
super.finish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private void handleUrl(final String url) {
|
2018-01-23 01:40:00 +01:00
|
|
|
disposables.add(Observable
|
2018-02-12 19:44:35 +01:00
|
|
|
.fromCallable(() -> {
|
2021-03-07 18:59:17 +01:00
|
|
|
try {
|
|
|
|
if (currentServiceId == -1) {
|
|
|
|
currentService = NewPipe.getServiceByUrl(url);
|
|
|
|
currentServiceId = currentService.getServiceId();
|
|
|
|
currentLinkType = currentService.getLinkTypeByUrl(url);
|
|
|
|
currentUrl = url;
|
|
|
|
} else {
|
|
|
|
currentService = NewPipe.getService(currentServiceId);
|
|
|
|
}
|
|
|
|
|
|
|
|
// return whether the url was found to be supported or not
|
|
|
|
return currentLinkType != LinkType.NONE;
|
|
|
|
} catch (final ExtractionException e) {
|
|
|
|
// this can be reached only when the url is completely unsupported
|
|
|
|
return false;
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
})
|
2018-01-23 01:40:00 +01:00
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2021-03-07 18:59:17 +01:00
|
|
|
.subscribe(isUrlSupported -> {
|
|
|
|
if (isUrlSupported) {
|
2018-02-12 19:44:35 +01:00
|
|
|
onSuccess();
|
|
|
|
} else {
|
2020-06-28 13:33:08 +02:00
|
|
|
showUnsupportedUrlDialog(url);
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
2021-03-07 18:59:17 +01:00
|
|
|
}, throwable -> handleError(this, new ErrorInfo(throwable,
|
|
|
|
UserAction.SHARE_TO_NEWPIPE, "Getting service from url: " + url))));
|
2018-01-23 01:40:00 +01:00
|
|
|
}
|
|
|
|
|
2020-12-11 14:55:47 +01:00
|
|
|
/**
|
2021-03-07 18:59:17 +01:00
|
|
|
* @param context the context. It will be {@code finish()}ed at the end of the handling if it is
|
|
|
|
* an instance of {@link RouterActivity}.
|
|
|
|
* @param errorInfo the error information
|
2020-12-11 14:55:47 +01:00
|
|
|
*/
|
|
|
|
private static void handleError(final Context context, final ErrorInfo errorInfo) {
|
|
|
|
if (errorInfo.getThrowable() != null) {
|
|
|
|
errorInfo.getThrowable().printStackTrace();
|
|
|
|
}
|
2018-01-23 01:40:00 +01:00
|
|
|
|
2020-12-11 14:55:47 +01:00
|
|
|
if (errorInfo.getThrowable() instanceof ReCaptchaException) {
|
|
|
|
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
|
|
|
// Starting ReCaptcha Challenge Activity
|
|
|
|
final Intent intent = new Intent(context, ReCaptchaActivity.class);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
context.startActivity(intent);
|
|
|
|
} else if (errorInfo.getThrowable() != null
|
|
|
|
&& ExceptionUtils.isNetworkRelated(errorInfo.getThrowable())) {
|
|
|
|
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof AgeRestrictedContentException) {
|
|
|
|
Toast.makeText(context, R.string.restricted_video_no_stream,
|
|
|
|
Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof GeographicRestrictionException) {
|
|
|
|
Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof PaidContentException) {
|
|
|
|
Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof PrivateContentException) {
|
|
|
|
Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof SoundCloudGoPlusContentException) {
|
|
|
|
Toast.makeText(context, R.string.soundcloud_go_plus_content,
|
|
|
|
Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof YoutubeMusicPremiumContentException) {
|
|
|
|
Toast.makeText(context, R.string.youtube_music_premium_content,
|
|
|
|
Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof ContentNotAvailableException) {
|
|
|
|
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
|
|
|
|
} else if (errorInfo.getThrowable() instanceof ContentNotSupportedException) {
|
|
|
|
Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show();
|
2018-01-23 01:40:00 +01:00
|
|
|
} else {
|
2021-12-01 09:43:24 +01:00
|
|
|
ErrorUtil.createNotification(context, errorInfo);
|
2020-12-11 14:55:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (context instanceof RouterActivity) {
|
|
|
|
((RouterActivity) context).finish();
|
2017-06-05 21:33:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-02 15:22:00 +01:00
|
|
|
protected void showUnsupportedUrlDialog(final String url) {
|
2020-06-28 13:33:08 +02:00
|
|
|
final Context context = getThemeWrapperContext();
|
|
|
|
new AlertDialog.Builder(context)
|
|
|
|
.setTitle(R.string.unsupported_url)
|
|
|
|
.setMessage(R.string.unsupported_url_dialog_message)
|
2021-03-27 15:45:49 +01:00
|
|
|
.setIcon(R.drawable.ic_share)
|
2020-06-28 13:33:08 +02:00
|
|
|
.setPositiveButton(R.string.open_in_browser,
|
|
|
|
(dialog, which) -> ShareUtils.openUrlInBrowser(this, url))
|
|
|
|
.setNegativeButton(R.string.share,
|
2021-04-25 14:14:56 +02:00
|
|
|
(dialog, which) -> ShareUtils.shareText(this, "", url)) // no subject
|
2020-06-28 13:33:08 +02:00
|
|
|
.setNeutralButton(R.string.cancel, null)
|
|
|
|
.setOnDismissListener(dialog -> finish())
|
|
|
|
.show();
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
2018-01-23 01:40:00 +01:00
|
|
|
|
2018-02-12 19:44:35 +01:00
|
|
|
protected void onSuccess() {
|
2020-03-31 19:20:15 +02:00
|
|
|
final SharedPreferences preferences = PreferenceManager
|
|
|
|
.getDefaultSharedPreferences(this);
|
2022-05-02 22:37:51 +02:00
|
|
|
|
|
|
|
final ChoiceAvailabilityChecker choiceChecker = new ChoiceAvailabilityChecker(
|
|
|
|
getChoicesForService(currentService, currentLinkType),
|
|
|
|
preferences.getString(getString(R.string.preferred_open_action_key),
|
|
|
|
getString(R.string.preferred_open_action_default)));
|
|
|
|
|
|
|
|
// Check for non-player related choices
|
|
|
|
if (choiceChecker.isAvailableAndSelected(
|
|
|
|
R.string.show_info_key,
|
|
|
|
R.string.download_key,
|
|
|
|
R.string.add_to_playlist_key)) {
|
|
|
|
handleChoice(choiceChecker.getSelectedChoiceKey());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Check if the choice is player related
|
|
|
|
if (choiceChecker.isAvailableAndSelected(
|
|
|
|
R.string.video_player_key,
|
|
|
|
R.string.background_player_key,
|
|
|
|
R.string.popup_player_key)) {
|
|
|
|
|
|
|
|
final String selectedChoice = choiceChecker.getSelectedChoiceKey();
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
final boolean isExtVideoEnabled = preferences.getBoolean(
|
|
|
|
getString(R.string.use_external_video_player_key), false);
|
|
|
|
final boolean isExtAudioEnabled = preferences.getBoolean(
|
|
|
|
getString(R.string.use_external_audio_player_key), false);
|
2022-05-01 22:46:15 +02:00
|
|
|
final boolean isVideoPlayerSelected =
|
2022-05-02 22:37:51 +02:00
|
|
|
selectedChoice.equals(getString(R.string.video_player_key))
|
|
|
|
|| selectedChoice.equals(getString(R.string.popup_player_key));
|
2022-05-01 22:46:15 +02:00
|
|
|
final boolean isAudioPlayerSelected =
|
2022-05-02 22:37:51 +02:00
|
|
|
selectedChoice.equals(getString(R.string.background_player_key));
|
2018-04-18 16:44:46 +02:00
|
|
|
|
2022-05-01 22:46:15 +02:00
|
|
|
if (currentLinkType != LinkType.STREAM
|
2022-05-03 19:19:21 +02:00
|
|
|
&& ((isExtAudioEnabled && isAudioPlayerSelected)
|
|
|
|
|| (isExtVideoEnabled && isVideoPlayerSelected))
|
2022-05-01 22:46:15 +02:00
|
|
|
) {
|
|
|
|
Toast.makeText(this, R.string.external_player_unsupported_link_type,
|
|
|
|
Toast.LENGTH_LONG).show();
|
2022-05-02 22:37:51 +02:00
|
|
|
handleChoice(getString(R.string.show_info_key));
|
2022-05-01 22:46:15 +02:00
|
|
|
return;
|
2018-04-18 16:44:46 +02:00
|
|
|
}
|
|
|
|
|
2022-05-01 22:46:15 +02:00
|
|
|
final List<StreamingService.ServiceInfo.MediaCapability> capabilities =
|
|
|
|
currentService.getServiceInfo().getMediaCapabilities();
|
2018-04-18 16:44:46 +02:00
|
|
|
|
2022-05-02 22:37:51 +02:00
|
|
|
// Check if the service supports the choice
|
2022-05-03 19:19:21 +02:00
|
|
|
if ((isVideoPlayerSelected && capabilities.contains(VIDEO))
|
|
|
|
|| (isAudioPlayerSelected && capabilities.contains(AUDIO))) {
|
2022-05-02 22:37:51 +02:00
|
|
|
handleChoice(selectedChoice);
|
|
|
|
} else {
|
|
|
|
handleChoice(getString(R.string.show_info_key));
|
2018-04-18 16:44:46 +02:00
|
|
|
}
|
2022-05-02 22:37:51 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-04-18 16:44:46 +02:00
|
|
|
|
2022-05-02 22:37:51 +02:00
|
|
|
// Default / Ask always
|
|
|
|
final List<AdapterChoiceItem> availableChoices = choiceChecker.getAvailableChoices();
|
|
|
|
switch (availableChoices.size()) {
|
|
|
|
case 1:
|
|
|
|
handleChoice(availableChoices.get(0).key);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
handleChoice(getString(R.string.show_info_key));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
showDialog(availableChoices);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is a helper class for checking if the choices are available and/or selected.
|
|
|
|
*/
|
|
|
|
class ChoiceAvailabilityChecker {
|
|
|
|
private final List<AdapterChoiceItem> availableChoices;
|
|
|
|
private final String selectedChoiceKey;
|
|
|
|
|
|
|
|
ChoiceAvailabilityChecker(
|
|
|
|
@NonNull final List<AdapterChoiceItem> availableChoices,
|
|
|
|
@NonNull final String selectedChoiceKey) {
|
|
|
|
this.availableChoices = availableChoices;
|
|
|
|
this.selectedChoiceKey = selectedChoiceKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<AdapterChoiceItem> getAvailableChoices() {
|
|
|
|
return availableChoices;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getSelectedChoiceKey() {
|
|
|
|
return selectedChoiceKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isAvailableAndSelected(@StringRes final int... wantedKeys) {
|
|
|
|
return Arrays.stream(wantedKeys).anyMatch(this::isAvailableAndSelected);
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isAvailableAndSelected(@StringRes final int wantedKey) {
|
|
|
|
final String wanted = getString(wantedKey);
|
|
|
|
// Check if the wanted option is selected
|
|
|
|
if (!selectedChoiceKey.equals(wanted)) {
|
|
|
|
return false;
|
2018-04-18 16:44:46 +02:00
|
|
|
}
|
2022-05-02 22:37:51 +02:00
|
|
|
// Check if it's available
|
|
|
|
return availableChoices.stream().anyMatch(item -> wanted.equals(item.key));
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-18 16:44:46 +02:00
|
|
|
private void showDialog(final List<AdapterChoiceItem> choices) {
|
2018-04-06 11:02:51 +02:00
|
|
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
2022-05-28 00:39:02 +02:00
|
|
|
|
2018-04-18 16:44:46 +02:00
|
|
|
final Context themeWrapperContext = getThemeWrapperContext();
|
2022-05-28 00:39:02 +02:00
|
|
|
final LayoutInflater layoutInflater = LayoutInflater.from(themeWrapperContext);
|
2018-02-12 19:44:35 +01:00
|
|
|
|
2022-05-28 00:39:02 +02:00
|
|
|
final SingleChoiceDialogViewBinding binding =
|
|
|
|
SingleChoiceDialogViewBinding.inflate(layoutInflater);
|
|
|
|
final RadioGroup radioGroup = binding.list;
|
2018-02-12 19:44:35 +01:00
|
|
|
|
|
|
|
final DialogInterface.OnClickListener dialogButtonsClickListener = (dialog, which) -> {
|
|
|
|
final int indexOfChild = radioGroup.indexOfChild(
|
|
|
|
radioGroup.findViewById(radioGroup.getCheckedRadioButtonId()));
|
2018-04-06 11:02:51 +02:00
|
|
|
final AdapterChoiceItem choice = choices.get(indexOfChild);
|
2018-02-12 19:44:35 +01:00
|
|
|
|
|
|
|
handleChoice(choice.key);
|
|
|
|
|
2020-09-09 20:45:42 +02:00
|
|
|
// open future streams always like this one, because "always" button was used by user
|
2018-02-12 19:44:35 +01:00
|
|
|
if (which == DialogInterface.BUTTON_POSITIVE) {
|
2020-03-31 19:20:15 +02:00
|
|
|
preferences.edit()
|
|
|
|
.putString(getString(R.string.preferred_open_action_key), choice.key)
|
|
|
|
.apply();
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-05-25 07:49:49 +02:00
|
|
|
alertDialogChoice = new AlertDialog.Builder(themeWrapperContext)
|
2018-04-07 20:36:52 +02:00
|
|
|
.setTitle(R.string.preferred_open_action_share_menu_title)
|
2022-05-28 00:39:02 +02:00
|
|
|
.setView(binding.getRoot())
|
2018-02-12 19:44:35 +01:00
|
|
|
.setCancelable(true)
|
|
|
|
.setNegativeButton(R.string.just_once, dialogButtonsClickListener)
|
|
|
|
.setPositiveButton(R.string.always, dialogButtonsClickListener)
|
2022-05-28 00:16:27 +02:00
|
|
|
.setOnDismissListener(dialog -> {
|
2021-10-02 19:21:25 +02:00
|
|
|
if (!selectionIsDownload && !selectionIsAddToPlaylist) {
|
2020-03-31 19:20:15 +02:00
|
|
|
finish();
|
|
|
|
}
|
2018-06-17 13:55:43 +02:00
|
|
|
})
|
2018-02-12 19:44:35 +01:00
|
|
|
.create();
|
|
|
|
|
2022-05-28 00:16:27 +02:00
|
|
|
alertDialogChoice.setOnShowListener(dialog -> setDialogButtonsState(
|
|
|
|
alertDialogChoice, radioGroup.getCheckedRadioButtonId() != -1));
|
2018-02-12 19:44:35 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
radioGroup.setOnCheckedChangeListener((group, checkedId) ->
|
2021-05-25 07:49:49 +02:00
|
|
|
setDialogButtonsState(alertDialogChoice, true));
|
2018-02-12 19:44:35 +01:00
|
|
|
final View.OnClickListener radioButtonsClickListener = v -> {
|
|
|
|
final int indexOfChild = radioGroup.indexOfChild(v);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (indexOfChild == -1) {
|
|
|
|
return;
|
|
|
|
}
|
2018-02-12 19:44:35 +01:00
|
|
|
|
|
|
|
selectedPreviously = selectedRadioPosition;
|
|
|
|
selectedRadioPosition = indexOfChild;
|
|
|
|
|
|
|
|
if (selectedPreviously == selectedRadioPosition) {
|
2018-04-06 11:02:51 +02:00
|
|
|
handleChoice(choices.get(selectedRadioPosition).key);
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
int id = 12345;
|
2020-08-16 10:24:58 +02:00
|
|
|
for (final AdapterChoiceItem item : choices) {
|
2022-05-28 00:39:02 +02:00
|
|
|
final RadioButton radioButton = ListRadioIconItemBinding.inflate(layoutInflater)
|
|
|
|
.getRoot();
|
2018-02-12 19:44:35 +01:00
|
|
|
radioButton.setText(item.description);
|
2022-05-10 04:15:01 +02:00
|
|
|
radioButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
2021-04-24 00:31:02 +02:00
|
|
|
AppCompatResources.getDrawable(themeWrapperContext, item.icon),
|
2020-04-01 15:15:38 +02:00
|
|
|
null, null, null);
|
2018-02-12 19:44:35 +01:00
|
|
|
radioButton.setChecked(false);
|
|
|
|
radioButton.setId(id++);
|
2020-03-31 19:20:15 +02:00
|
|
|
radioButton.setLayoutParams(new RadioGroup.LayoutParams(
|
|
|
|
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
2018-02-12 19:44:35 +01:00
|
|
|
radioButton.setOnClickListener(radioButtonsClickListener);
|
|
|
|
radioGroup.addView(radioButton);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectedRadioPosition == -1) {
|
2020-03-31 19:20:15 +02:00
|
|
|
final String lastSelectedPlayer = preferences.getString(
|
|
|
|
getString(R.string.preferred_open_action_last_selected_key), null);
|
2018-02-12 19:44:35 +01:00
|
|
|
if (!TextUtils.isEmpty(lastSelectedPlayer)) {
|
2018-04-06 11:02:51 +02:00
|
|
|
for (int i = 0; i < choices.size(); i++) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final AdapterChoiceItem c = choices.get(i);
|
2018-02-12 19:44:35 +01:00
|
|
|
if (lastSelectedPlayer.equals(c.key)) {
|
|
|
|
selectedRadioPosition = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-18 05:30:11 +02:00
|
|
|
selectedRadioPosition = MathUtils.clamp(selectedRadioPosition, -1, choices.size() - 1);
|
2018-02-12 19:44:35 +01:00
|
|
|
if (selectedRadioPosition != -1) {
|
|
|
|
((RadioButton) radioGroup.getChildAt(selectedRadioPosition)).setChecked(true);
|
|
|
|
}
|
|
|
|
selectedPreviously = selectedRadioPosition;
|
|
|
|
|
2021-05-25 07:49:49 +02:00
|
|
|
alertDialogChoice.show();
|
2019-09-23 09:17:03 +02:00
|
|
|
|
2020-07-21 00:43:49 +02:00
|
|
|
if (DeviceUtils.isTv(this)) {
|
2021-05-25 07:49:49 +02:00
|
|
|
FocusOverlayView.setupFocusObserver(alertDialogChoice);
|
2019-09-23 09:17:03 +02:00
|
|
|
}
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private List<AdapterChoiceItem> getChoicesForService(final StreamingService service,
|
|
|
|
final LinkType linkType) {
|
2020-09-09 20:45:42 +02:00
|
|
|
final AdapterChoiceItem showInfo = new AdapterChoiceItem(
|
|
|
|
getString(R.string.show_info_key), getString(R.string.show_info),
|
2021-03-27 15:45:49 +01:00
|
|
|
R.drawable.ic_info_outline);
|
2022-05-02 22:37:51 +02:00
|
|
|
final AdapterChoiceItem videoPlayer = new AdapterChoiceItem(
|
|
|
|
getString(R.string.video_player_key), getString(R.string.video_player),
|
|
|
|
R.drawable.ic_play_arrow);
|
2020-09-09 20:45:42 +02:00
|
|
|
final AdapterChoiceItem backgroundPlayer = new AdapterChoiceItem(
|
|
|
|
getString(R.string.background_player_key), getString(R.string.background_player),
|
2021-03-27 15:45:49 +01:00
|
|
|
R.drawable.ic_headset);
|
2022-05-02 22:37:51 +02:00
|
|
|
final AdapterChoiceItem popupPlayer = new AdapterChoiceItem(
|
|
|
|
getString(R.string.popup_player_key), getString(R.string.popup_player),
|
|
|
|
R.drawable.ic_picture_in_picture);
|
2021-10-02 19:21:25 +02:00
|
|
|
|
2022-05-02 22:37:51 +02:00
|
|
|
final List<AdapterChoiceItem> returnedItems = new ArrayList<>();
|
|
|
|
returnedItems.add(showInfo); // Always present
|
2022-05-03 19:19:21 +02:00
|
|
|
|
2022-05-02 22:37:51 +02:00
|
|
|
final List<StreamingService.ServiceInfo.MediaCapability> capabilities =
|
|
|
|
service.getServiceInfo().getMediaCapabilities();
|
2020-09-09 20:45:42 +02:00
|
|
|
|
|
|
|
if (linkType == LinkType.STREAM) {
|
|
|
|
if (capabilities.contains(VIDEO)) {
|
2022-05-02 22:37:51 +02:00
|
|
|
returnedItems.add(videoPlayer);
|
|
|
|
returnedItems.add(popupPlayer);
|
2020-09-09 20:45:42 +02:00
|
|
|
}
|
|
|
|
if (capabilities.contains(AUDIO)) {
|
2022-05-02 22:37:51 +02:00
|
|
|
returnedItems.add(backgroundPlayer);
|
2020-09-09 20:45:42 +02:00
|
|
|
}
|
2021-05-28 00:08:53 +02:00
|
|
|
// download is redundant for linkType CHANNEL AND PLAYLIST (till playlist downloading is
|
|
|
|
// not supported )
|
2022-05-02 22:37:51 +02:00
|
|
|
returnedItems.add(new AdapterChoiceItem(getString(R.string.download_key),
|
2021-05-28 00:08:53 +02:00
|
|
|
getString(R.string.download),
|
|
|
|
R.drawable.ic_file_download));
|
2020-09-09 20:45:42 +02:00
|
|
|
|
2021-10-02 19:21:25 +02:00
|
|
|
// Add to playlist is not necessary for CHANNEL and PLAYLIST linkType since those can
|
|
|
|
// not be added to a playlist
|
2022-05-02 22:37:51 +02:00
|
|
|
returnedItems.add(new AdapterChoiceItem(getString(R.string.add_to_playlist_key),
|
|
|
|
getString(R.string.add_to_playlist),
|
|
|
|
R.drawable.ic_add));
|
2020-09-09 20:45:42 +02:00
|
|
|
} else {
|
2022-05-03 19:19:21 +02:00
|
|
|
// LinkType.NONE is never present because it's filtered out before
|
|
|
|
// channels and playlist can be played as they contain a list of videos
|
2022-05-02 22:37:51 +02:00
|
|
|
final SharedPreferences preferences = PreferenceManager
|
|
|
|
.getDefaultSharedPreferences(this);
|
|
|
|
final boolean isExtVideoEnabled = preferences.getBoolean(
|
|
|
|
getString(R.string.use_external_video_player_key), false);
|
|
|
|
final boolean isExtAudioEnabled = preferences.getBoolean(
|
|
|
|
getString(R.string.use_external_audio_player_key), false);
|
|
|
|
|
2020-09-09 20:45:42 +02:00
|
|
|
if (capabilities.contains(VIDEO) && !isExtVideoEnabled) {
|
2022-05-02 22:37:51 +02:00
|
|
|
returnedItems.add(videoPlayer);
|
|
|
|
returnedItems.add(popupPlayer);
|
2020-09-09 20:45:42 +02:00
|
|
|
}
|
|
|
|
if (capabilities.contains(AUDIO) && !isExtAudioEnabled) {
|
2022-05-02 22:37:51 +02:00
|
|
|
returnedItems.add(backgroundPlayer);
|
2020-09-09 20:45:42 +02:00
|
|
|
}
|
2018-04-06 11:02:51 +02:00
|
|
|
}
|
|
|
|
|
2022-05-02 22:37:51 +02:00
|
|
|
return returnedItems;
|
2018-04-06 11:02:51 +02:00
|
|
|
}
|
|
|
|
|
2022-12-02 15:22:00 +01:00
|
|
|
protected Context getThemeWrapperContext() {
|
2020-03-31 19:20:15 +02:00
|
|
|
return new ContextThemeWrapper(this, ThemeHelper.isLightThemeSelected(this)
|
|
|
|
? R.style.LightTheme : R.style.DarkTheme);
|
2018-04-18 16:44:46 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private void setDialogButtonsState(final AlertDialog dialog, final boolean state) {
|
2018-02-12 19:44:35 +01:00
|
|
|
final Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
|
|
|
|
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (negativeButton == null || positiveButton == null) {
|
|
|
|
return;
|
|
|
|
}
|
2018-02-12 19:44:35 +01:00
|
|
|
|
|
|
|
negativeButton.setEnabled(state);
|
|
|
|
positiveButton.setEnabled(state);
|
|
|
|
}
|
|
|
|
|
2019-08-15 04:00:11 +02:00
|
|
|
private void handleText() {
|
2020-08-16 10:24:58 +02:00
|
|
|
final String searchString = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
|
|
|
final int serviceId = getIntent().getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
|
|
|
final Intent intent = new Intent(getThemeWrapperContext(), MainActivity.class);
|
2018-12-24 19:11:21 +01:00
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
startActivity(intent);
|
2019-08-15 04:00:11 +02:00
|
|
|
NavigationHelper.openSearch(getThemeWrapperContext(), serviceId, searchString);
|
2018-12-24 19:11:21 +01:00
|
|
|
}
|
|
|
|
|
2018-04-18 16:44:46 +02:00
|
|
|
private void handleChoice(final String selectedChoiceKey) {
|
2020-03-31 19:20:15 +02:00
|
|
|
final List<String> validChoicesList = Arrays.asList(getResources()
|
|
|
|
.getStringArray(R.array.preferred_open_action_values_list));
|
2018-04-18 16:44:46 +02:00
|
|
|
if (validChoicesList.contains(selectedChoiceKey)) {
|
2018-02-12 19:44:35 +01:00
|
|
|
PreferenceManager.getDefaultSharedPreferences(this).edit()
|
2020-03-31 19:20:15 +02:00
|
|
|
.putString(getString(
|
|
|
|
R.string.preferred_open_action_last_selected_key), selectedChoiceKey)
|
2018-04-06 11:02:51 +02:00
|
|
|
.apply();
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (selectedChoiceKey.equals(getString(R.string.popup_player_key))
|
2023-01-12 11:39:25 +01:00
|
|
|
&& !PermissionHelper.isPopupEnabledElseAsk(this)) {
|
2018-02-12 19:44:35 +01:00
|
|
|
finish();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-17 13:55:43 +02:00
|
|
|
if (selectedChoiceKey.equals(getString(R.string.download_key))) {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (PermissionHelper.checkStoragePermissions(this,
|
|
|
|
PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
2019-08-15 04:00:11 +02:00
|
|
|
selectionIsDownload = true;
|
|
|
|
openDownloadDialog();
|
|
|
|
}
|
2018-06-17 13:55:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-02 19:21:25 +02:00
|
|
|
if (selectedChoiceKey.equals(getString(R.string.add_to_playlist_key))) {
|
|
|
|
selectionIsAddToPlaylist = true;
|
|
|
|
openAddToPlaylistDialog();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-12 19:44:35 +01:00
|
|
|
// stop and bypass FetcherService if InfoScreen was selected since
|
|
|
|
// StreamDetailFragment can fetch data itself
|
2022-05-02 22:37:51 +02:00
|
|
|
if (selectedChoiceKey.equals(getString(R.string.show_info_key))
|
|
|
|
|| canHandleChoiceLikeShowInfo(selectedChoiceKey)) {
|
2018-02-12 19:44:35 +01:00
|
|
|
disposables.add(Observable
|
2018-04-05 22:45:00 +02:00
|
|
|
.fromCallable(() -> NavigationHelper.getIntentByLink(this, currentUrl))
|
2018-02-12 19:44:35 +01:00
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(intent -> {
|
|
|
|
startActivity(intent);
|
|
|
|
finish();
|
2021-03-07 18:59:17 +01:00
|
|
|
}, throwable -> handleError(this, new ErrorInfo(throwable,
|
|
|
|
UserAction.SHARE_TO_NEWPIPE, "Starting info activity: " + currentUrl)))
|
2018-02-12 19:44:35 +01:00
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
final Intent intent = new Intent(this, FetcherService.class);
|
2020-03-31 19:20:15 +02:00
|
|
|
final Choice choice = new Choice(currentService.getServiceId(), currentLinkType,
|
|
|
|
currentUrl, selectedChoiceKey);
|
2018-04-06 11:02:51 +02:00
|
|
|
intent.putExtra(FetcherService.KEY_CHOICE, choice);
|
2018-02-12 19:44:35 +01:00
|
|
|
startService(intent);
|
|
|
|
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
|
2022-05-02 22:37:51 +02:00
|
|
|
private boolean canHandleChoiceLikeShowInfo(final String selectedChoiceKey) {
|
2022-05-03 19:19:21 +02:00
|
|
|
if (!selectedChoiceKey.equals(getString(R.string.video_player_key))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// "video player" can be handled like "show info" (because VideoDetailFragment can load
|
|
|
|
// the stream instead of FetcherService) when...
|
2022-05-02 22:37:51 +02:00
|
|
|
|
2022-05-03 19:19:21 +02:00
|
|
|
// ...Autoplay is enabled
|
|
|
|
if (!PlayerHelper.isAutoplayAllowedByUser(getThemeWrapperContext())) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-05-02 22:37:51 +02:00
|
|
|
|
2022-05-03 19:19:21 +02:00
|
|
|
final boolean isExtVideoEnabled = PreferenceManager.getDefaultSharedPreferences(this)
|
|
|
|
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
|
|
|
// ...it's not done via an external player
|
|
|
|
if (isExtVideoEnabled) {
|
|
|
|
return false;
|
2022-05-02 22:37:51 +02:00
|
|
|
}
|
2022-05-03 19:19:21 +02:00
|
|
|
|
|
|
|
// ...the player is not running or in normal Video-mode/type
|
2022-07-10 23:05:37 +02:00
|
|
|
final PlayerType playerType = PlayerHolder.getInstance().getType();
|
|
|
|
return playerType == null || playerType == PlayerType.MAIN;
|
2022-05-02 22:37:51 +02:00
|
|
|
}
|
|
|
|
|
2022-12-02 15:22:00 +01:00
|
|
|
public static class PersistentFragment extends Fragment {
|
2023-01-11 15:08:10 +01:00
|
|
|
private WeakReference<AppCompatActivity> weakContext;
|
2022-12-02 15:22:00 +01:00
|
|
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
2022-12-07 14:43:27 +01:00
|
|
|
private int running = 0;
|
|
|
|
|
|
|
|
private synchronized void inFlight(final boolean started) {
|
|
|
|
if (started) {
|
|
|
|
running++;
|
|
|
|
} else {
|
|
|
|
running--;
|
2023-01-11 15:08:10 +01:00
|
|
|
if (running <= 0) {
|
|
|
|
getActivityContext().ifPresent(context -> context.getSupportFragmentManager()
|
|
|
|
.beginTransaction().remove(this).commit());
|
2022-12-07 14:43:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-02 15:22:00 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAttach(@NonNull final Context activityContext) {
|
|
|
|
super.onAttach(activityContext);
|
2023-01-11 15:08:10 +01:00
|
|
|
weakContext = new WeakReference<>((AppCompatActivity) activityContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDetach() {
|
|
|
|
super.onDetach();
|
|
|
|
weakContext = null;
|
2022-12-02 15:22:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("deprecation")
|
|
|
|
@Override
|
|
|
|
public void onCreate(final Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
setRetainInstance(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
disposables.clear();
|
|
|
|
}
|
|
|
|
|
2023-01-11 15:08:10 +01:00
|
|
|
/**
|
|
|
|
* @return the activity context, if there is one and the activity is not finishing
|
|
|
|
*/
|
|
|
|
private Optional<AppCompatActivity> getActivityContext() {
|
|
|
|
return Optional.ofNullable(weakContext)
|
2023-01-11 15:26:46 +01:00
|
|
|
.map(Reference::get)
|
2023-01-11 15:08:10 +01:00
|
|
|
.filter(context -> !context.isFinishing());
|
2022-12-07 14:43:27 +01:00
|
|
|
}
|
|
|
|
|
2022-12-02 15:22:00 +01:00
|
|
|
// guard against IllegalStateException in calling DialogFragment.show() whilst in background
|
|
|
|
// (which could happen, say, when the user pressed the home button while waiting for
|
|
|
|
// the network request to return) when it internally calls FragmentTransaction.commit()
|
|
|
|
// after the FragmentManager has saved its states (isStateSaved() == true)
|
|
|
|
// (ref: https://stackoverflow.com/a/39813506)
|
2023-01-11 15:08:10 +01:00
|
|
|
private void runOnVisible(final Consumer<AppCompatActivity> runnable) {
|
|
|
|
getActivityContext().ifPresentOrElse(context -> {
|
|
|
|
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
|
|
|
|
context.runOnUiThread(() -> {
|
|
|
|
runnable.accept(context);
|
|
|
|
inFlight(false);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
getLifecycle().addObserver(new DefaultLifecycleObserver() {
|
|
|
|
@Override
|
|
|
|
public void onResume(@NonNull final LifecycleOwner owner) {
|
|
|
|
getLifecycle().removeObserver(this);
|
|
|
|
getActivityContext().ifPresentOrElse(context ->
|
|
|
|
context.runOnUiThread(() -> {
|
|
|
|
runnable.accept(context);
|
|
|
|
inFlight(false);
|
|
|
|
}),
|
|
|
|
() -> inFlight(false)
|
|
|
|
);
|
2022-12-07 14:43:27 +01:00
|
|
|
}
|
2023-01-11 15:08:10 +01:00
|
|
|
});
|
|
|
|
// this trick doesn't seem to work on Android 10+ (API 29)
|
|
|
|
// which places restrictions on starting activities from the background
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
|
|
|
|
&& !context.isChangingConfigurations()) {
|
|
|
|
// try to bring the activity back to front if minimised
|
|
|
|
final Intent i = new Intent(context, RouterActivity.class);
|
|
|
|
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
|
|
|
startActivity(i);
|
2022-12-07 14:43:27 +01:00
|
|
|
}
|
2022-12-02 15:22:00 +01:00
|
|
|
}
|
2023-01-11 15:08:10 +01:00
|
|
|
|
2023-09-18 01:54:03 +02:00
|
|
|
}, () ->
|
2023-01-11 15:08:10 +01:00
|
|
|
// this branch is executed if there is no activity context
|
2023-09-18 01:54:03 +02:00
|
|
|
inFlight(false)
|
|
|
|
);
|
2022-12-02 15:22:00 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 15:08:10 +01:00
|
|
|
<T> Single<T> pleaseWait(final Single<T> single) {
|
|
|
|
// 'abuse' ambWith() here to cancel the toast for us when the wait is over
|
|
|
|
return single.ambWith(Single.create(emitter -> getActivityContext().ifPresent(context ->
|
|
|
|
context.runOnUiThread(() -> {
|
|
|
|
// Getting the stream info usually takes a moment
|
|
|
|
// Notifying the user here to ensure that no confusion arises
|
|
|
|
final Toast toast = Toast.makeText(context,
|
|
|
|
getString(R.string.processing_may_take_a_moment),
|
|
|
|
Toast.LENGTH_LONG);
|
|
|
|
toast.show();
|
|
|
|
emitter.setCancellable(toast::cancel);
|
|
|
|
}))));
|
2022-12-11 19:10:00 +01:00
|
|
|
}
|
|
|
|
|
2022-12-02 15:22:00 +01:00
|
|
|
@SuppressLint("CheckResult")
|
2022-12-07 14:43:27 +01:00
|
|
|
private void openDownloadDialog(final int currentServiceId, final String currentUrl) {
|
|
|
|
inFlight(true);
|
2023-09-18 01:54:03 +02:00
|
|
|
final LoadingDialog loadingDialog = new LoadingDialog(R.string.loading_metadata_title);
|
|
|
|
loadingDialog.show(getParentFragmentManager(), "loadingDialog");
|
2022-12-02 15:22:00 +01:00
|
|
|
disposables.add(ExtractorHelper.getStreamInfo(currentServiceId, currentUrl, true)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2023-01-11 15:08:10 +01:00
|
|
|
.compose(this::pleaseWait)
|
2022-12-02 15:22:00 +01:00
|
|
|
.subscribe(result ->
|
|
|
|
runOnVisible(ctx -> {
|
2023-09-18 01:54:03 +02:00
|
|
|
loadingDialog.dismiss();
|
2022-12-02 15:22:00 +01:00
|
|
|
final FragmentManager fm = ctx.getSupportFragmentManager();
|
|
|
|
final DownloadDialog downloadDialog = new DownloadDialog(ctx, result);
|
|
|
|
// dismiss listener to be handled by FragmentManager
|
|
|
|
downloadDialog.show(fm, "downloadDialog");
|
|
|
|
}
|
2023-09-18 01:54:03 +02:00
|
|
|
), throwable -> runOnVisible(ctx -> {
|
|
|
|
loadingDialog.dismiss();
|
|
|
|
((RouterActivity) ctx).showUnsupportedUrlDialog(currentUrl);
|
|
|
|
})));
|
2022-12-02 15:22:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void openAddToPlaylistDialog(final int currentServiceId, final String currentUrl) {
|
2022-12-07 14:43:27 +01:00
|
|
|
inFlight(true);
|
2022-12-02 15:22:00 +01:00
|
|
|
disposables.add(ExtractorHelper.getStreamInfo(currentServiceId, currentUrl, false)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2023-01-11 15:08:10 +01:00
|
|
|
.compose(this::pleaseWait)
|
2022-12-02 15:22:00 +01:00
|
|
|
.subscribe(
|
2023-01-11 15:08:10 +01:00
|
|
|
info -> getActivityContext().ifPresent(context ->
|
|
|
|
PlaylistDialog.createCorrespondingDialog(context,
|
|
|
|
List.of(new StreamEntity(info)),
|
|
|
|
playlistDialog -> runOnVisible(ctx -> {
|
|
|
|
// dismiss listener to be handled by FragmentManager
|
|
|
|
final FragmentManager fm =
|
|
|
|
ctx.getSupportFragmentManager();
|
|
|
|
playlistDialog.show(fm, "addToPlaylistDialog");
|
|
|
|
})
|
|
|
|
)),
|
2022-12-02 15:22:00 +01:00
|
|
|
throwable -> runOnVisible(ctx -> handleError(ctx, new ErrorInfo(
|
|
|
|
throwable,
|
|
|
|
UserAction.REQUESTED_STREAM,
|
|
|
|
"Tried to add " + currentUrl + " to a playlist",
|
|
|
|
((RouterActivity) ctx).currentService.getServiceId())
|
|
|
|
))
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-02 19:21:25 +02:00
|
|
|
private void openAddToPlaylistDialog() {
|
2022-12-02 15:22:00 +01:00
|
|
|
getPersistFragment().openAddToPlaylistDialog(currentServiceId, currentUrl);
|
2021-10-02 19:21:25 +02:00
|
|
|
}
|
|
|
|
|
2018-06-20 14:46:57 +02:00
|
|
|
private void openDownloadDialog() {
|
2022-12-02 15:22:00 +01:00
|
|
|
getPersistFragment().openDownloadDialog(currentServiceId, currentUrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
private PersistentFragment getPersistFragment() {
|
|
|
|
final FragmentManager fm = getSupportFragmentManager();
|
|
|
|
PersistentFragment persistFragment =
|
|
|
|
(PersistentFragment) fm.findFragmentByTag("PERSIST_FRAGMENT");
|
|
|
|
if (persistFragment == null) {
|
|
|
|
persistFragment = new PersistentFragment();
|
|
|
|
fm.beginTransaction()
|
|
|
|
.add(persistFragment, "PERSIST_FRAGMENT")
|
|
|
|
.commitNow();
|
|
|
|
}
|
|
|
|
return persistFragment;
|
2018-06-20 14:46:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onRequestPermissionsResult(final int requestCode,
|
|
|
|
@NonNull final String[] permissions,
|
|
|
|
@NonNull final int[] grantResults) {
|
2021-06-16 04:08:41 +02:00
|
|
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
2020-08-16 10:24:58 +02:00
|
|
|
for (final int i : grantResults) {
|
2019-08-15 04:00:11 +02:00
|
|
|
if (i == PackageManager.PERMISSION_DENIED) {
|
2018-06-20 14:46:57 +02:00
|
|
|
finish();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2019-08-15 04:00:11 +02:00
|
|
|
if (requestCode == PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE) {
|
|
|
|
openDownloadDialog();
|
|
|
|
}
|
2018-06-20 14:46:57 +02:00
|
|
|
}
|
|
|
|
|
2018-02-12 19:44:35 +01:00
|
|
|
private static class AdapterChoiceItem {
|
2020-03-31 19:20:15 +02:00
|
|
|
final String description;
|
|
|
|
final String key;
|
2019-08-15 04:00:11 +02:00
|
|
|
@DrawableRes
|
|
|
|
final int icon;
|
2018-02-12 19:44:35 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
AdapterChoiceItem(final String key, final String description, final int icon) {
|
2018-02-12 19:44:35 +01:00
|
|
|
this.key = key;
|
2022-05-02 22:37:51 +02:00
|
|
|
this.description = description;
|
2018-02-12 19:44:35 +01:00
|
|
|
this.icon = icon;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static class Choice implements Serializable {
|
|
|
|
final int serviceId;
|
2020-03-31 19:20:15 +02:00
|
|
|
final String url;
|
|
|
|
final String playerChoice;
|
2018-02-12 19:44:35 +01:00
|
|
|
final LinkType linkType;
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
Choice(final int serviceId, final LinkType linkType,
|
|
|
|
final String url, final String playerChoice) {
|
2018-02-12 19:44:35 +01:00
|
|
|
this.serviceId = serviceId;
|
|
|
|
this.linkType = linkType;
|
|
|
|
this.url = url;
|
|
|
|
this.playerChoice = playerChoice;
|
|
|
|
}
|
|
|
|
|
2020-12-11 14:55:47 +01:00
|
|
|
@NonNull
|
2018-02-12 19:44:35 +01:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return serviceId + ":" + url + " > " + linkType + " ::: " + playerChoice;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class FetcherService extends IntentService {
|
|
|
|
|
|
|
|
public static final String KEY_CHOICE = "key_choice";
|
2020-03-31 19:20:15 +02:00
|
|
|
private static final int ID = 456;
|
2018-02-12 19:44:35 +01:00
|
|
|
private Disposable fetcher;
|
|
|
|
|
|
|
|
public FetcherService() {
|
|
|
|
super(FetcherService.class.getSimpleName());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onCreate() {
|
|
|
|
super.onCreate();
|
|
|
|
startForeground(ID, createNotification().build());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
protected void onHandleIntent(@Nullable final Intent intent) {
|
|
|
|
if (intent == null) {
|
|
|
|
return;
|
|
|
|
}
|
2018-02-12 19:44:35 +01:00
|
|
|
|
|
|
|
final Serializable serializable = intent.getSerializableExtra(KEY_CHOICE);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (!(serializable instanceof Choice)) {
|
|
|
|
return;
|
|
|
|
}
|
2020-08-16 10:24:58 +02:00
|
|
|
final Choice playerChoice = (Choice) serializable;
|
2018-02-12 19:44:35 +01:00
|
|
|
handleChoice(playerChoice);
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
public void handleChoice(final Choice choice) {
|
2018-02-12 19:44:35 +01:00
|
|
|
Single<? extends Info> single = null;
|
|
|
|
UserAction userAction = UserAction.SOMETHING_ELSE;
|
|
|
|
|
|
|
|
switch (choice.linkType) {
|
|
|
|
case STREAM:
|
|
|
|
single = ExtractorHelper.getStreamInfo(choice.serviceId, choice.url, false);
|
|
|
|
userAction = UserAction.REQUESTED_STREAM;
|
|
|
|
break;
|
|
|
|
case CHANNEL:
|
|
|
|
single = ExtractorHelper.getChannelInfo(choice.serviceId, choice.url, false);
|
|
|
|
userAction = UserAction.REQUESTED_CHANNEL;
|
|
|
|
break;
|
|
|
|
case PLAYLIST:
|
|
|
|
single = ExtractorHelper.getPlaylistInfo(choice.serviceId, choice.url, false);
|
|
|
|
userAction = UserAction.REQUESTED_PLAYLIST;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (single != null) {
|
|
|
|
final UserAction finalUserAction = userAction;
|
|
|
|
final Consumer<Info> resultHandler = getResultHandler(choice);
|
|
|
|
fetcher = single
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(info -> {
|
|
|
|
resultHandler.accept(info);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (fetcher != null) {
|
|
|
|
fetcher.dispose();
|
|
|
|
}
|
2020-12-11 14:55:47 +01:00
|
|
|
}, throwable -> handleError(this, new ErrorInfo(throwable, finalUserAction,
|
|
|
|
choice.url + " opened with " + choice.playerChoice,
|
|
|
|
choice.serviceId)));
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
public Consumer<Info> getResultHandler(final Choice choice) {
|
2018-02-12 19:44:35 +01:00
|
|
|
return info -> {
|
|
|
|
final String videoPlayerKey = getString(R.string.video_player_key);
|
|
|
|
final String backgroundPlayerKey = getString(R.string.background_player_key);
|
|
|
|
final String popupPlayerKey = getString(R.string.popup_player_key);
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
final SharedPreferences preferences = PreferenceManager
|
|
|
|
.getDefaultSharedPreferences(this);
|
2020-08-16 10:24:58 +02:00
|
|
|
final boolean isExtVideoEnabled = preferences.getBoolean(
|
2020-03-31 19:20:15 +02:00
|
|
|
getString(R.string.use_external_video_player_key), false);
|
2020-08-16 10:24:58 +02:00
|
|
|
final boolean isExtAudioEnabled = preferences.getBoolean(
|
2020-03-31 19:20:15 +02:00
|
|
|
getString(R.string.use_external_audio_player_key), false);
|
2018-02-12 19:44:35 +01:00
|
|
|
|
2020-10-18 20:33:08 +02:00
|
|
|
final PlayQueue playQueue;
|
2018-02-12 19:44:35 +01:00
|
|
|
if (info instanceof StreamInfo) {
|
2020-10-18 20:33:08 +02:00
|
|
|
if (choice.playerChoice.equals(backgroundPlayerKey) && isExtAudioEnabled) {
|
2018-02-12 19:44:35 +01:00
|
|
|
NavigationHelper.playOnExternalAudioPlayer(this, (StreamInfo) info);
|
2020-10-18 20:33:08 +02:00
|
|
|
return;
|
|
|
|
} else if (choice.playerChoice.equals(videoPlayerKey) && isExtVideoEnabled) {
|
2018-02-12 19:44:35 +01:00
|
|
|
NavigationHelper.playOnExternalVideoPlayer(this, (StreamInfo) info);
|
2020-10-18 20:33:08 +02:00
|
|
|
return;
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
2020-10-18 20:33:08 +02:00
|
|
|
playQueue = new SinglePlayQueue((StreamInfo) info);
|
|
|
|
} else if (info instanceof ChannelInfo) {
|
2023-04-14 10:19:58 +02:00
|
|
|
final Optional<ListLinkHandler> playableTab = ((ChannelInfo) info).getTabs()
|
|
|
|
.stream()
|
|
|
|
.filter(ChannelTabHelper::isStreamsTab)
|
|
|
|
.findFirst();
|
|
|
|
|
|
|
|
if (playableTab.isPresent()) {
|
|
|
|
playQueue = new ChannelTabPlayQueue(info.getServiceId(), playableTab.get());
|
|
|
|
} else {
|
|
|
|
return; // there is no playable tab
|
|
|
|
}
|
2020-10-18 20:33:08 +02:00
|
|
|
} else if (info instanceof PlaylistInfo) {
|
|
|
|
playQueue = new PlaylistPlayQueue((PlaylistInfo) info);
|
|
|
|
} else {
|
|
|
|
return;
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
|
2020-10-18 20:33:08 +02:00
|
|
|
if (choice.playerChoice.equals(videoPlayerKey)) {
|
2020-10-31 20:26:09 +01:00
|
|
|
NavigationHelper.playOnMainPlayer(this, playQueue, false);
|
2020-10-18 20:33:08 +02:00
|
|
|
} else if (choice.playerChoice.equals(backgroundPlayerKey)) {
|
|
|
|
NavigationHelper.playOnBackgroundPlayer(this, playQueue, true);
|
|
|
|
} else if (choice.playerChoice.equals(popupPlayerKey)) {
|
|
|
|
NavigationHelper.playOnPopupPlayer(this, playQueue, true);
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
2020-12-19 12:22:17 +01:00
|
|
|
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (fetcher != null) {
|
|
|
|
fetcher.dispose();
|
|
|
|
}
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private NotificationCompat.Builder createNotification() {
|
|
|
|
return new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
|
|
|
|
.setOngoing(true)
|
|
|
|
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
|
|
|
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
2020-03-31 19:20:15 +02:00
|
|
|
.setContentTitle(
|
|
|
|
getString(R.string.preferred_player_fetcher_notification_title))
|
|
|
|
.setContentText(
|
|
|
|
getString(R.string.preferred_player_fetcher_notification_message));
|
2018-02-12 19:44:35 +01:00
|
|
|
}
|
2018-01-23 01:40:00 +01:00
|
|
|
}
|
|
|
|
|
2017-06-05 21:33:01 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-03-27 03:18:14 +01:00
|
|
|
@Nullable
|
2020-03-31 19:20:15 +02:00
|
|
|
private String getUrl(final Intent intent) {
|
2020-03-27 03:18:14 +01:00
|
|
|
String foundUrl = null;
|
2017-04-09 19:34:00 +02:00
|
|
|
if (intent.getData() != null) {
|
2020-03-27 03:18:14 +01:00
|
|
|
// Called from another app
|
|
|
|
foundUrl = intent.getData().toString();
|
2017-04-09 19:34:00 +02:00
|
|
|
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
2020-03-27 03:18:14 +01:00
|
|
|
// Called from the share menu
|
|
|
|
final String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
|
|
|
foundUrl = UrlFinder.firstUrlFromInput(extraText);
|
2017-04-09 19:34:00 +02:00
|
|
|
}
|
|
|
|
|
2020-03-27 03:18:14 +01:00
|
|
|
return foundUrl;
|
2017-02-27 21:14:03 +01:00
|
|
|
}
|
|
|
|
}
|