From 0fb8106ebfa7f2f2352bf443cb0a71f53203f174 Mon Sep 17 00:00:00 2001 From: FongMi Date: Thu, 20 Oct 2022 18:17:54 +0800 Subject: [PATCH] support live - part 3 --- .../android/tv/ui/activity/LiveActivity.java | 108 +++++++++++++++++- .../android/tv/ui/adapter/ChannelAdapter.java | 80 ++++++++++--- .../android/tv/ui/adapter/GroupAdapter.java | 66 ++++++++--- .../tv/ui/adapter/holder/ChannelHolder.java | 43 +++++++ .../tv/ui/adapter/holder/GroupHolder.java | 35 ++++++ .../ui/custom/CustomHorizontalGridView.java | 3 +- .../res/drawable/selector_live_channel.xml | 2 +- .../res/drawable/selector_live_group.xml | 2 +- .../res/layout/adapter_live_channel.xml | 5 +- .../res/layout/adapter_live_group.xml | 7 +- app/src/leanback/res/values/styles.xml | 2 + .../com/fongmi/android/tv/api/LiveConfig.java | 4 +- .../com/fongmi/android/tv/bean/Channel.java | 21 +++- .../com/fongmi/android/tv/player/ExoUtil.java | 2 + .../com/fongmi/android/tv/player/Players.java | 7 ++ .../android/tv/ui/custom/CustomWebView.java | 2 - 16 files changed, 329 insertions(+), 60 deletions(-) create mode 100644 app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/ChannelHolder.java create mode 100644 app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/GroupHolder.java diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java index 3523fc547..0c7d64d4f 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java @@ -1,15 +1,121 @@ package com.fongmi.android.tv.ui.activity; +import android.app.Activity; +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.view.View; + import androidx.viewbinding.ViewBinding; +import com.fongmi.android.tv.api.LiveConfig; +import com.fongmi.android.tv.bean.Channel; +import com.fongmi.android.tv.bean.Group; import com.fongmi.android.tv.databinding.ActivityLiveBinding; +import com.fongmi.android.tv.event.PlayerEvent; +import com.fongmi.android.tv.player.Players; +import com.fongmi.android.tv.ui.adapter.ChannelAdapter; +import com.fongmi.android.tv.ui.adapter.GroupAdapter; +import com.fongmi.android.tv.utils.Prefers; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; +import com.google.android.exoplayer2.ui.StyledPlayerView; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; -public class LiveActivity extends BaseActivity { +public class LiveActivity extends BaseActivity implements GroupAdapter.OnItemClickListener, ChannelAdapter.OnItemClickListener { private ActivityLiveBinding mBinding; + private ChannelAdapter mChannelAdapter; + private GroupAdapter mGroupAdapter; + private Handler mHandler; + private Players mPlayers; + + public static void start(Activity activity) { + activity.startActivity(new Intent(activity, LiveActivity.class)); + } + + private StyledPlayerView getPlayerView() { + return Prefers.getRender() == 0 ? mBinding.surface : mBinding.texture; + } @Override protected ViewBinding getBinding() { return mBinding = ActivityLiveBinding.inflate(getLayoutInflater()); } + + @Override + protected void initView() { + mHandler = new Handler(Looper.getMainLooper()); + mPlayers = new Players().init(); + setRecyclerView(); + setVideoView(); + } + + @Override + protected void initEvent() { + EventBus.getDefault().register(this); + } + + private void setRecyclerView() { + mBinding.group.setAdapter(mGroupAdapter = new GroupAdapter(this)); + mBinding.channel.setAdapter(mChannelAdapter = new ChannelAdapter(this)); + mGroupAdapter.addAll(LiveConfig.get().getLives().get(0).getGroups()); + } + + private void setVideoView() { + getPlayerView().setPlayer(mPlayers.exo()); + getPlayerView().setVisibility(View.VISIBLE); + getPlayerView().setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL); + } + + @Override + public void onItemClick(Group item) { + mChannelAdapter.addAll(item); + } + + @Override + public void onItemClick(Channel item) { + mPlayers.start(item, 0); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPlayerEvent(PlayerEvent event) { + switch (event.getState()) { + case 0: + break; + case Player.STATE_IDLE: + break; + case Player.STATE_BUFFERING: + //mBinding.widget.progress.getRoot().setVisibility(View.VISIBLE); + break; + case Player.STATE_READY: + mPlayers.setRetry(0); + //mBinding.widget.progress.getRoot().setVisibility(View.GONE); + break; + case Player.STATE_ENDED: + break; + default: + if (!event.isRetry() || mPlayers.addRetry() > 3) onError(event.getMsg()); + else onRetry(); + break; + } + } + + private void onError(String msg) { + + } + + private void onRetry() { + mPlayers.start(mChannelAdapter.getCurrent(), 0); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mPlayers.release(); + EventBus.getDefault().unregister(this); + } } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/ChannelAdapter.java b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/ChannelAdapter.java index 57e4dfff7..5ff2dc4b1 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/ChannelAdapter.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/ChannelAdapter.java @@ -9,17 +9,56 @@ import androidx.recyclerview.widget.RecyclerView; import com.fongmi.android.tv.bean.Channel; import com.fongmi.android.tv.bean.Group; import com.fongmi.android.tv.databinding.AdapterLiveChannelBinding; +import com.fongmi.android.tv.ui.adapter.holder.ChannelHolder; import java.util.ArrayList; import java.util.List; -public class ChannelAdapter extends RecyclerView.Adapter { +public class ChannelAdapter extends RecyclerView.Adapter { + private OnItemClickListener mListener; private final List mItems; + private Channel current; + private boolean focus; + private int position; private Group group; - public ChannelAdapter() { + public ChannelAdapter(OnItemClickListener listener) { this.mItems = new ArrayList<>(); + this.mListener = listener; + } + + public interface OnItemClickListener { + + void onItemClick(Channel item); + } + + private Channel getItem() { + return mItems.get(position); + } + + public Channel getCurrent() { + return current; + } + + public void setCurrent(Channel current) { + this.current = current; + } + + public boolean isFocus() { + return focus; + } + + public void setFocus(boolean focus) { + this.focus = focus; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; } public Group getGroup() { @@ -37,6 +76,22 @@ public class ChannelAdapter extends RecyclerView.Adapter mItems.size() - 1) return; + //if (!getGroup().isHidden()) getItem().putKeep(); + mListener.onItemClick(getItem()); + getGroup().setPosition(position); + getItem().setGroup(getGroup()); + setCurrent(getItem()); + setSelected(); + } + @Override public int getItemCount() { return mItems.size(); @@ -44,25 +99,12 @@ public class ChannelAdapter extends RecyclerView.Adapter { +public class GroupAdapter extends RecyclerView.Adapter { + private OnItemClickListener mListener; private final List mItems; private final List mHides; + private boolean focus; + private int position; - public GroupAdapter() { + public GroupAdapter(OnItemClickListener listener) { this.mItems = new ArrayList<>(); this.mHides = new ArrayList<>(); + this.mListener = listener; + } + + public interface OnItemClickListener { + + void onItemClick(Group item); + } + + private Group getItem() { + return mItems.get(position); + } + + public boolean isFocus() { + return focus; + } + + public void setFocus(boolean focus) { + this.focus = focus; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; } public void addAll(List items) { @@ -29,7 +59,17 @@ public class GroupAdapter extends RecyclerView.Adapter } private void addGroup(List items) { - for (Group item : items) if (item.isHidden()) mHides.add(item);else mItems.add(item); + for (Group item : items) if (item.isHidden()) mHides.add(item); else mItems.add(item); + } + + public void setSelected() { + for (int i = 0; i < mItems.size(); i++) mItems.get(i).setSelect(i == position); + notifyDataSetChanged(); + setFocus(true); + } + + public void setType() { + mListener.onItemClick(getItem()); } @Override @@ -39,24 +79,12 @@ public class GroupAdapter extends RecyclerView.Adapter @NonNull @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new ViewHolder(AdapterLiveGroupBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + public GroupHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new GroupHolder(this, AdapterLiveGroupBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); } @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - Group item = mItems.get(position); - holder.binding.name.setText(item.getName()); - holder.binding.icon.setVisibility(item.getVisible()); - } - - public static class ViewHolder extends RecyclerView.ViewHolder { - - private final AdapterLiveGroupBinding binding; - - public ViewHolder(@NonNull AdapterLiveGroupBinding binding) { - super(binding.getRoot()); - this.binding = binding; - } + public void onBindViewHolder(@NonNull GroupHolder holder, int position) { + holder.setView(mItems.get(position)); } } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/ChannelHolder.java b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/ChannelHolder.java new file mode 100644 index 000000000..7f2f225b5 --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/ChannelHolder.java @@ -0,0 +1,43 @@ +package com.fongmi.android.tv.ui.adapter.holder; + +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.fongmi.android.tv.bean.Channel; +import com.fongmi.android.tv.databinding.AdapterLiveChannelBinding; +import com.fongmi.android.tv.ui.adapter.ChannelAdapter; + +public class ChannelHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { + + private final AdapterLiveChannelBinding binding; + private final ChannelAdapter adapter; + + public ChannelHolder(ChannelAdapter adapter, @NonNull AdapterLiveChannelBinding binding) { + super(binding.getRoot()); + this.binding = binding; + this.adapter = adapter; + itemView.setOnClickListener(this); + itemView.setOnLongClickListener(this); + } + + @Override + public void onClick(View view) { + adapter.setPosition(getLayoutPosition()); + adapter.setChannel(); + } + + @Override + public boolean onLongClick(View view) { + adapter.setPosition(getLayoutPosition()); + return false; + } + + public void setView(Channel item) { + itemView.setSelected(item.isSelect()); + binding.name.setText(item.getName()); + binding.number.setText(item.getNumber()); + binding.icon.setVisibility(item.getVisible()); + } +} diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/GroupHolder.java b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/GroupHolder.java new file mode 100644 index 000000000..b7df278e8 --- /dev/null +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/adapter/holder/GroupHolder.java @@ -0,0 +1,35 @@ +package com.fongmi.android.tv.ui.adapter.holder; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +import com.fongmi.android.tv.bean.Group; +import com.fongmi.android.tv.databinding.AdapterLiveGroupBinding; +import com.fongmi.android.tv.ui.adapter.GroupAdapter; + +public class GroupHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + + private final AdapterLiveGroupBinding binding; + private final GroupAdapter adapter; + + public GroupHolder(GroupAdapter adapter, AdapterLiveGroupBinding binding) { + super(binding.getRoot()); + this.binding = binding; + this.adapter = adapter; + itemView.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + adapter.setPosition(getLayoutPosition()); + adapter.setSelected(); + adapter.setType(); + } + + public void setView(Group item) { + itemView.setSelected(item.isSelect()); + binding.name.setText(item.getName()); + binding.icon.setVisibility(item.getVisible()); + } +} diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomHorizontalGridView.java b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomHorizontalGridView.java index 77794433a..747a228da 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomHorizontalGridView.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomHorizontalGridView.java @@ -41,8 +41,7 @@ public class CustomHorizontalGridView extends HorizontalGridView { @Override public View focusSearch(View focused, int direction) { if (focused != null) { - FocusFinder finder = FocusFinder.getInstance(); - View found = finder.findNextFocus(this, focused, direction); + View found = FocusFinder.getInstance().findNextFocus(this, focused, direction); if (direction == View.FOCUS_LEFT || direction == View.FOCUS_RIGHT) { if ((found == null || found.getId() != R.id.text) && getScrollState() == SCROLL_STATE_IDLE) { focused.clearAnimation(); diff --git a/app/src/leanback/res/drawable/selector_live_channel.xml b/app/src/leanback/res/drawable/selector_live_channel.xml index a8c4a459e..947f817e3 100644 --- a/app/src/leanback/res/drawable/selector_live_channel.xml +++ b/app/src/leanback/res/drawable/selector_live_channel.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/app/src/leanback/res/drawable/selector_live_group.xml b/app/src/leanback/res/drawable/selector_live_group.xml index bfa668dd0..ee00a4d93 100644 --- a/app/src/leanback/res/drawable/selector_live_group.xml +++ b/app/src/leanback/res/drawable/selector_live_group.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/app/src/leanback/res/layout/adapter_live_channel.xml b/app/src/leanback/res/layout/adapter_live_channel.xml index 423ba796e..3b4215c66 100644 --- a/app/src/leanback/res/layout/adapter_live_channel.xml +++ b/app/src/leanback/res/layout/adapter_live_channel.xml @@ -5,7 +5,6 @@ android:layout_height="wrap_content" android:background="@drawable/selector_live_channel" android:focusable="true" - android:focusableInTouchMode="true" android:gravity="center" android:orientation="horizontal" android:paddingStart="20dp" @@ -20,7 +19,7 @@ android:layout_marginEnd="12dp" android:letterSpacing="0.05" android:textColor="@color/white" - android:textSize="14sp" + android:textSize="16sp" android:textStyle="bold" tools:text="01" /> @@ -41,7 +40,7 @@ android:scrollHorizontally="true" android:singleLine="true" android:textColor="@color/white" - android:textSize="14sp" + android:textSize="16sp" android:textStyle="bold" tools:text="CNN" /> diff --git a/app/src/leanback/res/layout/adapter_live_group.xml b/app/src/leanback/res/layout/adapter_live_group.xml index ad6564a10..af4a8a6de 100644 --- a/app/src/leanback/res/layout/adapter_live_group.xml +++ b/app/src/leanback/res/layout/adapter_live_group.xml @@ -1,12 +1,11 @@ diff --git a/app/src/leanback/res/values/styles.xml b/app/src/leanback/res/values/styles.xml index b9d4045b8..ff64a577a 100644 --- a/app/src/leanback/res/values/styles.xml +++ b/app/src/leanback/res/values/styles.xml @@ -33,8 +33,10 @@ false fill true + false false @drawable/radio + true diff --git a/app/src/main/java/com/fongmi/android/tv/api/LiveConfig.java b/app/src/main/java/com/fongmi/android/tv/api/LiveConfig.java index b066a90fb..6c4478917 100644 --- a/app/src/main/java/com/fongmi/android/tv/api/LiveConfig.java +++ b/app/src/main/java/com/fongmi/android/tv/api/LiveConfig.java @@ -41,8 +41,8 @@ public class LiveConfig { Live live = new Live(item.getName(), new ArrayList<>()); parse(OKHttp.newCall(url).execute().body().string(), live); if (live.getGroups().size() > 0) getLives().add(live); - } catch (Exception ignored) { - ignored.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); } } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Channel.java b/app/src/main/java/com/fongmi/android/tv/bean/Channel.java index 85c064200..132996fb2 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Channel.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Channel.java @@ -11,8 +11,10 @@ import com.google.gson.annotations.SerializedName; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; public class Channel { @@ -24,8 +26,8 @@ public class Channel { private String icon; @SerializedName("name") private String name; - @SerializedName("type") - private Group type; + @SerializedName("group") + private Group group; @SerializedName("ua") private String ua; @@ -85,12 +87,12 @@ public class Channel { this.name = name; } - public Group getType() { - return type; + public Group getGroup() { + return group; } - public void setType(Group type) { - this.type = type; + public void setGroup(Group group) { + this.group = group; } public String getUa() { @@ -117,6 +119,13 @@ public class Channel { if (!getIcon().isEmpty()) ImgUtil.load(getIcon(), view); } + public Map getHeaders() { + HashMap map = new HashMap<>(); + if (getUa().isEmpty()) return map; + map.put("User-Agent", getUa()); + return map; + } + @Override public boolean equals(Object obj) { if (this == obj) return true; diff --git a/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java b/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java index b05bce1e3..9d5465c18 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java +++ b/app/src/main/java/com/fongmi/android/tv/player/ExoUtil.java @@ -6,6 +6,7 @@ import android.net.Uri; import com.fongmi.android.tv.App; import com.fongmi.android.tv.bean.Result; import com.fongmi.android.tv.utils.FileUtil; +import com.github.catvod.crawler.SpiderDebug; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.database.DatabaseProvider; @@ -45,6 +46,7 @@ public class ExoUtil { } private static MediaSource getSource(Map headers, String url, int errorCode, List config) { + SpiderDebug.log(url + "," + headers); MediaItem.Builder builder = new MediaItem.Builder().setUri(Uri.parse(url)); if (errorCode == PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED) builder.setMimeType(MimeTypes.APPLICATION_OCTET); else if (errorCode == PlaybackException.ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED) builder.setMimeType(MimeTypes.APPLICATION_M3U8); diff --git a/app/src/main/java/com/fongmi/android/tv/player/Players.java b/app/src/main/java/com/fongmi/android/tv/player/Players.java index 951aaa960..c03e82d43 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/Players.java +++ b/app/src/main/java/com/fongmi/android/tv/player/Players.java @@ -4,6 +4,7 @@ import androidx.annotation.NonNull; import com.fongmi.android.tv.App; import com.fongmi.android.tv.R; +import com.fongmi.android.tv.bean.Channel; import com.fongmi.android.tv.bean.Result; import com.fongmi.android.tv.event.PlayerEvent; import com.fongmi.android.tv.utils.Notify; @@ -140,6 +141,10 @@ public class Players implements Player.Listener, AnalyticsListener, ParseTask.Ca exoPlayer = null; } + public void start(Channel channel, int index) { + setMediaSource(channel.getHeaders(), channel.getUrls().get(index)); + } + public void start(Result result, boolean useParse) { if (result.getUrl().isEmpty()) { PlayerEvent.error(R.string.error_play_load); @@ -159,6 +164,7 @@ public class Players implements Player.Listener, AnalyticsListener, ParseTask.Ca exoPlayer.setMediaSource(ExoUtil.getSource(result, errorCode)); PlayerEvent.state(0); exoPlayer.prepare(); + exoPlayer.play(); errorCode = 0; } @@ -166,6 +172,7 @@ public class Players implements Player.Listener, AnalyticsListener, ParseTask.Ca exoPlayer.setMediaSource(ExoUtil.getSource(headers, url, errorCode)); PlayerEvent.state(0); exoPlayer.prepare(); + exoPlayer.play(); errorCode = 0; } diff --git a/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java b/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java index 8aa72a686..3b6cf3f02 100644 --- a/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java +++ b/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java @@ -20,7 +20,6 @@ import androidx.annotation.Nullable; import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.player.ParseTask; import com.fongmi.android.tv.utils.Utils; -import com.github.catvod.crawler.SpiderDebug; import java.io.ByteArrayInputStream; import java.util.Arrays; @@ -118,7 +117,6 @@ public class CustomWebView extends WebView { handler.removeCallbacks(mTimer); handler.post(() -> { if (callback != null) callback.onParseSuccess(news, url, ""); - SpiderDebug.log(url + "," + headers); stop(false); }); }