Commit abb53d7c by tonihei Committed by Andrew Lewis

Support multiple overrides in TrackSelectionView and factor out Builder.

Supporting multiple overrides allows to select tracks from multiple groups, if
enabled. As more options are added, the creation of the dialog is moved to a
separate builder class.

PiperOrigin-RevId: 233366282
parent fc271049
......@@ -60,6 +60,8 @@
`PlayerNotificationManager` has been fixed. Apps using
`DownloadNotificationUtil` should switch to using
`DownloadNotificationHelper`.
* Move creation of dialogs for `TrackSelectionView`s to
`TrackSelectionDialogBuilder` and add option to select multiple overrides.
### 2.9.5 ###
......
......@@ -24,7 +24,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.Nullable;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
......@@ -45,11 +44,13 @@ import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionUtil;
import com.google.android.exoplayer2.ui.DefaultTrackNameProvider;
import com.google.android.exoplayer2.ui.TrackNameProvider;
import com.google.android.exoplayer2.ui.TrackSelectionView;
import com.google.android.exoplayer2.ui.TrackSelectionDialogBuilder;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
......@@ -229,8 +230,7 @@ public class DownloadTracker implements DownloadManager.Listener {
implements DownloadHelper.Callback,
DialogInterface.OnClickListener,
DialogInterface.OnDismissListener,
View.OnClickListener,
TrackSelectionView.DialogCallback {
View.OnClickListener {
private final DownloadHelper downloadHelper;
private final String name;
......@@ -290,29 +290,19 @@ public class DownloadTracker implements DownloadManager.Listener {
@Override
public void onClick(View v) {
Integer rendererIndex = (Integer) v.getTag();
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(rendererIndex);
String dialogTitle = getTrackTypeString(mappedTrackInfo.getRendererType(rendererIndex));
Pair<AlertDialog, TrackSelectionView> dialogPair =
TrackSelectionView.getDialog(
new TrackSelectionDialogBuilder(
dialog.getContext(),
dialogTitle,
mappedTrackInfo,
rendererIndex,
parameters,
/* callback= */ this);
dialogPair.second.setShowDisableOption(true);
dialogPair.second.setAllowAdaptiveSelections(false);
dialogPair.first.show();
}
// TrackSelectionView.DialogCallback implementation.
@Override
public void onTracksSelected(DefaultTrackSelector.Parameters parameters) {
for (int i = 0; i < downloadHelper.getPeriodCount(); i++) {
downloadHelper.replaceTrackSelections(/* periodIndex= */ i, parameters);
}
this.parameters = parameters;
updateSelectionList();
(isDisabled, overrides) -> updateTracks(rendererIndex, isDisabled, overrides))
.setShowDisableOption(true)
.setIsDisabled(parameters.getRendererDisabled(rendererIndex))
.setOverride(parameters.getSelectionOverride(rendererIndex, trackGroupArray))
.build()
.show();
}
// DialogInterface.OnClickListener implementation.
......@@ -332,6 +322,21 @@ public class DownloadTracker implements DownloadManager.Listener {
// Internal methods.
private void updateTracks(
int rendererIndex, boolean isDisabled, List<SelectionOverride> overrides) {
parameters =
TrackSelectionUtil.updateParametersWithOverride(
parameters,
rendererIndex,
mappedTrackInfo.getTrackGroups(rendererIndex),
isDisabled,
overrides.isEmpty() ? null : overrides.get(0));
for (int i = 0; i < downloadHelper.getPeriodCount(); i++) {
downloadHelper.replaceTrackSelections(/* periodIndex= */ i, parameters);
}
updateSelectionList();
}
private void updateSelectionList() {
selectionList.removeAllViews();
for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) {
......
......@@ -16,7 +16,6 @@
package com.google.android.exoplayer2.demo;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
......@@ -68,7 +67,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.DebugTextViewHelper;
import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.ui.TrackSelectionView;
import com.google.android.exoplayer2.ui.TrackSelectionDialogBuilder;
import com.google.android.exoplayer2.ui.spherical.SphericalSurfaceView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource;
......@@ -307,11 +306,11 @@ public class PlayerActivity extends Activity
|| (rendererType == C.TRACK_TYPE_AUDIO
&& mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO)
== MappedTrackInfo.RENDERER_SUPPORT_NO_TRACKS);
Pair<AlertDialog, TrackSelectionView> dialogPair =
TrackSelectionView.getDialog(this, title, trackSelector, rendererIndex);
dialogPair.second.setShowDisableOption(true);
dialogPair.second.setAllowAdaptiveSelections(allowAdaptiveSelections);
dialogPair.first.show();
new TrackSelectionDialogBuilder(/* context= */ this, title, trackSelector, rendererIndex)
.setShowDisableOption(true)
.setAllowAdaptiveSelections(allowAdaptiveSelections)
.build()
.show();
}
}
}
......
......@@ -19,9 +19,11 @@ import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.source.chunk.MediaChunkListIterator;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelection.Definition;
import com.google.android.exoplayer2.util.Assertions;
import java.util.Arrays;
......@@ -76,6 +78,34 @@ public final class TrackSelectionUtil {
}
/**
* Updates {@link DefaultTrackSelector.Parameters} with an override.
*
* @param parameters The current {@link DefaultTrackSelector.Parameters} to build upon.
* @param rendererIndex The renderer index to update.
* @param trackGroupArray The {@link TrackGroupArray} of the renderer.
* @param isDisabled Whether the renderer should be set disabled.
* @param override An optional override for the renderer. If null, no override will be set and an
* existing override for this renderer will be cleared.
* @return The updated {@link DefaultTrackSelector.Parameters}.
*/
public static DefaultTrackSelector.Parameters updateParametersWithOverride(
DefaultTrackSelector.Parameters parameters,
int rendererIndex,
TrackGroupArray trackGroupArray,
boolean isDisabled,
@Nullable SelectionOverride override) {
DefaultTrackSelector.ParametersBuilder builder =
parameters
.buildUpon()
.clearSelectionOverrides(rendererIndex)
.setRendererDisabled(rendererIndex, isDisabled);
if (override != null) {
builder.setSelectionOverride(rendererIndex, trackGroupArray, override);
}
return builder.build();
}
/**
* Returns average bitrate for chunks in bits per second. Chunks are included in average until
* {@code maxDurationMs} or the first unknown length chunk.
*
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.ui;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import com.google.android.exoplayer2.trackselection.TrackSelectionUtil;
import com.google.android.exoplayer2.util.Assertions;
import java.util.Collections;
import java.util.List;
/** Builder for a dialog with a {@link TrackSelectionView}. */
public final class TrackSelectionDialogBuilder {
/** Callback which is invoked when a track selection has been made. */
public interface DialogCallback {
/**
* Called when tracks are selected.
*
* @param isDisabled Whether the renderer is disabled.
* @param overrides List of selected track selection overrides for the renderer.
*/
void onTracksSelected(boolean isDisabled, List<SelectionOverride> overrides);
}
private final Context context;
private final CharSequence title;
private final MappedTrackInfo mappedTrackInfo;
private final int rendererIndex;
private final DialogCallback callback;
private boolean allowAdaptiveSelections;
private boolean allowMultipleOverrides;
private boolean showDisableOption;
@Nullable private TrackNameProvider trackNameProvider;
private boolean isDisabled;
private List<SelectionOverride> overrides;
/**
* Creates a builder for a track selection dialog.
*
* @param context The context of the dialog.
* @param title The title of the dialog.
* @param mappedTrackInfo The {@link MappedTrackInfo} containing the track information.
* @param rendererIndex The renderer index in the {@code mappedTrackInfo} for which the track
* selection is shown.
* @param callback The {@link DialogCallback} invoked when a track selection has been made.
*/
public TrackSelectionDialogBuilder(
Context context,
CharSequence title,
MappedTrackInfo mappedTrackInfo,
int rendererIndex,
DialogCallback callback) {
this.context = context;
this.title = title;
this.mappedTrackInfo = mappedTrackInfo;
this.rendererIndex = rendererIndex;
this.callback = callback;
overrides = Collections.emptyList();
}
/**
* Creates a builder for a track selection dialog which automatically updates a {@link
* DefaultTrackSelector}.
*
* @param context The context of the dialog.
* @param title The title of the dialog.
* @param trackSelector A {@link DefaultTrackSelector} whose current selection is used to set up
* the dialog and which is updated when new tracks are selected in the dialog.
* @param rendererIndex The renderer index in the {@code trackSelector} for which the track
* selection is shown.
*/
public TrackSelectionDialogBuilder(
Context context, CharSequence title, DefaultTrackSelector trackSelector, int rendererIndex) {
this.context = context;
this.title = title;
this.mappedTrackInfo = Assertions.checkNotNull(trackSelector.getCurrentMappedTrackInfo());
this.rendererIndex = rendererIndex;
TrackGroupArray rendererTrackGroups = mappedTrackInfo.getTrackGroups(rendererIndex);
DefaultTrackSelector.Parameters selectionParameters = trackSelector.getParameters();
isDisabled = selectionParameters.getRendererDisabled(rendererIndex);
SelectionOverride override =
selectionParameters.getSelectionOverride(rendererIndex, rendererTrackGroups);
overrides = override == null ? Collections.emptyList() : Collections.singletonList(override);
this.callback =
(newIsDisabled, newOverrides) ->
trackSelector.setParameters(
TrackSelectionUtil.updateParametersWithOverride(
selectionParameters,
rendererIndex,
rendererTrackGroups,
newIsDisabled,
newOverrides.isEmpty() ? null : newOverrides.get(0)));
}
/**
* Sets whether the selection is initially shown as disabled.
*
* @param isDisabled Whether the selection is initially shown as disabled.
* @return This builder, for convenience.
*/
public TrackSelectionDialogBuilder setIsDisabled(boolean isDisabled) {
this.isDisabled = isDisabled;
return this;
}
/**
* Sets the initial selection override to show.
*
* @param override The initial override to show, or null for no override.
* @return This builder, for convenience.
*/
public TrackSelectionDialogBuilder setOverride(@Nullable SelectionOverride override) {
return setOverrides(
override == null ? Collections.emptyList() : Collections.singletonList(override));
}
/**
* Sets the list of initial selection overrides to show.
*
* <p>Note that only the first override will be used unless {@link
* #setAllowMultipleOverrides(boolean)} is set to {@code true}.
*
* @param overrides The list of initial overrides to show. There must be at most one override for
* each track group.
* @return This builder, for convenience.
*/
public TrackSelectionDialogBuilder setOverrides(List<SelectionOverride> overrides) {
this.overrides = overrides;
return this;
}
/**
* Sets whether adaptive selections (consisting of more than one track) can be made.
*
* <p>For the selection view to enable adaptive selection it is necessary both for this feature to
* be enabled, and for the target renderer to support adaptation between the available tracks.
*
* @param allowAdaptiveSelections Whether adaptive selection is enabled.
* @return This builder, for convenience.
*/
public TrackSelectionDialogBuilder setAllowAdaptiveSelections(boolean allowAdaptiveSelections) {
this.allowAdaptiveSelections = allowAdaptiveSelections;
return this;
}
/**
* Sets whether multiple overrides can be set and selected, i.e. tracks from multiple track groups
* can be selected.
*
* @param allowMultipleOverrides Whether multiple track selection overrides are allowed.
* @return This builder, for convenience.
*/
public TrackSelectionDialogBuilder setAllowMultipleOverrides(boolean allowMultipleOverrides) {
this.allowMultipleOverrides = allowMultipleOverrides;
return this;
}
/**
* Sets whether an option is available for disabling the renderer.
*
* @param showDisableOption Whether the disable option is shown.
* @return This builder, for convenience.
*/
public TrackSelectionDialogBuilder setShowDisableOption(boolean showDisableOption) {
this.showDisableOption = showDisableOption;
return this;
}
/**
* Sets the {@link TrackNameProvider} used to generate the user visible name of each track and
* updates the view with track names queried from the specified provider.
*
* @param trackNameProvider The {@link TrackNameProvider} to use, or null to use the default.
*/
public TrackSelectionDialogBuilder setTrackNameProvider(
@Nullable TrackNameProvider trackNameProvider) {
this.trackNameProvider = trackNameProvider;
return this;
}
/** Builds the dialog. */
public AlertDialog build() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
// Inflate with the builder's context to ensure the correct style is used.
LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
View dialogView = dialogInflater.inflate(R.layout.exo_track_selection_dialog, /* root= */ null);
TrackSelectionView selectionView = dialogView.findViewById(R.id.exo_track_selection_view);
selectionView.setAllowMultipleOverrides(allowMultipleOverrides);
selectionView.setAllowAdaptiveSelections(allowAdaptiveSelections);
selectionView.setShowDisableOption(showDisableOption);
if (trackNameProvider != null) {
selectionView.setTrackNameProvider(trackNameProvider);
}
selectionView.init(mappedTrackInfo, rendererIndex, isDisabled, overrides);
Dialog.OnClickListener okClickListener =
(dialog, which) ->
callback.onTracksSelected(selectionView.getIsDisabled(), selectionView.getOverrides());
return builder
.setTitle(title)
.setView(dialogView)
.setPositiveButton(android.R.string.ok, okClickListener)
.setNegativeButton(android.R.string.cancel, null)
.create();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment