mirror of https://github.com/FongMi/TV.git
parent
c74a7b6d59
commit
f002efc5c1
@ -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…
Reference in new issue