mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add TrackSelectionDialog (with swipe tabs) to demo app.
PiperOrigin-RevId: 233582549
This commit is contained in:
parent
00c31265cd
commit
1dd36ae391
@ -63,6 +63,9 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.android.support:support-annotations:' + supportLibraryVersion
|
implementation 'com.android.support:support-annotations:' + supportLibraryVersion
|
||||||
|
implementation 'com.android.support:support-core-ui:' + supportLibraryVersion
|
||||||
|
implementation 'com.android.support:support-fragment:' + supportLibraryVersion
|
||||||
|
implementation 'com.android.support:design:' + supportLibraryVersion
|
||||||
implementation project(modulePrefix + 'library-core')
|
implementation project(modulePrefix + 'library-core')
|
||||||
implementation project(modulePrefix + 'library-dash')
|
implementation project(modulePrefix + 'library-dash')
|
||||||
implementation project(modulePrefix + 'library-hls')
|
implementation project(modulePrefix + 'library-hls')
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
|
|
||||||
<activity android:name="com.google.android.exoplayer2.demo.SampleChooserActivity"
|
<activity android:name="com.google.android.exoplayer2.demo.SampleChooserActivity"
|
||||||
android:configChanges="keyboardHidden"
|
android:configChanges="keyboardHidden"
|
||||||
android:label="@string/application_name">
|
android:label="@string/application_name"
|
||||||
|
android:theme="@style/Theme.AppCompat">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
@ -15,20 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.demo;
|
package com.google.android.exoplayer2.demo;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.RenderersFactory;
|
import com.google.android.exoplayer2.RenderersFactory;
|
||||||
@ -46,11 +38,6 @@ import com.google.android.exoplayer2.source.TrackGroupArray;
|
|||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
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.TrackSelectionDialogBuilder;
|
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
@ -81,7 +68,6 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final DataSource.Factory dataSourceFactory;
|
private final DataSource.Factory dataSourceFactory;
|
||||||
private final TrackNameProvider trackNameProvider;
|
|
||||||
private final CopyOnWriteArraySet<Listener> listeners;
|
private final CopyOnWriteArraySet<Listener> listeners;
|
||||||
private final HashMap<Uri, DownloadState> trackedDownloadStates;
|
private final HashMap<Uri, DownloadState> trackedDownloadStates;
|
||||||
private final DefaultDownloadIndex downloadIndex;
|
private final DefaultDownloadIndex downloadIndex;
|
||||||
@ -92,7 +78,6 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
this.downloadIndex = downloadIndex;
|
this.downloadIndex = downloadIndex;
|
||||||
trackNameProvider = new DefaultTrackNameProvider(context.getResources());
|
|
||||||
listeners = new CopyOnWriteArraySet<>();
|
listeners = new CopyOnWriteArraySet<>();
|
||||||
trackedDownloadStates = new HashMap<>();
|
trackedDownloadStates = new HashMap<>();
|
||||||
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
|
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
|
||||||
@ -122,7 +107,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void toggleDownload(
|
public void toggleDownload(
|
||||||
Activity activity,
|
FragmentManager fragmentManager,
|
||||||
String name,
|
String name,
|
||||||
Uri uri,
|
Uri uri,
|
||||||
String extension,
|
String extension,
|
||||||
@ -133,7 +118,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
startServiceWithAction(removeAction);
|
startServiceWithAction(removeAction);
|
||||||
} else {
|
} else {
|
||||||
new StartDownloadDialogHelper(
|
new StartDownloadDialogHelper(
|
||||||
activity, getDownloadHelper(uri, extension, renderersFactory), name);
|
fragmentManager, getDownloadHelper(uri, extension, renderersFactory), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,42 +210,23 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UngroupedOverloads")
|
|
||||||
private final class StartDownloadDialogHelper
|
private final class StartDownloadDialogHelper
|
||||||
implements DownloadHelper.Callback,
|
implements DownloadHelper.Callback,
|
||||||
DialogInterface.OnClickListener,
|
DialogInterface.OnClickListener,
|
||||||
DialogInterface.OnDismissListener,
|
DialogInterface.OnDismissListener {
|
||||||
View.OnClickListener {
|
|
||||||
|
|
||||||
|
private final FragmentManager fragmentManager;
|
||||||
private final DownloadHelper downloadHelper;
|
private final DownloadHelper downloadHelper;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final LayoutInflater dialogInflater;
|
|
||||||
private final AlertDialog dialog;
|
|
||||||
private final LinearLayout selectionList;
|
|
||||||
|
|
||||||
|
private TrackSelectionDialog trackSelectionDialog;
|
||||||
private MappedTrackInfo mappedTrackInfo;
|
private MappedTrackInfo mappedTrackInfo;
|
||||||
private DefaultTrackSelector.Parameters parameters;
|
|
||||||
|
|
||||||
private StartDownloadDialogHelper(
|
public StartDownloadDialogHelper(
|
||||||
Activity activity, DownloadHelper downloadHelper, String name) {
|
FragmentManager fragmentManager, DownloadHelper downloadHelper, String name) {
|
||||||
|
this.fragmentManager = fragmentManager;
|
||||||
this.downloadHelper = downloadHelper;
|
this.downloadHelper = downloadHelper;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
AlertDialog.Builder builder =
|
|
||||||
new AlertDialog.Builder(activity)
|
|
||||||
.setTitle(R.string.download_preparing)
|
|
||||||
.setPositiveButton(android.R.string.ok, /* listener= */ this)
|
|
||||||
.setNegativeButton(android.R.string.cancel, /* listener= */ null);
|
|
||||||
|
|
||||||
// Inflate with the builder's context to ensure the correct style is used.
|
|
||||||
dialogInflater = LayoutInflater.from(builder.getContext());
|
|
||||||
selectionList = (LinearLayout) dialogInflater.inflate(R.layout.start_download_dialog, null);
|
|
||||||
builder.setView(selectionList);
|
|
||||||
dialog = builder.create();
|
|
||||||
dialog.setOnDismissListener(/* listener= */ this);
|
|
||||||
dialog.show();
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
|
||||||
|
|
||||||
parameters = DownloadHelper.DEFAULT_TRACK_SELECTOR_PARAMETERS;
|
|
||||||
downloadHelper.prepare(this);
|
downloadHelper.prepare(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,12 +234,19 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepared(DownloadHelper helper) {
|
public void onPrepared(DownloadHelper helper) {
|
||||||
if (helper.getPeriodCount() > 0) {
|
if (helper.getPeriodCount() == 0) {
|
||||||
mappedTrackInfo = downloadHelper.getMappedTrackInfo(/* periodIndex= */ 0);
|
onPrepareError(helper, new IOException("No periods found."));
|
||||||
updateSelectionList();
|
return;
|
||||||
}
|
}
|
||||||
dialog.setTitle(R.string.exo_download_description);
|
mappedTrackInfo = downloadHelper.getMappedTrackInfo(/* periodIndex= */ 0);
|
||||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
|
trackSelectionDialog = new TrackSelectionDialog();
|
||||||
|
trackSelectionDialog.init(
|
||||||
|
mappedTrackInfo,
|
||||||
|
/* allowAdaptiveSelections =*/ false,
|
||||||
|
/* allowMultipleOverrides= */ true,
|
||||||
|
/* onClickListener= */ this,
|
||||||
|
/* onDismissListener= */ this);
|
||||||
|
trackSelectionDialog.show(fragmentManager, "download");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -282,33 +255,44 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
context.getApplicationContext(), R.string.download_start_error, Toast.LENGTH_LONG)
|
context.getApplicationContext(), R.string.download_start_error, Toast.LENGTH_LONG)
|
||||||
.show();
|
.show();
|
||||||
Log.e(TAG, "Failed to start download", e);
|
Log.e(TAG, "Failed to start download", e);
|
||||||
dialog.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
// View.OnClickListener implementation.
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Integer rendererIndex = (Integer) v.getTag();
|
|
||||||
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(rendererIndex);
|
|
||||||
String dialogTitle = getTrackTypeString(mappedTrackInfo.getRendererType(rendererIndex));
|
|
||||||
new TrackSelectionDialogBuilder(
|
|
||||||
dialog.getContext(),
|
|
||||||
dialogTitle,
|
|
||||||
mappedTrackInfo,
|
|
||||||
rendererIndex,
|
|
||||||
(isDisabled, overrides) -> updateTracks(rendererIndex, isDisabled, overrides))
|
|
||||||
.setShowDisableOption(true)
|
|
||||||
.setIsDisabled(parameters.getRendererDisabled(rendererIndex))
|
|
||||||
.setOverride(parameters.getSelectionOverride(rendererIndex, trackGroupArray))
|
|
||||||
.build()
|
|
||||||
.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialogInterface.OnClickListener implementation.
|
// DialogInterface.OnClickListener implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
DefaultTrackSelector.ParametersBuilder builder =
|
||||||
|
DownloadHelper.DEFAULT_TRACK_SELECTOR_PARAMETERS.buildUpon();
|
||||||
|
for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) {
|
||||||
|
builder.setRendererDisabled(/* rendererIndex= */ i, /* disabled= */ true);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < downloadHelper.getPeriodCount(); i++) {
|
||||||
|
downloadHelper.clearTrackSelections(/* periodIndex = */ i);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) {
|
||||||
|
if (trackSelectionDialog.getIsDisabled(/* rendererIndex= */ i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
builder.setRendererDisabled(/* rendererIndex= */ i, /* disabled= */ false);
|
||||||
|
List<SelectionOverride> overrides =
|
||||||
|
trackSelectionDialog.getOverrides(/* rendererIndex= */ i);
|
||||||
|
if (overrides.isEmpty()) {
|
||||||
|
for (int j = 0; j < downloadHelper.getPeriodCount(); j++) {
|
||||||
|
downloadHelper.addTrackSelection(/* periodIndex = */ j, builder.build());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(/* rendererIndex= */ i);
|
||||||
|
for (int overrideIndex = 0; overrideIndex < overrides.size(); overrideIndex++) {
|
||||||
|
builder.setSelectionOverride(
|
||||||
|
/* rendererIndex= */ i, trackGroupArray, overrides.get(overrideIndex));
|
||||||
|
for (int j = 0; j < downloadHelper.getPeriodCount(); j++) {
|
||||||
|
downloadHelper.addTrackSelection(/* periodIndex = */ j, builder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.clearSelectionOverrides();
|
||||||
|
}
|
||||||
|
builder.setRendererDisabled(/* rendererIndex= */ i, /* disabled= */ true);
|
||||||
|
}
|
||||||
DownloadAction downloadAction = downloadHelper.getDownloadAction(Util.getUtf8Bytes(name));
|
DownloadAction downloadAction = downloadHelper.getDownloadAction(Util.getUtf8Bytes(name));
|
||||||
startDownload(downloadAction);
|
startDownload(downloadAction);
|
||||||
}
|
}
|
||||||
@ -316,86 +300,8 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
// DialogInterface.OnDismissListener implementation.
|
// DialogInterface.OnDismissListener implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDismiss(DialogInterface dialog) {
|
public void onDismiss(DialogInterface dialogInterface) {
|
||||||
downloadHelper.release();
|
downloadHelper.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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++) {
|
|
||||||
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i);
|
|
||||||
if (trackGroupArray.length == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String trackTypeString =
|
|
||||||
getTrackTypeString(mappedTrackInfo.getRendererType(/* rendererIndex= */ i));
|
|
||||||
if (trackTypeString == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String trackSelectionsString = getTrackSelectionString(/* rendererIndex= */ i);
|
|
||||||
View view = dialogInflater.inflate(R.layout.download_track_item, selectionList, false);
|
|
||||||
TextView trackTitleView = view.findViewById(R.id.track_title);
|
|
||||||
TextView trackDescView = view.findViewById(R.id.track_desc);
|
|
||||||
ImageButton editButton = view.findViewById(R.id.edit_button);
|
|
||||||
trackTitleView.setText(trackTypeString);
|
|
||||||
trackDescView.setText(trackSelectionsString);
|
|
||||||
editButton.setTag(i);
|
|
||||||
editButton.setOnClickListener(this);
|
|
||||||
selectionList.addView(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTrackSelectionString(int rendererIndex) {
|
|
||||||
List<TrackSelection> trackSelections =
|
|
||||||
downloadHelper.getTrackSelections(/* periodIndex= */ 0, rendererIndex);
|
|
||||||
String selectedTracks = "";
|
|
||||||
Resources resources = selectionList.getResources();
|
|
||||||
for (int i = 0; i < trackSelections.size(); i++) {
|
|
||||||
TrackSelection selection = trackSelections.get(i);
|
|
||||||
for (int j = 0; j < selection.length(); j++) {
|
|
||||||
String trackName = trackNameProvider.getTrackName(selection.getFormat(j));
|
|
||||||
if (i == 0 && j == 0) {
|
|
||||||
selectedTracks = trackName;
|
|
||||||
} else {
|
|
||||||
selectedTracks = resources.getString(R.string.exo_item_list, selectedTracks, trackName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return selectedTracks.isEmpty()
|
|
||||||
? resources.getString(R.string.exo_track_selection_none)
|
|
||||||
: selectedTracks;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String getTrackTypeString(int trackType) {
|
|
||||||
Resources resources = selectionList.getResources();
|
|
||||||
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:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.demo;
|
package com.google.android.exoplayer2.demo;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
@ -23,6 +22,7 @@ import android.net.Uri;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.util.JsonReader;
|
import android.util.JsonReader;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@ -55,7 +55,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** An activity for selecting from a list of media samples. */
|
/** An activity for selecting from a list of media samples. */
|
||||||
public class SampleChooserActivity extends Activity
|
public class SampleChooserActivity extends AppCompatActivity
|
||||||
implements DownloadTracker.Listener, OnChildClickListener {
|
implements DownloadTracker.Listener, OnChildClickListener {
|
||||||
|
|
||||||
private static final String TAG = "SampleChooserActivity";
|
private static final String TAG = "SampleChooserActivity";
|
||||||
@ -182,7 +182,11 @@ public class SampleChooserActivity extends Activity
|
|||||||
((DemoApplication) getApplication())
|
((DemoApplication) getApplication())
|
||||||
.buildRenderersFactory(isNonNullAndChecked(preferExtensionDecodersMenuItem));
|
.buildRenderersFactory(isNonNullAndChecked(preferExtensionDecodersMenuItem));
|
||||||
downloadTracker.toggleDownload(
|
downloadTracker.toggleDownload(
|
||||||
this, sample.name, uriSample.uri, uriSample.extension, renderersFactory);
|
getSupportFragmentManager(),
|
||||||
|
sample.name,
|
||||||
|
uriSample.uri,
|
||||||
|
uriSample.extension,
|
||||||
|
renderersFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* 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.demo;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.TabLayout;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import android.support.v4.app.FragmentPagerAdapter;
|
||||||
|
import android.support.v4.view.ViewPager;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
|
||||||
|
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||||
|
import com.google.android.exoplayer2.ui.TrackSelectionView;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Dialog to select tracks. */
|
||||||
|
public final class TrackSelectionDialog extends DialogFragment {
|
||||||
|
|
||||||
|
private final SparseArray<TrackSelectionViewFragment> tabFragments;
|
||||||
|
private final List<CharSequence> tabTitles;
|
||||||
|
|
||||||
|
private MappedTrackInfo mappedTrackInfo;
|
||||||
|
private boolean allowAdaptiveSelections;
|
||||||
|
private boolean allowMultipleOverrides;
|
||||||
|
private DialogInterface.OnClickListener onClickListener;
|
||||||
|
private DialogInterface.OnDismissListener onDismissListener;
|
||||||
|
|
||||||
|
/** Creates the dialog. */
|
||||||
|
public TrackSelectionDialog() {
|
||||||
|
tabFragments = new SparseArray<>();
|
||||||
|
tabTitles = new ArrayList<>();
|
||||||
|
// Retain instance across orientation changes to prevent loosing access to init data.
|
||||||
|
setRetainInstance(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the dialog.
|
||||||
|
*
|
||||||
|
* @param mappedTrackInfo The {@link MappedTrackInfo} to display.
|
||||||
|
* @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 onClickListener {@link DialogInterface.OnClickListener} called when tracks are selected.
|
||||||
|
* @param onDismissListener {@link DialogInterface.OnDismissListener} called when the dialog is
|
||||||
|
* dismissed.
|
||||||
|
*/
|
||||||
|
public void init(
|
||||||
|
MappedTrackInfo mappedTrackInfo,
|
||||||
|
boolean allowAdaptiveSelections,
|
||||||
|
boolean allowMultipleOverrides,
|
||||||
|
DialogInterface.OnClickListener onClickListener,
|
||||||
|
DialogInterface.OnDismissListener onDismissListener) {
|
||||||
|
this.mappedTrackInfo = mappedTrackInfo;
|
||||||
|
this.allowAdaptiveSelections = allowAdaptiveSelections;
|
||||||
|
this.allowMultipleOverrides = allowMultipleOverrides;
|
||||||
|
this.onClickListener = onClickListener;
|
||||||
|
this.onDismissListener = onDismissListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a renderer is disabled.
|
||||||
|
*
|
||||||
|
* @param rendererIndex Renderer index.
|
||||||
|
* @return Whether the renderer is disabled.
|
||||||
|
*/
|
||||||
|
public boolean getIsDisabled(int rendererIndex) {
|
||||||
|
TrackSelectionViewFragment rendererView = tabFragments.get(rendererIndex);
|
||||||
|
return rendererView != null && rendererView.trackSelectionView.getIsDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of selected track selection overrides for the specified renderer. There will
|
||||||
|
* be at most one override for each track group.
|
||||||
|
*
|
||||||
|
* @param rendererIndex Renderer index.
|
||||||
|
* @return The list of track selection overrides for this renderer.
|
||||||
|
*/
|
||||||
|
public List<SelectionOverride> getOverrides(int rendererIndex) {
|
||||||
|
TrackSelectionViewFragment rendererView = tabFragments.get(rendererIndex);
|
||||||
|
return rendererView == null
|
||||||
|
? Collections.emptyList()
|
||||||
|
: rendererView.trackSelectionView.getOverrides();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
return new AlertDialog.Builder(getActivity())
|
||||||
|
.setTitle(R.string.exo_download_description)
|
||||||
|
.setPositiveButton(android.R.string.ok, onClickListener)
|
||||||
|
.setNegativeButton(android.R.string.cancel, /* listener= */ null)
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismiss(DialogInterface dialog) {
|
||||||
|
super.onDismiss(dialog);
|
||||||
|
onDismissListener.onDismiss(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(
|
||||||
|
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) {
|
||||||
|
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i);
|
||||||
|
if (trackGroupArray.length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String trackTypeString =
|
||||||
|
getTrackTypeString(mappedTrackInfo.getRendererType(/* rendererIndex= */ i));
|
||||||
|
if (trackTypeString == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TrackSelectionViewFragment tabFragment = new TrackSelectionViewFragment();
|
||||||
|
tabFragment.init(
|
||||||
|
mappedTrackInfo, /* rendererIndex= */ i, allowAdaptiveSelections, allowMultipleOverrides);
|
||||||
|
tabFragments.put(i, tabFragment);
|
||||||
|
tabTitles.add(trackTypeString);
|
||||||
|
}
|
||||||
|
View dialogView = inflater.inflate(R.layout.download_dialog, container, false);
|
||||||
|
TabLayout tabLayout = dialogView.findViewById(R.id.download_dialog_tab_layout);
|
||||||
|
ViewPager viewPager = dialogView.findViewById(R.id.download_dialog_view_pager);
|
||||||
|
viewPager.setAdapter(new FragmentAdapter(getChildFragmentManager()));
|
||||||
|
tabLayout.setupWithViewPager(viewPager);
|
||||||
|
((AlertDialog) getDialog()).setView(dialogView);
|
||||||
|
return dialogView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String getTrackTypeString(int trackType) {
|
||||||
|
Resources resources = getResources();
|
||||||
|
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:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FragmentAdapter extends FragmentPagerAdapter {
|
||||||
|
|
||||||
|
public FragmentAdapter(FragmentManager fragmentManager) {
|
||||||
|
super(fragmentManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Fragment getItem(int position) {
|
||||||
|
return tabFragments.valueAt(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return tabFragments.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public CharSequence getPageTitle(int position) {
|
||||||
|
return tabTitles.get(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fragment to show a track seleciton in tab of the track selection dialog. */
|
||||||
|
public static final class TrackSelectionViewFragment extends Fragment {
|
||||||
|
|
||||||
|
private MappedTrackInfo mappedTrackInfo;
|
||||||
|
private int rendererIndex;
|
||||||
|
private boolean allowAdaptiveSelections;
|
||||||
|
private boolean allowMultipleOverrides;
|
||||||
|
|
||||||
|
/* package */ TrackSelectionView trackSelectionView;
|
||||||
|
|
||||||
|
public void init(
|
||||||
|
MappedTrackInfo mappedTrackInfo,
|
||||||
|
int rendererIndex,
|
||||||
|
boolean allowAdaptiveSelections,
|
||||||
|
boolean allowMultipleOverrides) {
|
||||||
|
this.mappedTrackInfo = mappedTrackInfo;
|
||||||
|
this.rendererIndex = rendererIndex;
|
||||||
|
this.allowAdaptiveSelections = allowAdaptiveSelections;
|
||||||
|
this.allowMultipleOverrides = allowMultipleOverrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(
|
||||||
|
LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View rootView =
|
||||||
|
inflater.inflate(R.layout.download_dialog_tab, container, /* attachToRoot= */ false);
|
||||||
|
trackSelectionView = rootView.findViewById(R.id.download_dialog_track_selection_view);
|
||||||
|
trackSelectionView.setShowDisableOption(true);
|
||||||
|
trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides);
|
||||||
|
trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections);
|
||||||
|
trackSelectionView.init(
|
||||||
|
mappedTrackInfo,
|
||||||
|
rendererIndex,
|
||||||
|
/* isDisabled= */ false,
|
||||||
|
/* overrides= */ Collections.emptyList());
|
||||||
|
return rootView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 304 B |
Binary file not shown.
Before Width: | Height: | Size: 242 B |
Binary file not shown.
Before Width: | Height: | Size: 299 B |
Binary file not shown.
Before Width: | Height: | Size: 413 B |
Binary file not shown.
Before Width: | Height: | Size: 449 B |
@ -14,7 +14,15 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/selection_list"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="wrap_content">
|
||||||
|
<android.support.design.widget.TabLayout
|
||||||
|
android:id="@+id/download_dialog_tab_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
<android.support.v4.view.ViewPager
|
||||||
|
android:id="@+id/download_dialog_view_pager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
</LinearLayout>
|
24
demos/main/src/main/res/layout/download_dialog_tab.xml
Normal file
24
demos/main/src/main/res/layout/download_dialog_tab.xml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2018 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.
|
||||||
|
-->
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<com.google.android.exoplayer2.ui.TrackSelectionView
|
||||||
|
android:id="@+id/download_dialog_track_selection_view"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
</ScrollView>
|
@ -1,53 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2018 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.
|
|
||||||
-->
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="12dp"
|
|
||||||
android:paddingEnd="12dp"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/track_title"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingTop="4dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/track_desc"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingBottom="4dp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/edit_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:contentDescription="@string/download_edit_track"
|
|
||||||
android:src="@drawable/ic_edit"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -51,10 +51,6 @@
|
|||||||
|
|
||||||
<string name="ima_not_loaded">Playing sample without ads, as the IMA extension was not loaded</string>
|
<string name="ima_not_loaded">Playing sample without ads, as the IMA extension was not loaded</string>
|
||||||
|
|
||||||
<string name="download_edit_track">Edit selection</string>
|
|
||||||
|
|
||||||
<string name="download_preparing">Preparing download…</string>
|
|
||||||
|
|
||||||
<string name="download_start_error">Failed to start download</string>
|
<string name="download_start_error">Failed to start download</string>
|
||||||
|
|
||||||
<string name="download_playlist_unsupported">This demo app does not support downloading playlists</string>
|
<string name="download_playlist_unsupported">This demo app does not support downloading playlists</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user