Support track - part 4

pull/123/head
FongMi 3 years ago
parent c74a7b6d59
commit f002efc5c1
  1. 10
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java
  2. 4
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java
  3. 23
      app/src/main/java/com/fongmi/android/tv/bean/Track.java
  4. 310
      app/src/main/java/com/fongmi/android/tv/ui/custom/TrackSelectionDialog.java
  5. 111
      app/src/main/java/com/fongmi/android/tv/ui/custom/TrackSelectionDialog2.java

@ -40,7 +40,6 @@ import com.fongmi.android.tv.player.ExoUtil;
import com.fongmi.android.tv.player.Players;
import com.fongmi.android.tv.ui.custom.CustomKeyDownVod;
import com.fongmi.android.tv.ui.custom.TrackSelectionDialog;
import com.fongmi.android.tv.ui.custom.TrackSelectionDialog2;
import com.fongmi.android.tv.ui.custom.dialog.DescDialog;
import com.fongmi.android.tv.ui.presenter.ArrayPresenter;
import com.fongmi.android.tv.ui.presenter.EpisodePresenter;
@ -194,7 +193,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis
mBinding.control.decode.setOnClickListener(view -> onDecode());
mBinding.control.ending.setOnClickListener(view -> onEnding());
mBinding.control.opening.setOnClickListener(view -> onOpening());
//mBinding.control.opening.setOnClickListener(view -> onTracks());
mBinding.control.replay.setOnClickListener(view -> getPlayer(true));
mBinding.control.speed.setOnLongClickListener(view -> onSpeedLong());
mBinding.control.ending.setOnLongClickListener(view -> onEndingReset());
@ -585,13 +583,7 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis
private void onTracks(View view) {
int type = Integer.parseInt(view.getTag().toString());
TrackSelectionDialog2.create(this).player(mPlayers).type(type).show();
hideControl();
}
private void onTracks() {
TrackSelectionDialog.createForPlayer(mPlayers.exo(), dialog -> {
}).show(getSupportFragmentManager(), "tracks");
TrackSelectionDialog.create(this).player(mPlayers).type(type).show();
hideControl();
}

@ -35,7 +35,7 @@ import com.fongmi.android.tv.player.source.TVBus;
import com.fongmi.android.tv.player.source.ZLive;
import com.fongmi.android.tv.ui.custom.CustomKeyDownLive;
import com.fongmi.android.tv.ui.custom.CustomLiveListView;
import com.fongmi.android.tv.ui.custom.TrackSelectionDialog2;
import com.fongmi.android.tv.ui.custom.TrackSelectionDialog;
import com.fongmi.android.tv.ui.custom.dialog.LiveDialog;
import com.fongmi.android.tv.ui.custom.dialog.PassDialog;
import com.fongmi.android.tv.ui.presenter.ChannelPresenter;
@ -320,7 +320,7 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick
private void onTracks(View view) {
int type = Integer.parseInt(view.getTag().toString());
TrackSelectionDialog2.create(this).player(mPlayers).type(type).show();
TrackSelectionDialog.create(this).player(mPlayers).type(type).show();
hideControl();
}

@ -2,14 +2,13 @@ package com.fongmi.android.tv.bean;
public class Track {
private int group;
private int track;
private String name;
private int index;
private int playerType;
private boolean selected;
public Track(int playerType, String name) {
public Track(String name) {
this.name = name;
this.playerType = playerType;
}
public String getName() {
@ -20,20 +19,20 @@ public class Track {
this.name = name;
}
public int getIndex() {
return index;
public int getGroup() {
return group;
}
public void setIndex(int index) {
this.index = index;
public void setGroup(int group) {
this.group = group;
}
public int getPlayerType() {
return playerType;
public int getTrack() {
return track;
}
public void setPlayerType(int playerType) {
this.playerType = playerType;
public void setTrack(int track) {
this.track = track;
}
public boolean isSelected() {

@ -1,272 +1,114 @@
package com.fongmi.android.tv.ui.custom;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.SparseArray;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AlertDialog;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Player;
import com.fongmi.android.tv.bean.Track;
import com.fongmi.android.tv.databinding.DialogTrackBinding;
import com.fongmi.android.tv.player.Players;
import com.fongmi.android.tv.ui.adapter.TrackAdapter;
import com.fongmi.android.tv.utils.ResUtil;
import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
import com.google.android.exoplayer2.ui.R;
import com.google.android.exoplayer2.ui.TrackSelectionView;
import com.google.android.material.tabs.TabLayout;
import com.google.common.collect.ImmutableList;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class TrackSelectionDialog extends DialogFragment {
import tv.danmaku.ijk.media.player.misc.IjkTrackInfo;
public static final ImmutableList<Integer> SUPPORTED_TRACK_TYPES = ImmutableList.of(C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_TEXT);
private final SparseArray<TrackSelectionViewFragment> tabFragments;
private final ArrayList<Integer> tabTrackTypes;
private DialogInterface.OnClickListener onClickListener;
private DialogInterface.OnDismissListener onDismissListener;
public final class TrackSelectionDialog implements TrackAdapter.OnClickListener {
public TrackSelectionDialog() {
tabFragments = new SparseArray<>();
tabTrackTypes = new ArrayList<>();
setRetainInstance(true);
}
/**
* Returns whether a track selection dialog will have content to display if initialized with the
* specified {@link Player}.
*/
public static void setVisible(ExoPlayer player, View view) {
view.setVisibility(willHaveContent(player.getCurrentTracks()) ? View.VISIBLE : View.GONE);
}
private final DialogTrackBinding binding;
private final TrackNameProvider provider;
private final TrackAdapter adapter;
private final AlertDialog dialog;
private Players player;
private int type;
/**
* Returns whether a track selection dialog will have content to display if initialized with the
* specified {@link Tracks}.
*/
public static boolean willHaveContent(Tracks tracks) {
for (Tracks.Group trackGroup : tracks.getGroups()) {
if (SUPPORTED_TRACK_TYPES.contains(trackGroup.getType())) {
return true;
}
}
return false;
public static TrackSelectionDialog create(Activity activity) {
return new TrackSelectionDialog(activity);
}
/**
* Creates a dialog for a given {@link Player}, whose parameters will be automatically updated
* when tracks are selected.
*
* @param player The {@link Player}.
* @param onDismissListener A {@link DialogInterface.OnDismissListener} to call when the dialog is
* dismissed.
*/
public static TrackSelectionDialog createForPlayer(Player player, DialogInterface.OnDismissListener onDismissListener) {
return createForTracksAndParameters(player.getCurrentTracks(), player.getTrackSelectionParameters(), true, false, player::setTrackSelectionParameters, onDismissListener);
public TrackSelectionDialog(Activity activity) {
this.binding = DialogTrackBinding.inflate(LayoutInflater.from(activity));
this.dialog = new MaterialAlertDialogBuilder(activity).setView(binding.getRoot()).create();
this.adapter = new TrackAdapter(this);
this.provider = new TrackNameProvider();
}
/**
* Creates a dialog for given {@link Tracks} and {@link TrackSelectionParameters}.
*
* @param tracks The {@link Tracks} describing the tracks to display.
* @param trackSelectionParameters The initial {@link TrackSelectionParameters}.
* @param allowAdaptiveSelections Whether adaptive selections (consisting of more than one track)
* can be made.
* @param allowMultipleOverrides Whether tracks from multiple track groups can be selected.
* @param trackSelectionListener Called when tracks are selected.
* @param onDismissListener {@link DialogInterface.OnDismissListener} called when the dialog is
* dismissed.
*/
public static TrackSelectionDialog createForTracksAndParameters(Tracks tracks, TrackSelectionParameters trackSelectionParameters, boolean allowAdaptiveSelections, boolean allowMultipleOverrides, TrackSelectionListener trackSelectionListener, DialogInterface.OnDismissListener onDismissListener) {
TrackSelectionDialog trackSelectionDialog = new TrackSelectionDialog();
trackSelectionDialog.init(tracks, trackSelectionParameters, allowAdaptiveSelections, allowMultipleOverrides, (dialog, which) -> {
TrackSelectionParameters.Builder builder = trackSelectionParameters.buildUpon();
for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) {
int trackType = SUPPORTED_TRACK_TYPES.get(i);
builder.setTrackTypeDisabled(trackType, trackSelectionDialog.getIsDisabled(trackType));
builder.clearOverridesOfType(trackType);
Map<TrackGroup, TrackSelectionOverride> overrides = trackSelectionDialog.getOverrides(trackType);
for (TrackSelectionOverride override : overrides.values()) builder.addOverride(override);
}
trackSelectionListener.onTracksSelected(builder.build());
}, onDismissListener);
return trackSelectionDialog;
public TrackSelectionDialog type(int type) {
this.type = type;
return this;
}
private static String getTrackTypeString(Resources resources, @C.TrackType int trackType) {
switch (trackType) {
case C.TRACK_TYPE_VIDEO:
return resources.getString(R.string.exo_track_selection_title_video);
case C.TRACK_TYPE_AUDIO:
return resources.getString(R.string.exo_track_selection_title_audio);
case C.TRACK_TYPE_TEXT:
return resources.getString(R.string.exo_track_selection_title_text);
default:
throw new IllegalArgumentException();
}
public TrackSelectionDialog player(Players player) {
this.player = player;
return this;
}
private void init(Tracks tracks, TrackSelectionParameters trackSelectionParameters, boolean allowAdaptiveSelections, boolean allowMultipleOverrides, DialogInterface.OnClickListener onClickListener, DialogInterface.OnDismissListener onDismissListener) {
this.onClickListener = onClickListener;
this.onDismissListener = onDismissListener;
for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) {
@C.TrackType int trackType = SUPPORTED_TRACK_TYPES.get(i);
ArrayList<Tracks.Group> trackGroups = new ArrayList<>();
for (Tracks.Group trackGroup : tracks.getGroups()) {
if (trackGroup.getType() == trackType) {
trackGroups.add(trackGroup);
}
}
if (!trackGroups.isEmpty()) {
TrackSelectionViewFragment tabFragment = new TrackSelectionViewFragment();
tabFragment.init(trackGroups, trackSelectionParameters.disabledTrackTypes.contains(trackType), trackSelectionParameters.overrides, allowAdaptiveSelections, allowMultipleOverrides);
tabFragments.put(trackType, tabFragment);
tabTrackTypes.add(trackType);
}
}
public void show() {
setRecyclerView();
setDialog();
}
/**
* Returns whether the disabled option is selected for the specified track type.
*
* @param trackType The track type.
* @return Whether the disabled option is selected for the track type.
*/
public boolean getIsDisabled(int trackType) {
TrackSelectionViewFragment trackView = tabFragments.get(trackType);
return trackView != null && trackView.isDisabled;
private void setRecyclerView() {
binding.recycler.setHasFixedSize(true);
binding.recycler.addItemDecoration(new SpaceItemDecoration(1, 16));
binding.recycler.setAdapter(adapter.addAll(getTrack()));
binding.recycler.scrollToPosition(adapter.getSelected());
}
/**
* Returns the selected track overrides for the specified track type.
*
* @param trackType The track type.
* @return The track overrides for the track type.
*/
public Map<TrackGroup, TrackSelectionOverride> getOverrides(int trackType) {
TrackSelectionViewFragment trackView = tabFragments.get(trackType);
return trackView == null ? Collections.emptyMap() : trackView.overrides;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new AppCompatDialog(getActivity());
private void setDialog() {
WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
params.width = (int) (ResUtil.getScreenWidthPx() * 0.4f);
dialog.getWindow().setAttributes(params);
dialog.getWindow().setDimAmount(0);
return dialog;
dialog.show();
}
@Override
public void onDismiss(@NonNull DialogInterface dialog) {
super.onDismiss(dialog);
onDismissListener.onDismiss(dialog);
private List<Track> getTrack() {
List<Track> items = new ArrayList<>();
if (player.isExo()) addExoTrack(items);
if (player.isIjk()) addIjkTrack(items);
return items;
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View dialogView = inflater.inflate(com.fongmi.android.tv.R.layout.dialog_tracks, container, false);
TabLayout tabLayout = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_tab_layout);
ViewPager viewPager = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_view_pager);
TextView cancelButton = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_cancel_button);
TextView okButton = dialogView.findViewById(com.fongmi.android.tv.R.id.track_selection_dialog_ok_button);
viewPager.setAdapter(new FragmentAdapter(getChildFragmentManager()));
tabLayout.setupWithViewPager(viewPager);
tabLayout.setVisibility(tabFragments.size() > 1 ? View.VISIBLE : View.GONE);
cancelButton.setOnClickListener(view -> dismiss());
okButton.setOnClickListener(view -> {
onClickListener.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE);
dismiss();
});
return dialogView;
}
public interface TrackSelectionListener {
void onTracksSelected(TrackSelectionParameters trackSelectionParameters);
}
/**
* Fragment to show a track selection in tab of the track selection dialog.
*/
public static final class TrackSelectionViewFragment extends Fragment implements TrackSelectionView.TrackSelectionListener {
private List<Tracks.Group> trackGroups;
private boolean allowAdaptiveSelections;
private boolean allowMultipleOverrides;
Map<TrackGroup, TrackSelectionOverride> overrides;
boolean isDisabled;
public TrackSelectionViewFragment() {
setRetainInstance(true);
}
public void init(List<Tracks.Group> trackGroups, boolean isDisabled, Map<TrackGroup, TrackSelectionOverride> overrides, boolean allowAdaptiveSelections, boolean allowMultipleOverrides) {
this.trackGroups = trackGroups;
this.isDisabled = isDisabled;
this.allowAdaptiveSelections = allowAdaptiveSelections;
this.allowMultipleOverrides = allowMultipleOverrides;
// TrackSelectionView does this filtering internally, but we need to do it here as well to
// handle the case where the TrackSelectionView is never created.
this.overrides = new HashMap<>(TrackSelectionView.filterOverrides(overrides, trackGroups, allowMultipleOverrides));
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.exo_track_selection_dialog, container, /* attachToRoot= */ false);
TrackSelectionView trackSelectionView = rootView.findViewById(R.id.exo_track_selection_view);
trackSelectionView.setShowDisableOption(true);
trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides);
trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections);
trackSelectionView.init(trackGroups, isDisabled, overrides, null, this);
return rootView;
}
@Override
public void onTrackSelectionChanged(boolean isDisabled, @NonNull Map<TrackGroup, TrackSelectionOverride> overrides) {
this.isDisabled = isDisabled;
this.overrides = overrides;
private void addExoTrack(List<Track> items) {
List<Tracks.Group> groups = player.exo().getCurrentTracks().getGroups();
for (int i = 0; i < groups.size(); i++) {
Tracks.Group trackGroup = groups.get(i);
if (trackGroup.getType() != type) continue;
for (int j = 0; j < trackGroup.length; j++) {
Track item = new Track(provider.getTrackName(trackGroup.getTrackFormat(j)));
item.setSelected(trackGroup.isTrackSelected(j));
item.setGroup(i);
item.setTrack(j);
items.add(item);
}
}
}
private final class FragmentAdapter extends FragmentPagerAdapter {
public FragmentAdapter(FragmentManager fragmentManager) {
super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
return tabFragments.get(tabTrackTypes.get(position));
}
@Override
public int getCount() {
return tabTrackTypes.size();
private void addIjkTrack(List<Track> items) {
int track = player.ijk().getSelectedTrack(type);
IjkTrackInfo[] trackInfos = player.ijk().getTrackInfo();
for (int i = 0; i < trackInfos.length; i++) {
IjkTrackInfo trackInfo = trackInfos[i];
if (trackInfo.getTrackType() != type) continue;
Track item = new Track(provider.getTrackName(trackInfo));
item.setSelected(track == i);
item.setTrack(i);
items.add(item);
}
}
@Override
public CharSequence getPageTitle(int position) {
return getTrackTypeString(getResources(), tabTrackTypes.get(position));
}
@Override
public void onItemClick(Track item) {
if (player.isExo()) player.exo().setTrackSelectionParameters(player.exo().getTrackSelectionParameters().buildUpon().setOverrideForType(new TrackSelectionOverride(player.exo().getCurrentTracks().getGroups().get(item.getGroup()).getMediaTrackGroup(), item.getTrack())).build());
if (player.isIjk()) player.ijk().selectTrack(item.getTrack());
dialog.dismiss();
}
}

@ -1,111 +0,0 @@
package com.fongmi.android.tv.ui.custom;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.WindowManager;
import androidx.appcompat.app.AlertDialog;
import com.fongmi.android.tv.bean.Track;
import com.fongmi.android.tv.databinding.DialogTrackBinding;
import com.fongmi.android.tv.player.Players;
import com.fongmi.android.tv.ui.adapter.TrackAdapter;
import com.fongmi.android.tv.utils.ResUtil;
import com.google.android.exoplayer2.Tracks;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import tv.danmaku.ijk.media.player.misc.IjkTrackInfo;
public final class TrackSelectionDialog2 implements TrackAdapter.OnClickListener {
private final DialogTrackBinding binding;
private final TrackNameProvider provider;
private final TrackAdapter adapter;
private final AlertDialog dialog;
private Players player;
private int type;
public static TrackSelectionDialog2 create(Activity activity) {
return new TrackSelectionDialog2(activity);
}
public TrackSelectionDialog2(Activity activity) {
this.binding = DialogTrackBinding.inflate(LayoutInflater.from(activity));
this.dialog = new MaterialAlertDialogBuilder(activity).setView(binding.getRoot()).create();
this.adapter = new TrackAdapter(this);
this.provider = new TrackNameProvider();
}
public TrackSelectionDialog2 type(int type) {
this.type = type;
return this;
}
public TrackSelectionDialog2 player(Players player) {
this.player = player;
return this;
}
public void show() {
setRecyclerView();
setDialog();
}
private void setRecyclerView() {
binding.recycler.setHasFixedSize(true);
binding.recycler.addItemDecoration(new SpaceItemDecoration(1, 16));
binding.recycler.setAdapter(adapter.addAll(getTrack()));
binding.recycler.scrollToPosition(adapter.getSelected());
}
private void setDialog() {
WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
params.width = (int) (ResUtil.getScreenWidthPx() * 0.4f);
dialog.getWindow().setAttributes(params);
dialog.getWindow().setDimAmount(0);
dialog.show();
}
private List<Track> getTrack() {
List<Track> items = new ArrayList<>();
if (player.isExo()) addExoTrack(items);
if (player.isIjk()) addIjkTrack(items);
return items;
}
private void addExoTrack(List<Track> items) {
for (Tracks.Group trackGroup : player.exo().getCurrentTracks().getGroups()) {
if (trackGroup.getType() != type) continue;
for (int i = 0; i < trackGroup.length; i++) {
items.add(new Track(player.getPlayer(), provider.getTrackName(trackGroup.getTrackFormat(i))));
}
}
}
private void addIjkTrack(List<Track> items) {
int track = player.ijk().getSelectedTrack(type);
IjkTrackInfo[] trackInfos = player.ijk().getTrackInfo();
for (int index = 0; index < trackInfos.length; index++) {
IjkTrackInfo trackInfo = trackInfos[index];
if (trackInfo.getTrackType() != type) continue;
Track item = new Track(player.getPlayer(), provider.getTrackName(trackInfo));
item.setSelected(track == index);
item.setIndex(index);
items.add(item);
}
}
@Override
public void onItemClick(Track item) {
if (player.isExo()) {
}
if (player.isIjk()) {
player.ijk().selectTrack(item.getIndex());
}
dialog.dismiss();
}
}
Loading…
Cancel
Save