-Added player conversion to background and popup players.

-[#919] Fixed custom notification does not trigger unlocking on lockscreen.
-[#947] Fixes player crashing on internet outage, issue partially addressed.
-Fixed main player losing state after destroy while in background.
-Fixed main player controls not hiding automatically after orientation change.
-Fixed dialog uploader not marqueeing when too long.
-Fixed popup permission throwing NPE on BaseList.
-Refactored popup permissions to start in NavigationHelper.
-Extracted hardcoded string for player menus.
-Bump Java version to 1.8.
-Some lambda conversions.
This commit is contained in:
John Zhen Mo 2018-01-03 22:53:31 -08:00
parent 0223d6d200
commit 39b0b2f032
21 changed files with 282 additions and 221 deletions

View File

@ -42,8 +42,8 @@ android {
abortOnError false abortOnError false
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_8
} }
} }

View File

@ -18,9 +18,8 @@ public class RouterPopupActivity extends RouterActivity {
@Override @Override
protected void handleUrl(String url) { protected void handleUrl(String url) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M if (!PermissionHelper.isPopupEnabled(this)) {
&& !PermissionHelper.checkSystemAlertWindowPermission(this)) { PermissionHelper.showPopupEnablementToast(this);
Toast.makeText(this, R.string.msg_popup_permission, Toast.LENGTH_LONG).show();
finish(); finish();
return; return;
} }

View File

@ -505,7 +505,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break; break;
case 1: case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnPopupPlayer(getActivity(), new SinglePlayQueue(item));
break; break;
default: default:
break; break;
@ -813,11 +813,8 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
} }
private void openPopupPlayer(final boolean append) { private void openPopupPlayer(final boolean append) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) { if (!PermissionHelper.isPopupEnabled(activity)) {
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG); PermissionHelper.showPopupEnablementToast(activity);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
return; return;
} }

View File

@ -1,16 +1,21 @@
package org.schabi.newpipe.fragments.list; package org.schabi.newpipe.fragments.list;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.View; import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
@ -24,6 +29,7 @@ import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.StateSaver; import org.schabi.newpipe.util.StateSaver;
import java.util.List; import java.util.List;
@ -192,6 +198,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
protected void showStreamDialog(final StreamInfoItem item) { protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext(); final Context context = getContext();
final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return; if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{ final String[] commands = new String[]{
@ -207,7 +214,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break; break;
case 1: case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break; break;
default: default:
break; break;

View File

@ -1,10 +1,10 @@
package org.schabi.newpipe.fragments.list.channel; package org.schabi.newpipe.fragments.list.channel;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -12,7 +12,6 @@ import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -23,7 +22,6 @@ import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.jakewharton.rxbinding2.view.RxView; import com.jakewharton.rxbinding2.view.RxView;
@ -153,6 +151,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
@Override @Override
protected void showStreamDialog(final StreamInfoItem item) { protected void showStreamDialog(final StreamInfoItem item) {
final Activity activity = getActivity();
final Context context = getContext(); final Context context = getContext();
if (context == null || context.getResources() == null || getActivity() == null) return; if (context == null || context.getResources() == null || getActivity() == null) return;
@ -173,7 +172,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break; break;
case 1: case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break; break;
case 2: case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index)); NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
@ -182,7 +181,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index)); NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break; break;
case 4: case 4:
NavigationHelper.playOnPopupPlayer(context, getPlayQueue(index)); NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
break; break;
default: default:
break; break;
@ -454,13 +453,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
headerPopupButton.setOnClickListener(new View.OnClickListener() { headerPopupButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
return;
}
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()); NavigationHelper.playOnPopupPlayer(activity, getPlayQueue());
} }
}); });

View File

@ -1,14 +1,13 @@
package org.schabi.newpipe.fragments.list.playlist; package org.schabi.newpipe.fragments.list.playlist;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -17,7 +16,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.ListExtractor;
@ -33,7 +31,6 @@ import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import io.reactivex.Single; import io.reactivex.Single;
@ -102,6 +99,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
@Override @Override
protected void showStreamDialog(final StreamInfoItem item) { protected void showStreamDialog(final StreamInfoItem item) {
final Context context = getContext(); final Context context = getContext();
final Activity activity = getActivity();
if (context == null || context.getResources() == null || getActivity() == null) return; if (context == null || context.getResources() == null || getActivity() == null) return;
final String[] commands = new String[]{ final String[] commands = new String[]{
@ -121,7 +119,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
break; break;
case 1: case 1:
NavigationHelper.enqueueOnPopupPlayer(context, new SinglePlayQueue(item)); NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
break; break;
case 2: case 2:
NavigationHelper.playOnMainPlayer(context, getPlayQueue(index)); NavigationHelper.playOnMainPlayer(context, getPlayQueue(index));
@ -130,7 +128,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index)); NavigationHelper.playOnBackgroundPlayer(context, getPlayQueue(index));
break; break;
case 4: case 4:
NavigationHelper.playOnPopupPlayer(context, getPlayQueue(index)); NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(index));
break; break;
default: default:
break; break;
@ -230,13 +228,6 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
headerPopupButton.setOnClickListener(new View.OnClickListener() { headerPopupButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
return;
}
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()); NavigationHelper.playOnPopupPlayer(activity, getPlayQueue());
} }
}); });

View File

@ -65,7 +65,6 @@ public final class BackgroundPlayer extends Service {
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.BackgroundPlayer.CLOSE"; public static final String ACTION_CLOSE = "org.schabi.newpipe.player.BackgroundPlayer.CLOSE";
public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.BackgroundPlayer.PLAY_PAUSE"; public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.BackgroundPlayer.PLAY_PAUSE";
public static final String ACTION_OPEN_CONTROLS = "org.schabi.newpipe.player.BackgroundPlayer.OPEN_CONTROLS";
public static final String ACTION_REPEAT = "org.schabi.newpipe.player.BackgroundPlayer.REPEAT"; public static final String ACTION_REPEAT = "org.schabi.newpipe.player.BackgroundPlayer.REPEAT";
public static final String ACTION_PLAY_NEXT = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_NEXT"; public static final String ACTION_PLAY_NEXT = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_NEXT";
public static final String ACTION_PLAY_PREVIOUS = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_PREVIOUS"; public static final String ACTION_PLAY_PREVIOUS = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_PREVIOUS";
@ -195,11 +194,14 @@ public final class BackgroundPlayer extends Service {
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationStop, remoteViews.setOnClickPendingIntent(R.id.notificationStop,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_CONTROLS), PendingIntent.FLAG_UPDATE_CURRENT));
remoteViews.setOnClickPendingIntent(R.id.notificationRepeat, remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
// Starts background player activity -- attempts to unlock lockscreen
final Intent intent = NavigationHelper.getBackgroundPlayerActivityIntent(this);
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getActivity(this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT));
if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) { if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_previous); remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_previous);
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_next); remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_next);
@ -393,7 +395,7 @@ public final class BackgroundPlayer extends Service {
if (index < 0 || index >= info.audio_streams.size()) return null; if (index < 0 || index >= info.audio_streams.size()) return null;
final AudioStream audio = info.audio_streams.get(index); final AudioStream audio = info.audio_streams.get(index);
return buildMediaSource(audio.getUrl(), MediaFormat.getSuffixById(audio.format)); return buildMediaSource(audio.getUrl(), MediaFormat.getSuffixById(audio.getFormatId()));
} }
@Override @Override
@ -453,7 +455,6 @@ public final class BackgroundPlayer extends Service {
super.setupBroadcastReceiver(intentFilter); super.setupBroadcastReceiver(intentFilter);
intentFilter.addAction(ACTION_CLOSE); intentFilter.addAction(ACTION_CLOSE);
intentFilter.addAction(ACTION_PLAY_PAUSE); intentFilter.addAction(ACTION_PLAY_PAUSE);
intentFilter.addAction(ACTION_OPEN_CONTROLS);
intentFilter.addAction(ACTION_REPEAT); intentFilter.addAction(ACTION_REPEAT);
intentFilter.addAction(ACTION_PLAY_PREVIOUS); intentFilter.addAction(ACTION_PLAY_PREVIOUS);
intentFilter.addAction(ACTION_PLAY_NEXT); intentFilter.addAction(ACTION_PLAY_NEXT);
@ -478,9 +479,6 @@ public final class BackgroundPlayer extends Service {
case ACTION_PLAY_PAUSE: case ACTION_PLAY_PAUSE:
onVideoPlayPause(); onVideoPlayPause();
break; break;
case ACTION_OPEN_CONTROLS:
NavigationHelper.openBackgroundPlayerControl(getApplicationContext());
break;
case ACTION_REPEAT: case ACTION_REPEAT:
onRepeatClicked(); onRepeatClicked();
break; break;

View File

@ -1,9 +1,12 @@
package org.schabi.newpipe.player; package org.schabi.newpipe.player;
import android.content.Intent; import android.content.Intent;
import android.view.MenuItem;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import static org.schabi.newpipe.player.BackgroundPlayer.ACTION_CLOSE;
public final class BackgroundPlayerActivity extends ServicePlayerActivity { public final class BackgroundPlayerActivity extends ServicePlayerActivity {
private static final String TAG = "BackgroundPlayerActivity"; private static final String TAG = "BackgroundPlayerActivity";
@ -36,4 +39,25 @@ public final class BackgroundPlayerActivity extends ServicePlayerActivity {
((BackgroundPlayer.BasePlayerImpl) player).removeActivityListener(this); ((BackgroundPlayer.BasePlayerImpl) player).removeActivityListener(this);
} }
} }
@Override
public int getPlayerOptionMenuResource() {
return R.menu.menu_play_queue_bg;
}
@Override
public boolean onPlayerOptionSelected(MenuItem item) {
if (item.getItemId() == R.id.action_switch_popup) {
this.player.setRecovery();
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
getApplicationContext().startService(getSwitchIntent(PopupVideoPlayer.class));
return true;
}
return false;
}
@Override
public Intent getPlayerShutdownIntent() {
return new Intent(ACTION_CLOSE);
}
} }

View File

@ -78,6 +78,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public final class MainVideoPlayer extends Activity { public final class MainVideoPlayer extends Activity {
private static final String TAG = ".MainVideoPlayer"; private static final String TAG = ".MainVideoPlayer";
private static final boolean DEBUG = BasePlayer.DEBUG; private static final boolean DEBUG = BasePlayer.DEBUG;
private static final String PLAYER_STATE_INTENT = "player_state_intent";
private GestureDetector gestureDetector; private GestureDetector gestureDetector;
@ -99,19 +100,41 @@ public final class MainVideoPlayer extends Activity {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) getWindow().setStatusBarColor(Color.BLACK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) getWindow().setStatusBarColor(Color.BLACK);
setVolumeControlStream(AudioManager.STREAM_MUSIC); setVolumeControlStream(AudioManager.STREAM_MUSIC);
if (getIntent() == null) { final Intent intent;
if (savedInstanceState != null && savedInstanceState.getParcelable(PLAYER_STATE_INTENT) != null) {
intent = savedInstanceState.getParcelable(PLAYER_STATE_INTENT);
} else {
intent = getIntent();
}
if (intent == null) {
Toast.makeText(this, R.string.general_error, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.general_error, Toast.LENGTH_SHORT).show();
finish(); finish();
return; return;
} }
showSystemUi(); showSystemUi();
setContentView(R.layout.activity_main_player); setContentView(R.layout.activity_main_player);
playerImpl = new VideoPlayerImpl(this); playerImpl = new VideoPlayerImpl(this);
playerImpl.setup(findViewById(android.R.id.content)); playerImpl.setup(findViewById(android.R.id.content));
playerImpl.handleIntent(getIntent()); playerImpl.handleIntent(intent);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (this.playerImpl == null) return;
final Intent intent = NavigationHelper.getPlayerIntent(
getApplicationContext(),
this.getClass(),
this.playerImpl.getPlayQueue(),
this.playerImpl.getRepeatMode(),
this.playerImpl.getPlaybackSpeed(),
this.playerImpl.getPlaybackPitch(),
this.playerImpl.getPlaybackQuality()
);
outState.putParcelable(PLAYER_STATE_INTENT, intent);
} }
@Override @Override
@ -448,12 +471,9 @@ public final class MainVideoPlayer extends Activity {
if (getCurrentState() != STATE_COMPLETED) { if (getCurrentState() != STATE_COMPLETED) {
getControlsVisibilityHandler().removeCallbacksAndMessages(null); getControlsVisibilityHandler().removeCallbacksAndMessages(null);
animateView(getControlsRoot(), true, 300, 0, new Runnable() { animateView(getControlsRoot(), true, 300, 0, () -> {
@Override if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
public void run() { hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
}
} }
}); });
} }
@ -506,6 +526,7 @@ public final class MainVideoPlayer extends Activity {
private void onScreenRotationClicked() { private void onScreenRotationClicked() {
if (DEBUG) Log.d(TAG, "onScreenRotationClicked() called"); if (DEBUG) Log.d(TAG, "onScreenRotationClicked() called");
toggleOrientation(); toggleOrientation();
showControlsThenHide();
} }
@Override @Override
@ -561,12 +582,9 @@ public final class MainVideoPlayer extends Activity {
@Override @Override
public void onPlaying() { public void onPlaying() {
super.onPlaying(); super.onPlaying();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, new Runnable() { animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
@Override playPauseButton.setImageResource(R.drawable.ic_pause_white);
public void run() { animatePlayButtons(true, 200);
playPauseButton.setImageResource(R.drawable.ic_pause_white);
animatePlayButtons(true, 200);
}
}); });
showSystemUi(); showSystemUi();
getRootView().setKeepScreenOn(true); getRootView().setKeepScreenOn(true);
@ -575,12 +593,9 @@ public final class MainVideoPlayer extends Activity {
@Override @Override
public void onPaused() { public void onPaused() {
super.onPaused(); super.onPaused();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, new Runnable() { animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
@Override playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
public void run() { animatePlayButtons(true, 200);
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
animatePlayButtons(true, 200);
}
}); });
showSystemUi(); showSystemUi();
@ -598,12 +613,9 @@ public final class MainVideoPlayer extends Activity {
@Override @Override
public void onCompleted() { public void onCompleted() {
showSystemUi(); showSystemUi();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, new Runnable() { animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> {
@Override playPauseButton.setImageResource(R.drawable.ic_replay_white);
public void run() { animatePlayButtons(true, 300);
playPauseButton.setImageResource(R.drawable.ic_replay_white);
animatePlayButtons(true, 300);
}
}); });
getRootView().setKeepScreenOn(false); getRootView().setKeepScreenOn(false);
@ -632,17 +644,10 @@ public final class MainVideoPlayer extends Activity {
public void hideControls(final long duration, long delay) { public void hideControls(final long duration, long delay) {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]"); if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
getControlsVisibilityHandler().removeCallbacksAndMessages(null); getControlsVisibilityHandler().removeCallbacksAndMessages(null);
getControlsVisibilityHandler().postDelayed(new Runnable() { getControlsVisibilityHandler().postDelayed(() ->
@Override animateView(getControlsRoot(), false, duration, 0, MainVideoPlayer.this::hideSystemUi),
public void run() { delay
animateView(getControlsRoot(), false, duration, 0, new Runnable() { );
@Override
public void run() {
hideSystemUi();
}
});
}
}, delay);
} }
private void updatePlaybackButtons() { private void updatePlaybackButtons() {
@ -655,22 +660,19 @@ public final class MainVideoPlayer extends Activity {
private void buildMoreOptionsMenu() { private void buildMoreOptionsMenu() {
if (moreOptionsPopupMenu == null) return; if (moreOptionsPopupMenu == null) return;
moreOptionsPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { moreOptionsPopupMenu.setOnMenuItemClickListener(menuItem -> {
@Override switch (menuItem.getItemId()) {
public boolean onMenuItemClick(MenuItem menuItem) { case R.id.toggleOrientation:
switch (menuItem.getItemId()) { onScreenRotationClicked();
case R.id.toggleOrientation: break;
onScreenRotationClicked(); case R.id.switchPopup:
break; onFullScreenButtonClicked();
case R.id.switchPopup: break;
onFullScreenButtonClicked(); case R.id.switchBackground:
break; onPlayBackgroundButtonClicked();
case R.id.switchBackground: break;
onPlayBackgroundButtonClicked();
break;
}
return false;
} }
return false;
}); });
} }
@ -692,12 +694,7 @@ public final class MainVideoPlayer extends Activity {
playQueueAdapter.setSelectedListener(getOnSelectedListener()); playQueueAdapter.setSelectedListener(getOnSelectedListener());
itemsListCloseButton.setOnClickListener(new View.OnClickListener() { itemsListCloseButton.setOnClickListener(view -> onQueueClosed());
@Override
public void onClick(View view) {
onQueueClosed();
}
});
} }
private OnScrollBelowItemsListener getQueueScrollListener() { private OnScrollBelowItemsListener getQueueScrollListener() {

View File

@ -66,9 +66,9 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.event.PlayerEventListener; import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity; import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.playlist.PlayQueueItem;
import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.playlist.SinglePlayQueue;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
@ -84,7 +84,6 @@ import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.player.helper.PlayerHelper.isUsingOldPlayer; import static org.schabi.newpipe.player.helper.PlayerHelper.isUsingOldPlayer;
@ -102,7 +101,6 @@ public final class PopupVideoPlayer extends Service {
private static final int NOTIFICATION_ID = 40028922; private static final int NOTIFICATION_ID = 40028922;
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE"; public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE";
public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.PopupVideoPlayer.PLAY_PAUSE"; public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.PopupVideoPlayer.PLAY_PAUSE";
public static final String ACTION_OPEN_CONTROLS = "org.schabi.newpipe.player.PopupVideoPlayer.OPEN_CONTROLS";
public static final String ACTION_REPEAT = "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT"; public static final String ACTION_REPEAT = "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT";
private static final String POPUP_SAVED_WIDTH = "popup_saved_width"; private static final String POPUP_SAVED_WIDTH = "popup_saved_width";
@ -169,17 +167,7 @@ public final class PopupVideoPlayer extends Service {
currentWorker = ExtractorHelper.getStreamInfo(serviceId,url,false) currentWorker = ExtractorHelper.getStreamInfo(serviceId,url,false)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<StreamInfo>() { .subscribe(fetcherRunnable::onReceive, fetcherRunnable::onError);
@Override
public void accept(@NonNull StreamInfo info) throws Exception {
fetcherRunnable.onReceive(info);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
fetcherRunnable.onError(throwable);
}
});
} else { } else {
playerImpl.setStartedFromNewPipe(true); playerImpl.setStartedFromNewPipe(true);
playerImpl.handleIntent(intent); playerImpl.handleIntent(intent);
@ -267,11 +255,14 @@ public final class PopupVideoPlayer extends Service {
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
notRemoteView.setOnClickPendingIntent(R.id.notificationStop, notRemoteView.setOnClickPendingIntent(R.id.notificationStop,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_CONTROLS), PendingIntent.FLAG_UPDATE_CURRENT));
notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat, notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
// Starts popup player activity -- attempts to unlock lockscreen
final Intent intent = NavigationHelper.getPopupPlayerActivityIntent(this);
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
PendingIntent.getActivity(this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT));
setRepeatModeRemote(notRemoteView, playerImpl.getRepeatMode()); setRepeatModeRemote(notRemoteView, playerImpl.getRepeatMode());
return new NotificationCompat.Builder(this, getString(R.string.notification_channel_id)) return new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
@ -421,12 +412,7 @@ public final class PopupVideoPlayer extends Service {
super.initViews(rootView); super.initViews(rootView);
resizingIndicator = rootView.findViewById(R.id.resizing_indicator); resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
fullScreenButton = rootView.findViewById(R.id.fullScreenButton); fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
fullScreenButton.setOnClickListener(new View.OnClickListener() { fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked());
@Override
public void onClick(View v) {
onFullScreenButtonClicked();
}
});
} }
@Override @Override
@ -604,7 +590,6 @@ public final class PopupVideoPlayer extends Service {
if (DEBUG) Log.d(TAG, "setupBroadcastReceiver() called with: intentFilter = [" + intentFilter + "]"); if (DEBUG) Log.d(TAG, "setupBroadcastReceiver() called with: intentFilter = [" + intentFilter + "]");
intentFilter.addAction(ACTION_CLOSE); intentFilter.addAction(ACTION_CLOSE);
intentFilter.addAction(ACTION_PLAY_PAUSE); intentFilter.addAction(ACTION_PLAY_PAUSE);
intentFilter.addAction(ACTION_OPEN_CONTROLS);
intentFilter.addAction(ACTION_REPEAT); intentFilter.addAction(ACTION_REPEAT);
intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_ON);
@ -623,9 +608,6 @@ public final class PopupVideoPlayer extends Service {
case ACTION_PLAY_PAUSE: case ACTION_PLAY_PAUSE:
onVideoPlayPause(); onVideoPlayPause();
break; break;
case ACTION_OPEN_CONTROLS:
NavigationHelper.openPopupPlayerControl(getApplicationContext());
break;
case ACTION_REPEAT: case ACTION_REPEAT:
onRepeatClicked(); onRepeatClicked();
break; break;
@ -899,37 +881,31 @@ public final class PopupVideoPlayer extends Service {
} }
private void onReceive(final StreamInfo info) { private void onReceive(final StreamInfo info) {
mainHandler.post(new Runnable() { mainHandler.post(() -> {
@Override final Intent intent = NavigationHelper.getPlayerIntent(getApplicationContext(),
public void run() { PopupVideoPlayer.class, new SinglePlayQueue(info));
final Intent intent = NavigationHelper.getPlayerIntent(getApplicationContext(), playerImpl.handleIntent(intent);
PopupVideoPlayer.class, new SinglePlayQueue(info));
playerImpl.handleIntent(intent);
}
}); });
} }
private void onError(final Throwable exception) { private void onError(final Throwable exception) {
if (DEBUG) Log.d(TAG, "onError() called with: exception = [" + exception + "]"); if (DEBUG) Log.d(TAG, "onError() called with: exception = [" + exception + "]");
exception.printStackTrace(); exception.printStackTrace();
mainHandler.post(new Runnable() { mainHandler.post(() -> {
@Override if (exception instanceof ReCaptchaException) {
public void run() { onReCaptchaException();
if (exception instanceof ReCaptchaException) { } else if (exception instanceof IOException) {
onReCaptchaException(); Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
} else if (exception instanceof IOException) { } else if (exception instanceof YoutubeStreamExtractor.GemaException) {
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show(); Toast.makeText(context, R.string.blocked_by_gema, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.GemaException) { } else if (exception instanceof YoutubeStreamExtractor.LiveStreamException) {
Toast.makeText(context, R.string.blocked_by_gema, Toast.LENGTH_LONG).show(); Toast.makeText(context, R.string.live_streams_not_supported, Toast.LENGTH_LONG).show();
} else if (exception instanceof YoutubeStreamExtractor.LiveStreamException) { } else if (exception instanceof ContentNotAvailableException) {
Toast.makeText(context, R.string.live_streams_not_supported, Toast.LENGTH_LONG).show(); Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
} else if (exception instanceof ContentNotAvailableException) { } else {
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show(); int errorId = exception instanceof YoutubeStreamExtractor.DecryptException ? R.string.youtube_signature_decryption_error :
} else { exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
int errorId = exception instanceof YoutubeStreamExtractor.DecryptException ? R.string.youtube_signature_decryption_error : ErrorActivity.reportError(mainHandler, context, exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(serviceId), url, errorId));
exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
ErrorActivity.reportError(mainHandler, context, exception, MainActivity.class, null, ErrorActivity.ErrorInfo.make(UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(serviceId), url, errorId));
}
} }
}); });
stopSelf(); stopSelf();

View File

@ -1,9 +1,12 @@
package org.schabi.newpipe.player; package org.schabi.newpipe.player;
import android.content.Intent; import android.content.Intent;
import android.view.MenuItem;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import static org.schabi.newpipe.player.PopupVideoPlayer.ACTION_CLOSE;
public final class PopupVideoPlayerActivity extends ServicePlayerActivity { public final class PopupVideoPlayerActivity extends ServicePlayerActivity {
private static final String TAG = "PopupVideoPlayerActivity"; private static final String TAG = "PopupVideoPlayerActivity";
@ -36,4 +39,25 @@ public final class PopupVideoPlayerActivity extends ServicePlayerActivity {
((PopupVideoPlayer.VideoPlayerImpl) player).removeActivityListener(this); ((PopupVideoPlayer.VideoPlayerImpl) player).removeActivityListener(this);
} }
} }
@Override
public int getPlayerOptionMenuResource() {
return R.menu.menu_play_queue_popup;
}
@Override
public boolean onPlayerOptionSelected(MenuItem item) {
if (item.getItemId() == R.id.action_switch_background) {
this.player.setRecovery();
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
getApplicationContext().startService(getSwitchIntent(BackgroundPlayer.class));
return true;
}
return false;
}
@Override
public Intent getPlayerShutdownIntent() {
return new Intent(ACTION_CLOSE);
}
} }

View File

@ -100,6 +100,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
public abstract void stopPlayerListener(); public abstract void stopPlayerListener();
public abstract int getPlayerOptionMenuResource();
public abstract boolean onPlayerOptionSelected(MenuItem item);
public abstract Intent getPlayerShutdownIntent();
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Activity Lifecycle // Activity Lifecycle
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -134,6 +139,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_play_queue, menu); getMenuInflater().inflate(R.menu.menu_play_queue, menu);
getMenuInflater().inflate(getPlayerOptionMenuResource(), menu);
return true; return true;
} }
@ -153,8 +159,13 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
case R.id.action_system_audio: case R.id.action_system_audio:
startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS)); startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
return true; return true;
case R.id.action_switch_main:
this.player.setRecovery();
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
getApplicationContext().startActivity(getSwitchIntent(MainVideoPlayer.class));
return true;
} }
return super.onOptionsItemSelected(item); return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
} }
@Override @Override
@ -163,6 +174,17 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
unbind(); unbind();
} }
protected Intent getSwitchIntent(final Class clazz) {
return NavigationHelper.getPlayerIntent(
getApplicationContext(),
clazz,
this.player.getPlayQueue(),
this.player.getRepeatMode(),
this.player.getPlaybackSpeed(),
this.player.getPlaybackPitch(),
null
);
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Service Connection // Service Connection
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -288,14 +310,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
final float playbackSpeed = BasePlayer.PLAYBACK_SPEEDS[i]; final float playbackSpeed = BasePlayer.PLAYBACK_SPEEDS[i];
final String formattedSpeed = formatSpeed(playbackSpeed); final String formattedSpeed = formatSpeed(playbackSpeed);
final MenuItem item = playbackSpeedPopupMenu.getMenu().add(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedSpeed); final MenuItem item = playbackSpeedPopupMenu.getMenu().add(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedSpeed);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { item.setOnMenuItemClickListener(menuItem -> {
@Override if (player == null) return false;
public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
player.setPlaybackSpeed(playbackSpeed); player.setPlaybackSpeed(playbackSpeed);
return true; return true;
}
}); });
} }
} }
@ -308,14 +327,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
final float playbackPitch = BasePlayer.PLAYBACK_PITCHES[i]; final float playbackPitch = BasePlayer.PLAYBACK_PITCHES[i];
final String formattedPitch = formatPitch(playbackPitch); final String formattedPitch = formatPitch(playbackPitch);
final MenuItem item = playbackPitchPopupMenu.getMenu().add(PLAYBACK_PITCH_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedPitch); final MenuItem item = playbackPitchPopupMenu.getMenu().add(PLAYBACK_PITCH_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedPitch);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { item.setOnMenuItemClickListener(menuItem -> {
@Override if (player == null) return false;
public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
player.setPlaybackPitch(playbackPitch); player.setPlaybackPitch(playbackPitch);
return true; return true;
}
}); });
} }
} }
@ -323,24 +339,18 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
private void buildItemPopupMenu(final PlayQueueItem item, final View view) { private void buildItemPopupMenu(final PlayQueueItem item, final View view) {
final PopupMenu menu = new PopupMenu(this, view); final PopupMenu menu = new PopupMenu(this, view);
final MenuItem remove = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 0, Menu.NONE, R.string.play_queue_remove); final MenuItem remove = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 0, Menu.NONE, R.string.play_queue_remove);
remove.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { remove.setOnMenuItemClickListener(menuItem -> {
@Override if (player == null) return false;
public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
final int index = player.getPlayQueue().indexOf(item); final int index = player.getPlayQueue().indexOf(item);
if (index != -1) player.getPlayQueue().remove(index); if (index != -1) player.getPlayQueue().remove(index);
return true; return true;
}
}); });
final MenuItem detail = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 1, Menu.NONE, R.string.play_queue_stream_detail); final MenuItem detail = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 1, Menu.NONE, R.string.play_queue_stream_detail);
detail.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { detail.setOnMenuItemClickListener(menuItem -> {
@Override onOpenDetail(item.getServiceId(), item.getUrl(), item.getTitle());
public boolean onMenuItemClick(MenuItem menuItem) { return true;
onOpenDetail(item.getServiceId(), item.getUrl(), item.getTitle());
return true;
}
}); });
menu.show(); menu.show();

View File

@ -219,16 +219,20 @@ public final class ExtractorHelper {
// as it will cause a infinite loop if it is // as it will cause a infinite loop if it is
Throwable cause, getCause = throwable; Throwable cause, getCause = throwable;
// Check if throwable is a subclass of any of the filtered classes
final Class throwableClass = throwable.getClass();
for (Class<?> causesEl : causesToCheck) { for (Class<?> causesEl : causesToCheck) {
if (throwable.getClass().isAssignableFrom(causesEl)) { if (causesEl.isAssignableFrom(throwableClass)) {
return true; return true;
} }
} }
// Iteratively checks if the root cause of the throwable is a subclass of the filtered class
while ((cause = throwable.getCause()) != null && getCause != cause) { while ((cause = throwable.getCause()) != null && getCause != cause) {
getCause = cause; getCause = cause;
final Class causeClass = cause.getClass();
for (Class<?> causesEl : causesToCheck) { for (Class<?> causesEl : causesToCheck) {
if (cause.getClass().isAssignableFrom(causesEl)) { if (causesEl.isAssignableFrom(causeClass)) {
return true; return true;
} }
} }

View File

@ -1,7 +1,6 @@
package org.schabi.newpipe.util; package org.schabi.newpipe.util;
import android.app.Activity; import android.app.Activity;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -21,9 +20,7 @@ import org.schabi.newpipe.download.DownloadActivity;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.channel.ChannelFragment; import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
@ -46,8 +43,6 @@ import org.schabi.newpipe.settings.SettingsActivity;
public class NavigationHelper { public class NavigationHelper {
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag"; public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
public static final int PENDING_INTENT_OPEN_PLAYER_ACTIVITY = 1546;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Players // Players
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -92,9 +87,13 @@ public class NavigationHelper {
context.startActivity(getPlayerIntent(context, MainVideoPlayer.class, queue)); context.startActivity(getPlayerIntent(context, MainVideoPlayer.class, queue));
} }
public static void playOnPopupPlayer(final Context context, final PlayQueue queue) { public static void playOnPopupPlayer(final Activity activity, final PlayQueue queue) {
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show(); if (!PermissionHelper.isPopupEnabled(activity)) {
context.startService(getPlayerIntent(context, PopupVideoPlayer.class, queue)); PermissionHelper.showPopupEnablementToast(activity);
return;
}
Toast.makeText(activity, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
activity.startService(getPlayerIntent(activity, PopupVideoPlayer.class, queue));
} }
public static void playOnBackgroundPlayer(final Context context, final PlayQueue queue) { public static void playOnBackgroundPlayer(final Context context, final PlayQueue queue) {
@ -102,9 +101,13 @@ public class NavigationHelper {
context.startService(getPlayerIntent(context, BackgroundPlayer.class, queue)); context.startService(getPlayerIntent(context, BackgroundPlayer.class, queue));
} }
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue) { public static void enqueueOnPopupPlayer(final Activity activity, final PlayQueue queue) {
Toast.makeText(context, R.string.popup_playing_append, Toast.LENGTH_SHORT).show(); if (!PermissionHelper.isPopupEnabled(activity)) {
context.startService(getPlayerEnqueueIntent(context, PopupVideoPlayer.class, queue)); PermissionHelper.showPopupEnablementToast(activity);
return;
}
Toast.makeText(activity, R.string.popup_playing_append, Toast.LENGTH_SHORT).show();
activity.startService(getPlayerEnqueueIntent(activity, PopupVideoPlayer.class, queue));
} }
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue) { public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue) {
@ -264,34 +267,22 @@ public class NavigationHelper {
return true; return true;
} }
public static void openBackgroundPlayerControl(final Context context) { public static Intent getBackgroundPlayerActivityIntent(final Context context) {
openServicePlayerControl(context, BackgroundPlayerActivity.class); return getServicePlayerActivityIntent(context, BackgroundPlayerActivity.class);
} }
public static void openPopupPlayerControl(final Context context) { public static Intent getPopupPlayerActivityIntent(final Context context) {
openServicePlayerControl(context, PopupVideoPlayerActivity.class); return getServicePlayerActivityIntent(context, PopupVideoPlayerActivity.class);
} }
private static void openServicePlayerControl(final Context context, final Class activityClass) { private static Intent getServicePlayerActivityIntent(final Context context,
Intent intent = getServicePlayerControlIntent(context, activityClass); final Class activityClass) {
context.startActivity(intent); Intent intent = new Intent(context, activityClass);
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
public static Intent getServicePlayerControlIntent(final Context context, final Class activityClass) {
final Intent intent = new Intent(context, activityClass);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} }
return intent; return intent;
} }
public static PendingIntent getServicePlayerControlPendingIntent(final Context context, final Class activityClass) {
Intent intent = getServicePlayerControlIntent(context, activityClass);
PendingIntent pIntent = PendingIntent.getActivity(context, PENDING_INTENT_OPEN_PLAYER_ACTIVITY, intent, 0);
return pIntent;
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Link handling // Link handling
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/

View File

@ -11,6 +11,11 @@ import android.provider.Settings;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.view.Gravity;
import android.widget.TextView;
import android.widget.Toast;
import org.schabi.newpipe.R;
public class PermissionHelper { public class PermissionHelper {
public static final int PERMISSION_WRITE_STORAGE = 778; public static final int PERMISSION_WRITE_STORAGE = 778;
@ -92,4 +97,16 @@ public class PermissionHelper {
return false; return false;
}else return true; }else return true;
} }
public static boolean isPopupEnabled(Activity activity) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
PermissionHelper.checkSystemAlertWindowPermission(activity);
}
public static void showPopupEnablementToast(Context context) {
Toast toast = Toast.makeText(context, R.string.msg_popup_permission, Toast.LENGTH_LONG);
TextView messageView = toast.getView().findViewById(android.R.id.message);
if (messageView != null) messageView.setGravity(Gravity.CENTER);
toast.show();
}
} }

View File

@ -31,10 +31,14 @@
android:layout_below="@+id/itemTitleView" android:layout_below="@+id/itemTitleView"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true" android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_uploader_text_size" android:textSize="@dimen/video_item_search_uploader_text_size"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" tools:visibility="visible"
tools:text="TYPE" /> tools:text="UPLOADER" />
</RelativeLayout> </RelativeLayout>

View File

@ -17,4 +17,9 @@
android:orderInCategory="996" android:orderInCategory="996"
android:title="@string/play_queue_audio_settings" android:title="@string/play_queue_audio_settings"
app:showAsAction="never"/> app:showAsAction="never"/>
<item android:id="@+id/action_switch_main"
android:orderInCategory="999"
android:title="@string/switch_to_main"
app:showAsAction="never"/>
</menu> </menu>

View File

@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.schabi.newpipe.history.HistoryActivity">
<item android:id="@+id/action_switch_popup"
android:orderInCategory="1999"
android:title="@string/switch_to_popup"
app:showAsAction="never"/>
</menu>

View File

@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.schabi.newpipe.history.HistoryActivity">
<item android:id="@+id/action_switch_background"
android:orderInCategory="1999"
android:title="@string/switch_to_background"
app:showAsAction="never"/>
</menu>

View File

@ -6,16 +6,16 @@
<item <item
android:icon="@drawable/ic_screen_rotation_white" android:icon="@drawable/ic_screen_rotation_white"
android:id="@+id/toggleOrientation" android:id="@+id/toggleOrientation"
android:title="Toggle orientation" android:title="@string/toggle_orientation"
app:showAsAction="always|withText" /> app:showAsAction="always|withText" />
<item <item
android:icon="@drawable/ic_fullscreen_exit_white" android:icon="@drawable/ic_fullscreen_exit_white"
android:id="@+id/switchPopup" android:id="@+id/switchPopup"
android:title="Switch to popup" android:title="@string/switch_to_popup"
app:showAsAction="always|withText" /> app:showAsAction="always|withText" />
<item android:icon="?audio" <item android:icon="?audio"
android:id="@+id/switchBackground" android:id="@+id/switchBackground"
android:title="Switch to background" android:title="@string/switch_to_background"
app:showAsAction="always|withText" /> app:showAsAction="always|withText" />
</menu> </menu>

View File

@ -124,6 +124,11 @@
<string name="unknown_content">[Unknown]</string> <string name="unknown_content">[Unknown]</string>
<string name="toggle_orientation">Toggle Orientation</string>
<string name="switch_to_background">Switch to Background</string>
<string name="switch_to_popup">Switch to Popup</string>
<string name="switch_to_main">Switch to Main</string>
<!-- error strings --> <!-- error strings -->
<string name="general_error">Error</string> <string name="general_error">Error</string>
<string name="network_error">Network error</string> <string name="network_error">Network error</string>