Skip to content

Commit

Permalink
background UI
Browse files Browse the repository at this point in the history
  • Loading branch information
watson1982 authored Nov 15, 2023
1 parent 1eaed50 commit 9fbe434
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 147 deletions.
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
android:name=".ui.activity.DetailActivity"
android:screenOrientation="sensorLandscape"
android:supportsPictureInPicture="true"
android:launchMode="singleTask"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />
<activity
android:name=".ui.activity.HistoryActivity"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.PermissionChecker;

import com.blankj.utilcode.util.ActivityUtils;
import com.github.tvbox.osc.R;
import com.github.tvbox.osc.callback.EmptyCallback;
import com.github.tvbox.osc.callback.LoadingCallback;
import com.github.tvbox.osc.ui.activity.DetailActivity;
import com.github.tvbox.osc.util.AppManager;
import com.github.tvbox.osc.util.HawkConfig;
import com.github.tvbox.osc.util.LocaleHelper;
Expand Down Expand Up @@ -238,6 +239,10 @@ public void jumpActivity(Class<? extends BaseActivity> clazz) {
}

public void jumpActivity(Class<? extends BaseActivity> clazz, Bundle bundle) {
if (DetailActivity.class.isAssignableFrom(clazz) && Hawk.get(HawkConfig.BACKGROUND_PLAY_TYPE, 0) == 2) {
//1.重新打开singleTask的页面(关闭小窗) 2.关闭画中画,重进detail再开启画中画会闪退
ActivityUtils.finishActivity(DetailActivity.class);
}
Intent intent = new Intent(mContext, clazz);
intent.putExtras(bundle);
startActivity(intent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class RefreshEvent {
public static final int TYPE_EPG_URL_CHANGE = 14;
public static final int TYPE_APP_REFRESH = 15;
public static final int TYPE_FILTER_CHANGE = 16;
public static final int TYPE_REFRESH_NOTIFY = 17;
public int type;
public Object obj;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.github.tvbox.osc.base.BaseActivity;
import com.github.tvbox.osc.bean.IJKCode;
import com.github.tvbox.osc.bean.ParseBean;
import com.github.tvbox.osc.event.RefreshEvent;
import com.github.tvbox.osc.player.thirdparty.Kodi;
import com.github.tvbox.osc.player.thirdparty.MXPlayer;
import com.github.tvbox.osc.player.thirdparty.ReexPlayer;
Expand All @@ -50,7 +51,7 @@
import com.orhanobut.hawk.Hawk;
import com.owen.tvrecyclerview.widget.TvRecyclerView;
import com.owen.tvrecyclerview.widget.V7LinearLayoutManager;

import org.greenrobot.eventbus.EventBus;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -1062,6 +1063,7 @@ protected void updateSeekUI(int curr, int seekTo, int duration) {
@Override
protected void onPlayStateChanged(int playState) {
super.onPlayStateChanged(playState);
EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_REFRESH_NOTIFY, null));
switch (playState) {
case VideoView.STATE_IDLE:
break;
Expand Down
86 changes: 60 additions & 26 deletions app/src/main/java/com/github/tvbox/osc/server/PlayService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,31 @@
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.IBinder;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;

import androidx.core.graphics.drawable.IconCompat;
import com.blankj.utilcode.util.LogUtils;
import com.github.tvbox.osc.R;
import com.github.tvbox.osc.base.App;
import com.github.tvbox.osc.event.RefreshEvent;
import com.github.tvbox.osc.player.MyVideoView;
import com.github.tvbox.osc.player.controller.VodController;
import com.github.tvbox.osc.ui.activity.DetailActivity;
import com.github.tvbox.osc.ui.activity.HomeActivity;

import xyz.doikki.videoplayer.player.AbstractPlayer;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONObject;

public class PlayService extends Service {

static String videoInfo = "TvBox&&第一集";
private static MyVideoView videoView;

public static void start(MyVideoView controller) {
public static void start(MyVideoView controller,String currentVideoInfo) {
videoInfo = currentVideoInfo;
PlayService.videoView = controller;
ContextCompat.startForegroundService(App.getInstance(), new Intent(App.getInstance(), PlayService.class));
}
Expand All @@ -41,7 +46,7 @@ public static void stop() {
@Override
public void onCreate() {
super.onCreate();

EventBus.getDefault().register(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, "My Channel", NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Expand All @@ -51,32 +56,61 @@ public void onCreate() {

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

Notification.Builder builder = new Notification.Builder(this)
.setContentTitle("My Service")
.setContentText("Running in the background")
startForeground(NOTIFICATION_ID, buildNotification());
videoView.start();
return START_NOT_STICKY;
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void refresh(RefreshEvent event){
if (event.type == RefreshEvent.TYPE_REFRESH_NOTIFY){
if (event.obj != null) {
videoInfo = event.obj.toString();
}
NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, buildNotification());
}
}

private Notification buildNotification(){
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(videoInfo.split("&&")[0])
.setContentText("正在播放: "+videoInfo.split("&&")[1])
.setSmallIcon(R.drawable.app_icon)
.setContentIntent(getPendingIntentActivity());

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID);
}
// 创建通知栏操作
NotificationCompat.Action previousAction = buildNotificationAction(
R.drawable.ic_play_pre, "上一集", getPendingIntent(DetailActivity.BROADCAST_ACTION_PREV));
NotificationCompat.Action pauseAction = buildNotificationAction(
R.drawable.ic_pause, videoView.isPlaying()?"暂停":"播放",getPendingIntent(DetailActivity.BROADCAST_ACTION_PLAYPAUSE));
NotificationCompat.Action nextAction = buildNotificationAction(
R.drawable.ic_play_next, "下一集", getPendingIntent(DetailActivity.BROADCAST_ACTION_NEXT));

Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
videoView.start();
return START_NOT_STICKY;
// 将通知栏操作添加到通知中
builder.addAction(previousAction);
builder.addAction(pauseAction);
builder.addAction(nextAction);

return builder.build();
}

private NotificationCompat.Action buildNotificationAction(int iconResId, String title, PendingIntent intent) {
final IconCompat icon = IconCompat.createWithResource(App.getInstance(), iconResId);
// 创建通知栏操作
return new NotificationCompat.Action.Builder(icon, title, intent).build();
}

private PendingIntent getPendingIntentActivity() {
Intent intentMain = new Intent(this, HomeActivity.class);
Intent intentPlayer = new Intent(this, DetailActivity.class);
Intent[] intents = {intentMain, intentPlayer};
return PendingIntent.getActivities(this, 1, intents, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Intent intent = new Intent(this, DetailActivity.class);
return PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
public static PendingIntent getPendingIntent(int actionCode) {
return PendingIntent.getBroadcast(App.getInstance(), actionCode, new Intent(DetailActivity.BROADCAST_ACTION).putExtra("action", actionCode).setPackage(App.getInstance().getPackageName()),PendingIntent.FLAG_UPDATE_CURRENT);
}

@Override
public void onDestroy() {
//LogUtils.d("PlayService onDestroy");
EventBus.getDefault().unregister(this);
stopForeground(true);
}

Expand All @@ -85,4 +119,4 @@ public void onDestroy() {
public IBinder onBind(Intent intent) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ public class DetailActivity extends BaseActivity {
private V7GridLayoutManager mGridViewLayoutMgr = null;

private BroadcastReceiver pipActionReceiver;
private static final int PIP_BOARDCAST_ACTION_PREV = 0;
private static final int PIP_BOARDCAST_ACTION_PLAYPAUSE = 1;
private static final int PIP_BOARDCAST_ACTION_NEXT = 2;
public static final String BROADCAST_ACTION = "VOD_CONTROL";
public static final int BROADCAST_ACTION_PREV = 0;
public static final int BROADCAST_ACTION_PLAYPAUSE = 1;
public static final int BROADCAST_ACTION_NEXT = 2;

private ImageView tvPlayUrl;
/**
Expand Down Expand Up @@ -158,16 +159,14 @@ protected void init() {
protected void onResume() {
super.onResume();
openBackgroundPlay = false;
if (ServiceUtils.isServiceRunning(PlayService.class)){
PlayService.stop();
}
playServerSwitch(false);
}

@Override
protected void onPause() {
super.onPause();
if (openBackgroundPlay){
PlayService.start(playFragment.getPlayer());
playServerSwitch(true);
}
}

Expand Down Expand Up @@ -876,6 +875,7 @@ private void insertVod(String sourceKey, VodInfo vodInfo) {

@Override
protected void onDestroy() {
registerActionReceiver(false);
super.onDestroy();
// 注销广播接收器
if (mHomeKeyReceiver != null) {
Expand Down Expand Up @@ -919,9 +919,9 @@ public void onUserLeaveHint() {
ratio = new Rational(16, 9);
}
List<RemoteAction> actions = new ArrayList<>();
actions.add(generateRemoteAction(android.R.drawable.ic_media_previous, PIP_BOARDCAST_ACTION_PREV, "Prev", "Play Previous"));
actions.add(generateRemoteAction(android.R.drawable.ic_media_play, PIP_BOARDCAST_ACTION_PLAYPAUSE, "Play", "Play/Pause"));
actions.add(generateRemoteAction(android.R.drawable.ic_media_next, PIP_BOARDCAST_ACTION_NEXT, "Next", "Play Next"));
actions.add(generateRemoteAction(android.R.drawable.ic_media_previous, BROADCAST_ACTION_PREV, "Prev", "Play Previous"));
actions.add(generateRemoteAction(android.R.drawable.ic_media_play, BROADCAST_ACTION_PLAYPAUSE, "Play", "Play/Pause"));
actions.add(generateRemoteAction(android.R.drawable.ic_media_next, BROADCAST_ACTION_NEXT, "Next", "Play Next"));
PictureInPictureParams params = new PictureInPictureParams.Builder()
.setAspectRatio(ratio)
.setActions(actions).build();
Expand All @@ -935,8 +935,7 @@ public void onUserLeaveHint() {
playFragment.getVodController().togglePlay();
}
},400);
}
super.onUserLeaveHint();
}
}

@RequiresApi(api = Build.VERSION_CODES.O)
Expand All @@ -945,44 +944,70 @@ private RemoteAction generateRemoteAction(int iconResId, int actionCode, String
PendingIntent.getBroadcast(
DetailActivity.this,
actionCode,
new Intent("PIP_VOD_CONTROL").putExtra("action", actionCode),
new Intent(BROADCAST_ACTION).putExtra("action", actionCode),
0);
final Icon icon = Icon.createWithResource(DetailActivity.this, iconResId);
return (new RemoteAction(icon, title, desc, intent));
}

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
if (supportsPiPMode() && isInPictureInPictureMode) {
/**
* 事件接收广播(画中画/后台播放点击事件)
* @param isRegister 注册/注销
*/
private void registerActionReceiver(boolean isRegister){
if (isRegister) {
pipActionReceiver = new BroadcastReceiver() {

@Override
public void onReceive(Context context, Intent intent) {
if (intent == null || !intent.getAction().equals("PIP_VOD_CONTROL") || playFragment.getVodController() == null) {
if (intent == null || !intent.getAction().equals(BROADCAST_ACTION) || playFragment.getVodController() == null) {
return;
}

int currentStatus = intent.getIntExtra("action", 1);
if (currentStatus == PIP_BOARDCAST_ACTION_PREV) {
int currentStatus = intent.getIntExtra("action", 1);
if (currentStatus == BROADCAST_ACTION_PREV) {
playFragment.playPrevious();
} else if (currentStatus == PIP_BOARDCAST_ACTION_PLAYPAUSE) {
} else if (currentStatus == BROADCAST_ACTION_PLAYPAUSE) {
playFragment.getVodController().togglePlay();
} else if (currentStatus == PIP_BOARDCAST_ACTION_NEXT) {
} else if (currentStatus == BROADCAST_ACTION_NEXT) {
playFragment.playNext(false);
}
}
};
registerReceiver(pipActionReceiver, new IntentFilter("PIP_VOD_CONTROL"));
registerReceiver(pipActionReceiver, new IntentFilter(BROADCAST_ACTION));

} else {
unregisterReceiver(pipActionReceiver);
pipActionReceiver = null;
if (pipActionReceiver!=null){
unregisterReceiver(pipActionReceiver);
pipActionReceiver = null;
}
if (playFragment.getPlayer().isPlaying()){
playFragment.getVodController().togglePlay();
}
}
}

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
registerActionReceiver(supportsPiPMode() && isInPictureInPictureMode);
}

/**
* 后台播放服务开关,开启时注册操作广播,关闭时注销
*/
private void playServerSwitch(boolean open){
if (open){
VodInfo.VodSeries vod = vodInfo.seriesMap.get(vodInfo.playFlag).get(vodInfo.playIndex);
PlayService.start(playFragment.getPlayer(),vodInfo.name+"&&"+vod.name);
registerActionReceiver(true);
}else {
if (ServiceUtils.isServiceRunning(PlayService.class)){
PlayService.stop();
registerActionReceiver(false);
}
}
}

@Override
public void onBackPressed() {
Expand Down Expand Up @@ -1073,4 +1098,4 @@ void toggleSubtitleTextSize() {
}
EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_SUBTITLE_SIZE_CHANGE, subtitleTextSize));
}
}
}
Loading

0 comments on commit 9fbe434

Please sign in to comment.