Let SimpleExoPlayerView/LeanbackPlayerAdapter bind with any Player
Also sanitize naming (PlayerView/PlayerControlView). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=182364487
This commit is contained in:
parent
605aeb3a42
commit
c577d9d351
@ -6,6 +6,10 @@
|
|||||||
`SimpleExoPlayerView` is configured to use `TextureView`
|
`SimpleExoPlayerView` is configured to use `TextureView`
|
||||||
([#91](https://github.com/google/ExoPlayer/issues/91)).
|
([#91](https://github.com/google/ExoPlayer/issues/91)).
|
||||||
* Player interface:
|
* Player interface:
|
||||||
|
* Add `Player.VideoComponent`, `Player.TextComponent` and
|
||||||
|
`Player.MetadataComponent` interfaces that define optional video, text and
|
||||||
|
metadata output functionality. New `getVideoComponent`, `getTextComponent`
|
||||||
|
and `getMetadataComponent` methods provide access to this functionality.
|
||||||
* Add optional parameter to `stop` to reset the player when stopping.
|
* Add optional parameter to `stop` to reset the player when stopping.
|
||||||
* Add a reason to `EventListener.onTimelineChanged` to distinguish between
|
* Add a reason to `EventListener.onTimelineChanged` to distinguish between
|
||||||
initial preparation, reset and dynamic updates.
|
initial preparation, reset and dynamic updates.
|
||||||
@ -17,6 +21,10 @@
|
|||||||
more customization of the message. Now supports setting a message delivery
|
more customization of the message. Now supports setting a message delivery
|
||||||
playback position and/or a delivery handler.
|
playback position and/or a delivery handler.
|
||||||
([#2189](https://github.com/google/ExoPlayer/issues/2189)).
|
([#2189](https://github.com/google/ExoPlayer/issues/2189)).
|
||||||
|
* UI components:
|
||||||
|
* Generalized player and control views to allow them to bind with any
|
||||||
|
`Player`, and renamed them to `PlayerView` and `PlayerControlView`
|
||||||
|
respectively.
|
||||||
* Buffering:
|
* Buffering:
|
||||||
* Allow a back-buffer of media to be retained behind the current playback
|
* Allow a back-buffer of media to be retained behind the current playback
|
||||||
position, for fast backward seeking. The back-buffer can be configured by
|
position, for fast backward seeking. The back-buffer can be configured by
|
||||||
|
@ -39,8 +39,8 @@ import com.google.android.exoplayer2.C;
|
|||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer2.castdemo.DemoUtil.Sample;
|
import com.google.android.exoplayer2.castdemo.DemoUtil.Sample;
|
||||||
import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
||||||
import com.google.android.exoplayer2.ui.PlaybackControlView;
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory;
|
import com.google.android.gms.cast.framework.CastButtonFactory;
|
||||||
import com.google.android.gms.cast.framework.CastContext;
|
import com.google.android.gms.cast.framework.CastContext;
|
||||||
|
|
||||||
@ -50,8 +50,8 @@ import com.google.android.gms.cast.framework.CastContext;
|
|||||||
public class MainActivity extends AppCompatActivity implements OnClickListener,
|
public class MainActivity extends AppCompatActivity implements OnClickListener,
|
||||||
PlayerManager.QueuePositionListener {
|
PlayerManager.QueuePositionListener {
|
||||||
|
|
||||||
private SimpleExoPlayerView simpleExoPlayerView;
|
private PlayerView localPlayerView;
|
||||||
private PlaybackControlView castControlView;
|
private PlayerControlView castControlView;
|
||||||
private PlayerManager playerManager;
|
private PlayerManager playerManager;
|
||||||
private MediaQueueAdapter listAdapter;
|
private MediaQueueAdapter listAdapter;
|
||||||
private CastContext castContext;
|
private CastContext castContext;
|
||||||
@ -66,8 +66,8 @@ public class MainActivity extends AppCompatActivity implements OnClickListener,
|
|||||||
|
|
||||||
setContentView(R.layout.main_activity);
|
setContentView(R.layout.main_activity);
|
||||||
|
|
||||||
simpleExoPlayerView = findViewById(R.id.player_view);
|
localPlayerView = findViewById(R.id.local_player_view);
|
||||||
simpleExoPlayerView.requestFocus();
|
localPlayerView.requestFocus();
|
||||||
|
|
||||||
castControlView = findViewById(R.id.cast_control_view);
|
castControlView = findViewById(R.id.cast_control_view);
|
||||||
|
|
||||||
@ -93,8 +93,13 @@ public class MainActivity extends AppCompatActivity implements OnClickListener,
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
playerManager = PlayerManager.createPlayerManager(this, simpleExoPlayerView, castControlView,
|
playerManager =
|
||||||
this, castContext);
|
PlayerManager.createPlayerManager(
|
||||||
|
/* queuePositionListener= */ this,
|
||||||
|
localPlayerView,
|
||||||
|
castControlView,
|
||||||
|
/* context= */ this,
|
||||||
|
castContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -40,8 +40,8 @@ import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
|||||||
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
|
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
|
||||||
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.ui.PlaybackControlView;
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||||
import com.google.android.gms.cast.MediaInfo;
|
import com.google.android.gms.cast.MediaInfo;
|
||||||
@ -73,12 +73,12 @@ import java.util.ArrayList;
|
|||||||
private static final DefaultHttpDataSourceFactory DATA_SOURCE_FACTORY =
|
private static final DefaultHttpDataSourceFactory DATA_SOURCE_FACTORY =
|
||||||
new DefaultHttpDataSourceFactory(USER_AGENT, BANDWIDTH_METER);
|
new DefaultHttpDataSourceFactory(USER_AGENT, BANDWIDTH_METER);
|
||||||
|
|
||||||
private final SimpleExoPlayerView exoPlayerView;
|
private final PlayerView localPlayerView;
|
||||||
private final PlaybackControlView castControlView;
|
private final PlayerControlView castControlView;
|
||||||
private final SimpleExoPlayer exoPlayer;
|
private final SimpleExoPlayer exoPlayer;
|
||||||
private final CastPlayer castPlayer;
|
private final CastPlayer castPlayer;
|
||||||
private final ArrayList<DemoUtil.Sample> mediaQueue;
|
private final ArrayList<DemoUtil.Sample> mediaQueue;
|
||||||
private final QueuePositionListener listener;
|
private final QueuePositionListener queuePositionListener;
|
||||||
|
|
||||||
private DynamicConcatenatingMediaSource dynamicConcatenatingMediaSource;
|
private DynamicConcatenatingMediaSource dynamicConcatenatingMediaSource;
|
||||||
private boolean castMediaQueueCreationPending;
|
private boolean castMediaQueueCreationPending;
|
||||||
@ -86,25 +86,33 @@ import java.util.ArrayList;
|
|||||||
private Player currentPlayer;
|
private Player currentPlayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param listener A {@link QueuePositionListener} for queue position changes.
|
* @param queuePositionListener A {@link QueuePositionListener} for queue position changes.
|
||||||
* @param exoPlayerView The {@link SimpleExoPlayerView} for local playback.
|
* @param localPlayerView The {@link PlayerView} for local playback.
|
||||||
* @param castControlView The {@link PlaybackControlView} to control remote playback.
|
* @param castControlView The {@link PlayerControlView} to control remote playback.
|
||||||
* @param context A {@link Context}.
|
* @param context A {@link Context}.
|
||||||
* @param castContext The {@link CastContext}.
|
* @param castContext The {@link CastContext}.
|
||||||
*/
|
*/
|
||||||
public static PlayerManager createPlayerManager(QueuePositionListener listener,
|
public static PlayerManager createPlayerManager(
|
||||||
SimpleExoPlayerView exoPlayerView, PlaybackControlView castControlView, Context context,
|
QueuePositionListener queuePositionListener,
|
||||||
|
PlayerView localPlayerView,
|
||||||
|
PlayerControlView castControlView,
|
||||||
|
Context context,
|
||||||
CastContext castContext) {
|
CastContext castContext) {
|
||||||
PlayerManager playerManager = new PlayerManager(listener, exoPlayerView, castControlView,
|
PlayerManager playerManager =
|
||||||
context, castContext);
|
new PlayerManager(
|
||||||
|
queuePositionListener, localPlayerView, castControlView, context, castContext);
|
||||||
playerManager.init();
|
playerManager.init();
|
||||||
return playerManager;
|
return playerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayerManager(QueuePositionListener listener, SimpleExoPlayerView exoPlayerView,
|
private PlayerManager(
|
||||||
PlaybackControlView castControlView, Context context, CastContext castContext) {
|
QueuePositionListener queuePositionListener,
|
||||||
this.listener = listener;
|
PlayerView localPlayerView,
|
||||||
this.exoPlayerView = exoPlayerView;
|
PlayerControlView castControlView,
|
||||||
|
Context context,
|
||||||
|
CastContext castContext) {
|
||||||
|
this.queuePositionListener = queuePositionListener;
|
||||||
|
this.localPlayerView = localPlayerView;
|
||||||
this.castControlView = castControlView;
|
this.castControlView = castControlView;
|
||||||
mediaQueue = new ArrayList<>();
|
mediaQueue = new ArrayList<>();
|
||||||
currentItemIndex = C.INDEX_UNSET;
|
currentItemIndex = C.INDEX_UNSET;
|
||||||
@ -113,7 +121,7 @@ import java.util.ArrayList;
|
|||||||
RenderersFactory renderersFactory = new DefaultRenderersFactory(context, null);
|
RenderersFactory renderersFactory = new DefaultRenderersFactory(context, null);
|
||||||
exoPlayer = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);
|
exoPlayer = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);
|
||||||
exoPlayer.addListener(this);
|
exoPlayer.addListener(this);
|
||||||
exoPlayerView.setPlayer(exoPlayer);
|
localPlayerView.setPlayer(exoPlayer);
|
||||||
|
|
||||||
castPlayer = new CastPlayer(castContext);
|
castPlayer = new CastPlayer(castContext);
|
||||||
castPlayer.addListener(this);
|
castPlayer.addListener(this);
|
||||||
@ -242,7 +250,7 @@ import java.util.ArrayList;
|
|||||||
*/
|
*/
|
||||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
if (currentPlayer == exoPlayer) {
|
if (currentPlayer == exoPlayer) {
|
||||||
return exoPlayerView.dispatchKeyEvent(event);
|
return localPlayerView.dispatchKeyEvent(event);
|
||||||
} else /* currentPlayer == castPlayer */ {
|
} else /* currentPlayer == castPlayer */ {
|
||||||
return castControlView.dispatchKeyEvent(event);
|
return castControlView.dispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
@ -256,7 +264,7 @@ import java.util.ArrayList;
|
|||||||
mediaQueue.clear();
|
mediaQueue.clear();
|
||||||
castPlayer.setSessionAvailabilityListener(null);
|
castPlayer.setSessionAvailabilityListener(null);
|
||||||
castPlayer.release();
|
castPlayer.release();
|
||||||
exoPlayerView.setPlayer(null);
|
localPlayerView.setPlayer(null);
|
||||||
exoPlayer.release();
|
exoPlayer.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,10 +317,10 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
// View management.
|
// View management.
|
||||||
if (currentPlayer == exoPlayer) {
|
if (currentPlayer == exoPlayer) {
|
||||||
exoPlayerView.setVisibility(View.VISIBLE);
|
localPlayerView.setVisibility(View.VISIBLE);
|
||||||
castControlView.hide();
|
castControlView.hide();
|
||||||
} else /* currentPlayer == castPlayer */ {
|
} else /* currentPlayer == castPlayer */ {
|
||||||
exoPlayerView.setVisibility(View.GONE);
|
localPlayerView.setVisibility(View.GONE);
|
||||||
castControlView.show();
|
castControlView.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +388,7 @@ import java.util.ArrayList;
|
|||||||
if (this.currentItemIndex != currentItemIndex) {
|
if (this.currentItemIndex != currentItemIndex) {
|
||||||
int oldIndex = this.currentItemIndex;
|
int oldIndex = this.currentItemIndex;
|
||||||
this.currentItemIndex = currentItemIndex;
|
this.currentItemIndex = currentItemIndex;
|
||||||
listener.onQueuePositionChanged(oldIndex, currentItemIndex);
|
queuePositionListener.onQueuePositionChanged(oldIndex, currentItemIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:keepScreenOn="true">
|
android:keepScreenOn="true">
|
||||||
<com.google.android.exoplayer2.ui.SimpleExoPlayerView android:id="@+id/player_view"
|
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/local_player_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="12"
|
android:layout_weight="12"
|
||||||
@ -42,7 +42,7 @@
|
|||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:padding="30dp"/>
|
android:padding="30dp"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
<com.google.android.exoplayer2.ui.PlaybackControlView android:id="@+id/cast_control_view"
|
<com.google.android.exoplayer2.ui.PlayerControlView android:id="@+id/cast_control_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="2"
|
android:layout_weight="2"
|
||||||
|
@ -18,7 +18,7 @@ package com.google.android.exoplayer2.imademo;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main Activity for the IMA plugin demo. {@link ExoPlayer} objects are created by
|
* Main Activity for the IMA plugin demo. {@link ExoPlayer} objects are created by
|
||||||
@ -26,7 +26,7 @@ import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
|||||||
*/
|
*/
|
||||||
public final class MainActivity extends Activity {
|
public final class MainActivity extends Activity {
|
||||||
|
|
||||||
private SimpleExoPlayerView playerView;
|
private PlayerView playerView;
|
||||||
private PlayerManager player;
|
private PlayerManager player;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,7 +38,7 @@ import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
|||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||||
@ -68,7 +68,7 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
new DefaultBandwidthMeter());
|
new DefaultBandwidthMeter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Context context, SimpleExoPlayerView simpleExoPlayerView) {
|
public void init(Context context, PlayerView playerView) {
|
||||||
// Create a default track selector.
|
// Create a default track selector.
|
||||||
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||||
TrackSelection.Factory videoTrackSelectionFactory =
|
TrackSelection.Factory videoTrackSelectionFactory =
|
||||||
@ -79,7 +79,7 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
player = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
|
player = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
|
||||||
|
|
||||||
// Bind the player to the view.
|
// Bind the player to the view.
|
||||||
simpleExoPlayerView.setPlayer(player);
|
playerView.setPlayer(player);
|
||||||
|
|
||||||
// This is the MediaSource representing the content media (i.e. not the ad).
|
// This is the MediaSource representing the content media (i.e. not the ad).
|
||||||
String contentUrl = context.getString(R.string.content_url);
|
String contentUrl = context.getString(R.string.content_url);
|
||||||
@ -92,7 +92,7 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
contentMediaSource,
|
contentMediaSource,
|
||||||
/* adMediaSourceFactory= */ this,
|
/* adMediaSourceFactory= */ this,
|
||||||
adsLoader,
|
adsLoader,
|
||||||
simpleExoPlayerView.getOverlayFrameLayout(),
|
playerView.getOverlayFrameLayout(),
|
||||||
/* eventHandler= */ null,
|
/* eventHandler= */ null,
|
||||||
/* eventListener= */ null);
|
/* eventListener= */ null);
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
|
<com.google.android.exoplayer2.ui.PlayerView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/player_view"
|
android:id="@+id/player_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -68,8 +68,8 @@ import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedT
|
|||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||||
import com.google.android.exoplayer2.ui.DebugTextViewHelper;
|
import com.google.android.exoplayer2.ui.DebugTextViewHelper;
|
||||||
import com.google.android.exoplayer2.ui.PlaybackControlView;
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||||
@ -79,11 +79,9 @@ import java.net.CookieManager;
|
|||||||
import java.net.CookiePolicy;
|
import java.net.CookiePolicy;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/** An activity that plays media using {@link SimpleExoPlayer}. */
|
||||||
* An activity that plays media using {@link SimpleExoPlayer}.
|
public class PlayerActivity extends Activity
|
||||||
*/
|
implements OnClickListener, PlayerControlView.VisibilityListener {
|
||||||
public class PlayerActivity extends Activity implements OnClickListener,
|
|
||||||
PlaybackControlView.VisibilityListener {
|
|
||||||
|
|
||||||
public static final String DRM_SCHEME_EXTRA = "drm_scheme";
|
public static final String DRM_SCHEME_EXTRA = "drm_scheme";
|
||||||
public static final String DRM_LICENSE_URL = "drm_license_url";
|
public static final String DRM_LICENSE_URL = "drm_license_url";
|
||||||
@ -112,7 +110,7 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
|
|
||||||
private Handler mainHandler;
|
private Handler mainHandler;
|
||||||
private EventLogger eventLogger;
|
private EventLogger eventLogger;
|
||||||
private SimpleExoPlayerView simpleExoPlayerView;
|
private PlayerView playerView;
|
||||||
private LinearLayout debugRootView;
|
private LinearLayout debugRootView;
|
||||||
private TextView debugTextView;
|
private TextView debugTextView;
|
||||||
private Button retryButton;
|
private Button retryButton;
|
||||||
@ -156,9 +154,9 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
retryButton = findViewById(R.id.retry_button);
|
retryButton = findViewById(R.id.retry_button);
|
||||||
retryButton.setOnClickListener(this);
|
retryButton.setOnClickListener(this);
|
||||||
|
|
||||||
simpleExoPlayerView = findViewById(R.id.player_view);
|
playerView = findViewById(R.id.player_view);
|
||||||
simpleExoPlayerView.setControllerVisibilityListener(this);
|
playerView.setControllerVisibilityListener(this);
|
||||||
simpleExoPlayerView.requestFocus();
|
playerView.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -223,7 +221,7 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
@Override
|
@Override
|
||||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
// See whether the player view wants to handle media or DPAD keys events.
|
// See whether the player view wants to handle media or DPAD keys events.
|
||||||
return simpleExoPlayerView.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
|
return playerView.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnClickListener methods
|
// OnClickListener methods
|
||||||
@ -303,7 +301,7 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
player.addAudioDebugListener(eventLogger);
|
player.addAudioDebugListener(eventLogger);
|
||||||
player.addVideoDebugListener(eventLogger);
|
player.addVideoDebugListener(eventLogger);
|
||||||
|
|
||||||
simpleExoPlayerView.setPlayer(player);
|
playerView.setPlayer(player);
|
||||||
player.setPlayWhenReady(shouldAutoPlay);
|
player.setPlayWhenReady(shouldAutoPlay);
|
||||||
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
||||||
debugViewHelper.start();
|
debugViewHelper.start();
|
||||||
@ -470,7 +468,7 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
.newInstance(this, adTagUri);
|
.newInstance(this, adTagUri);
|
||||||
adUiViewGroup = new FrameLayout(this);
|
adUiViewGroup = new FrameLayout(this);
|
||||||
// The demo app has a non-null overlay frame layout.
|
// The demo app has a non-null overlay frame layout.
|
||||||
simpleExoPlayerView.getOverlayFrameLayout().addView(adUiViewGroup);
|
playerView.getOverlayFrameLayout().addView(adUiViewGroup);
|
||||||
}
|
}
|
||||||
AdsMediaSource.MediaSourceFactory adMediaSourceFactory =
|
AdsMediaSource.MediaSourceFactory adMediaSourceFactory =
|
||||||
new AdsMediaSource.MediaSourceFactory() {
|
new AdsMediaSource.MediaSourceFactory() {
|
||||||
@ -495,7 +493,7 @@ public class PlayerActivity extends Activity implements OnClickListener,
|
|||||||
adsLoader.release();
|
adsLoader.release();
|
||||||
adsLoader = null;
|
adsLoader = null;
|
||||||
loadedAdTagUri = null;
|
loadedAdTagUri = null;
|
||||||
simpleExoPlayerView.getOverlayFrameLayout().removeAllViews();
|
playerView.getOverlayFrameLayout().removeAllViews();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:keepScreenOn="true">
|
android:keepScreenOn="true">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.SimpleExoPlayerView android:id="@+id/player_view"
|
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/player_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
@ -27,7 +27,4 @@ locally. Instructions for doing this can be found in ExoPlayer's
|
|||||||
## Using the extension ##
|
## Using the extension ##
|
||||||
|
|
||||||
Create a `CastPlayer` and use it to integrate Cast into your app using
|
Create a `CastPlayer` and use it to integrate Cast into your app using
|
||||||
ExoPlayer's common Player interface. You can try the Cast Extension to see how a
|
ExoPlayer's common `Player` interface.
|
||||||
[PlaybackControlView][] can be used to control playback in a remote receiver app.
|
|
||||||
|
|
||||||
[PlaybackControlView]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/ui/PlaybackControlView.html
|
|
||||||
|
@ -280,6 +280,16 @@ public final class CastPlayer implements Player {
|
|||||||
|
|
||||||
// Player implementation.
|
// Player implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VideoComponent getVideoComponent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponent getTextComponent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(EventListener listener) {
|
public void addListener(EventListener listener) {
|
||||||
listeners.add(listener);
|
listeners.add(listener);
|
||||||
|
@ -33,13 +33,11 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
|||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
||||||
import com.google.android.exoplayer2.Player.TimelineChangeReason;
|
import com.google.android.exoplayer2.Player.TimelineChangeReason;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.util.ErrorMessageProvider;
|
import com.google.android.exoplayer2.util.ErrorMessageProvider;
|
||||||
|
import com.google.android.exoplayer2.video.VideoListener;
|
||||||
|
|
||||||
/**
|
/** Leanback {@code PlayerAdapter} implementation for {@link Player}. */
|
||||||
* Leanback {@code PlayerAdapter} implementation for {@link SimpleExoPlayer}.
|
|
||||||
*/
|
|
||||||
public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -47,7 +45,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final SimpleExoPlayer player;
|
private final Player player;
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
private final ComponentListener componentListener;
|
private final ComponentListener componentListener;
|
||||||
private final Runnable updateProgressRunnable;
|
private final Runnable updateProgressRunnable;
|
||||||
@ -60,14 +58,14 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an instance. Note that the {@code PlayerAdapter} does not manage the lifecycle of the
|
* Builds an instance. Note that the {@code PlayerAdapter} does not manage the lifecycle of the
|
||||||
* {@link SimpleExoPlayer} instance. The caller remains responsible for releasing the player when
|
* {@link Player} instance. The caller remains responsible for releasing the player when it's no
|
||||||
* it's no longer required.
|
* longer required.
|
||||||
*
|
*
|
||||||
* @param context The current context (activity).
|
* @param context The current context (activity).
|
||||||
* @param player Instance of your exoplayer that needs to be configured.
|
* @param player Instance of your exoplayer that needs to be configured.
|
||||||
* @param updatePeriodMs The delay between player control updates, in milliseconds.
|
* @param updatePeriodMs The delay between player control updates, in milliseconds.
|
||||||
*/
|
*/
|
||||||
public LeanbackPlayerAdapter(Context context, SimpleExoPlayer player, final int updatePeriodMs) {
|
public LeanbackPlayerAdapter(Context context, Player player, final int updatePeriodMs) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
handler = new Handler();
|
handler = new Handler();
|
||||||
@ -115,13 +113,19 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
|||||||
}
|
}
|
||||||
notifyStateChanged();
|
notifyStateChanged();
|
||||||
player.addListener(componentListener);
|
player.addListener(componentListener);
|
||||||
player.addVideoListener(componentListener);
|
Player.VideoComponent videoComponent = player.getVideoComponent();
|
||||||
|
if (videoComponent != null) {
|
||||||
|
videoComponent.addVideoListener(componentListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDetachedFromHost() {
|
public void onDetachedFromHost() {
|
||||||
player.removeListener(componentListener);
|
player.removeListener(componentListener);
|
||||||
player.removeVideoListener(componentListener);
|
Player.VideoComponent videoComponent = player.getVideoComponent();
|
||||||
|
if (videoComponent != null) {
|
||||||
|
videoComponent.removeVideoListener(componentListener);
|
||||||
|
}
|
||||||
if (surfaceHolderGlueHost != null) {
|
if (surfaceHolderGlueHost != null) {
|
||||||
surfaceHolderGlueHost.setSurfaceHolderCallback(null);
|
surfaceHolderGlueHost.setSurfaceHolderCallback(null);
|
||||||
surfaceHolderGlueHost = null;
|
surfaceHolderGlueHost = null;
|
||||||
@ -196,7 +200,10 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
|||||||
|
|
||||||
/* package */ void setVideoSurface(Surface surface) {
|
/* package */ void setVideoSurface(Surface surface) {
|
||||||
hasSurface = surface != null;
|
hasSurface = surface != null;
|
||||||
player.setVideoSurface(surface);
|
Player.VideoComponent videoComponent = player.getVideoComponent();
|
||||||
|
if (videoComponent != null) {
|
||||||
|
videoComponent.setVideoSurface(surface);
|
||||||
|
}
|
||||||
maybeNotifyPreparedStateChanged(getCallback());
|
maybeNotifyPreparedStateChanged(getCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,8 +226,8 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ComponentListener extends Player.DefaultEventListener implements
|
private final class ComponentListener extends Player.DefaultEventListener
|
||||||
SimpleExoPlayer.VideoListener, SurfaceHolder.Callback {
|
implements SurfaceHolder.Callback, VideoListener {
|
||||||
|
|
||||||
// SurfaceHolder.Callback implementation.
|
// SurfaceHolder.Callback implementation.
|
||||||
|
|
||||||
@ -274,11 +281,11 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
|||||||
callback.onBufferedPositionChanged(LeanbackPlayerAdapter.this);
|
callback.onBufferedPositionChanged(LeanbackPlayerAdapter.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleExoplayerView.Callback implementation.
|
// VideoListener implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
public void onVideoSizeChanged(
|
||||||
float pixelWidthHeightRatio) {
|
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
||||||
getCallback().onVideoSizeChanged(LeanbackPlayerAdapter.this, width, height);
|
getCallback().onVideoSizeChanged(LeanbackPlayerAdapter.this, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +124,16 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
|
internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VideoComponent getVideoComponent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponent getTextComponent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Looper getPlaybackLooper() {
|
public Looper getPlaybackLooper() {
|
||||||
return internalPlayer.getPlaybackLooper();
|
return internalPlayer.getPlaybackLooper();
|
||||||
|
@ -18,8 +18,14 @@ package com.google.android.exoplayer2;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.Surface;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
import android.view.TextureView;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
|
import com.google.android.exoplayer2.text.TextOutput;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||||
|
import com.google.android.exoplayer2.video.VideoListener;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
@ -44,6 +50,130 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
*/
|
*/
|
||||||
public interface Player {
|
public interface Player {
|
||||||
|
|
||||||
|
/** The video component of a {@link Player}. */
|
||||||
|
interface VideoComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the video scaling mode.
|
||||||
|
*
|
||||||
|
* @param videoScalingMode The video scaling mode.
|
||||||
|
*/
|
||||||
|
void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode);
|
||||||
|
|
||||||
|
/** Returns the video scaling mode. */
|
||||||
|
@C.VideoScalingMode
|
||||||
|
int getVideoScalingMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener to receive video events.
|
||||||
|
*
|
||||||
|
* @param listener The listener to register.
|
||||||
|
*/
|
||||||
|
void addVideoListener(VideoListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a listener of video events.
|
||||||
|
*
|
||||||
|
* @param listener The listener to unregister.
|
||||||
|
*/
|
||||||
|
void removeVideoListener(VideoListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears any {@link Surface}, {@link SurfaceHolder}, {@link SurfaceView} or {@link TextureView}
|
||||||
|
* currently set on the player.
|
||||||
|
*/
|
||||||
|
void clearVideoSurface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link Surface} onto which video will be rendered. The caller is responsible for
|
||||||
|
* tracking the lifecycle of the surface, and must clear the surface by calling {@code
|
||||||
|
* setVideoSurface(null)} if the surface is destroyed.
|
||||||
|
*
|
||||||
|
* <p>If the surface is held by a {@link SurfaceView}, {@link TextureView} or {@link
|
||||||
|
* SurfaceHolder} then it's recommended to use {@link #setVideoSurfaceView(SurfaceView)}, {@link
|
||||||
|
* #setVideoTextureView(TextureView)} or {@link #setVideoSurfaceHolder(SurfaceHolder)} rather
|
||||||
|
* than this method, since passing the holder allows the player to track the lifecycle of the
|
||||||
|
* surface automatically.
|
||||||
|
*
|
||||||
|
* @param surface The {@link Surface}.
|
||||||
|
*/
|
||||||
|
void setVideoSurface(Surface surface);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the {@link Surface} onto which video is being rendered if it matches the one passed.
|
||||||
|
* Else does nothing.
|
||||||
|
*
|
||||||
|
* @param surface The surface to clear.
|
||||||
|
*/
|
||||||
|
void clearVideoSurface(Surface surface);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link SurfaceHolder} that holds the {@link Surface} onto which video will be
|
||||||
|
* rendered. The player will track the lifecycle of the surface automatically.
|
||||||
|
*
|
||||||
|
* @param surfaceHolder The surface holder.
|
||||||
|
*/
|
||||||
|
void setVideoSurfaceHolder(SurfaceHolder surfaceHolder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the {@link SurfaceHolder} that holds the {@link Surface} onto which video is being
|
||||||
|
* rendered if it matches the one passed. Else does nothing.
|
||||||
|
*
|
||||||
|
* @param surfaceHolder The surface holder to clear.
|
||||||
|
*/
|
||||||
|
void clearVideoSurfaceHolder(SurfaceHolder surfaceHolder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link SurfaceView} onto which video will be rendered. The player will track the
|
||||||
|
* lifecycle of the surface automatically.
|
||||||
|
*
|
||||||
|
* @param surfaceView The surface view.
|
||||||
|
*/
|
||||||
|
void setVideoSurfaceView(SurfaceView surfaceView);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the {@link SurfaceView} onto which video is being rendered if it matches the one
|
||||||
|
* passed. Else does nothing.
|
||||||
|
*
|
||||||
|
* @param surfaceView The texture view to clear.
|
||||||
|
*/
|
||||||
|
void clearVideoSurfaceView(SurfaceView surfaceView);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link TextureView} onto which video will be rendered. The player will track the
|
||||||
|
* lifecycle of the surface automatically.
|
||||||
|
*
|
||||||
|
* @param textureView The texture view.
|
||||||
|
*/
|
||||||
|
void setVideoTextureView(TextureView textureView);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the {@link TextureView} onto which video is being rendered if it matches the one
|
||||||
|
* passed. Else does nothing.
|
||||||
|
*
|
||||||
|
* @param textureView The texture view to clear.
|
||||||
|
*/
|
||||||
|
void clearVideoTextureView(TextureView textureView);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The text component of a {@link Player}. */
|
||||||
|
interface TextComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an output to receive text events.
|
||||||
|
*
|
||||||
|
* @param listener The output to register.
|
||||||
|
*/
|
||||||
|
void addTextOutput(TextOutput listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a text output.
|
||||||
|
*
|
||||||
|
* @param listener The output to remove.
|
||||||
|
*/
|
||||||
|
void removeTextOutput(TextOutput listener);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener of changes in player state.
|
* Listener of changes in player state.
|
||||||
*/
|
*/
|
||||||
@ -298,6 +428,14 @@ public interface Player {
|
|||||||
*/
|
*/
|
||||||
int TIMELINE_CHANGE_REASON_DYNAMIC = 2;
|
int TIMELINE_CHANGE_REASON_DYNAMIC = 2;
|
||||||
|
|
||||||
|
/** Returns the component of this player for video output, or null if video is not supported. */
|
||||||
|
@Nullable
|
||||||
|
VideoComponent getVideoComponent();
|
||||||
|
|
||||||
|
/** Returns the component of this player for text output, or null if text is not supported. */
|
||||||
|
@Nullable
|
||||||
|
TextComponent getTextComponent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a listener to receive events from the player. The listener's methods will be called on
|
* Register a listener to receive events from the player. The listener's methods will be called on
|
||||||
* the thread that was used to construct the player. However, if the thread used to construct the
|
* the thread that was used to construct the player. However, if the thread used to construct the
|
||||||
|
@ -50,39 +50,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
* be obtained from {@link ExoPlayerFactory}.
|
* be obtained from {@link ExoPlayerFactory}.
|
||||||
*/
|
*/
|
||||||
@TargetApi(16)
|
@TargetApi(16)
|
||||||
public class SimpleExoPlayer implements ExoPlayer {
|
public class SimpleExoPlayer implements ExoPlayer, Player.VideoComponent, Player.TextComponent {
|
||||||
|
|
||||||
/**
|
/** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */
|
||||||
* A listener for video rendering information from a {@link SimpleExoPlayer}.
|
@Deprecated
|
||||||
*/
|
public interface VideoListener extends com.google.android.exoplayer2.video.VideoListener {}
|
||||||
public interface VideoListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called each time there's a change in the size of the video being rendered.
|
|
||||||
*
|
|
||||||
* @param width The video width in pixels.
|
|
||||||
* @param height The video height in pixels.
|
|
||||||
* @param unappliedRotationDegrees For videos that require a rotation, this is the clockwise
|
|
||||||
* rotation in degrees that the application should apply for the video for it to be rendered
|
|
||||||
* in the correct orientation. This value will always be zero on API levels 21 and above,
|
|
||||||
* since the renderer will apply all necessary rotations internally. On earlier API levels
|
|
||||||
* this is not possible. Applications that use {@link android.view.TextureView} can apply
|
|
||||||
* the rotation by calling {@link android.view.TextureView#setTransform}. Applications that
|
|
||||||
* do not expect to encounter rotated videos can safely ignore this parameter.
|
|
||||||
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case
|
|
||||||
* of square pixels this will be equal to 1.0. Different values are indicative of anamorphic
|
|
||||||
* content.
|
|
||||||
*/
|
|
||||||
void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
|
||||||
float pixelWidthHeightRatio);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a frame is rendered for the first time since setting the surface, and when a
|
|
||||||
* frame is rendered for the first time since a video track was selected.
|
|
||||||
*/
|
|
||||||
void onRenderedFirstFrame();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String TAG = "SimpleExoPlayer";
|
private static final String TAG = "SimpleExoPlayer";
|
||||||
|
|
||||||
@ -90,7 +62,8 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
|
|
||||||
private final ExoPlayer player;
|
private final ExoPlayer player;
|
||||||
private final ComponentListener componentListener;
|
private final ComponentListener componentListener;
|
||||||
private final CopyOnWriteArraySet<VideoListener> videoListeners;
|
private final CopyOnWriteArraySet<com.google.android.exoplayer2.video.VideoListener>
|
||||||
|
videoListeners;
|
||||||
private final CopyOnWriteArraySet<TextOutput> textOutputs;
|
private final CopyOnWriteArraySet<TextOutput> textOutputs;
|
||||||
private final CopyOnWriteArraySet<MetadataOutput> metadataOutputs;
|
private final CopyOnWriteArraySet<MetadataOutput> metadataOutputs;
|
||||||
private final CopyOnWriteArraySet<VideoRendererEventListener> videoDebugListeners;
|
private final CopyOnWriteArraySet<VideoRendererEventListener> videoDebugListeners;
|
||||||
@ -154,14 +127,25 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
player = createExoPlayerImpl(renderers, trackSelector, loadControl, clock);
|
player = createExoPlayerImpl(renderers, trackSelector, loadControl, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VideoComponent getVideoComponent() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponent getTextComponent() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the video scaling mode.
|
* Sets the video scaling mode.
|
||||||
* <p>
|
*
|
||||||
* Note that the scaling mode only applies if a {@link MediaCodec}-based video {@link Renderer} is
|
* <p>Note that the scaling mode only applies if a {@link MediaCodec}-based video {@link Renderer}
|
||||||
* enabled and if the output surface is owned by a {@link android.view.SurfaceView}.
|
* is enabled and if the output surface is owned by a {@link android.view.SurfaceView}.
|
||||||
*
|
*
|
||||||
* @param videoScalingMode The video scaling mode.
|
* @param videoScalingMode The video scaling mode.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) {
|
public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) {
|
||||||
this.videoScalingMode = videoScalingMode;
|
this.videoScalingMode = videoScalingMode;
|
||||||
for (Renderer renderer : renderers) {
|
for (Renderer renderer : renderers) {
|
||||||
@ -175,57 +159,30 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the video scaling mode.
|
|
||||||
*/
|
|
||||||
public @C.VideoScalingMode int getVideoScalingMode() {
|
public @C.VideoScalingMode int getVideoScalingMode() {
|
||||||
return videoScalingMode;
|
return videoScalingMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Clears any {@link Surface}, {@link SurfaceHolder}, {@link SurfaceView} or {@link TextureView}
|
|
||||||
* currently set on the player.
|
|
||||||
*/
|
|
||||||
public void clearVideoSurface() {
|
public void clearVideoSurface() {
|
||||||
setVideoSurface(null);
|
setVideoSurface(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the {@link Surface} onto which video will be rendered. The caller is responsible for
|
|
||||||
* tracking the lifecycle of the surface, and must clear the surface by calling
|
|
||||||
* {@code setVideoSurface(null)} if the surface is destroyed.
|
|
||||||
* <p>
|
|
||||||
* If the surface is held by a {@link SurfaceView}, {@link TextureView} or {@link SurfaceHolder}
|
|
||||||
* then it's recommended to use {@link #setVideoSurfaceView(SurfaceView)},
|
|
||||||
* {@link #setVideoTextureView(TextureView)} or {@link #setVideoSurfaceHolder(SurfaceHolder)}
|
|
||||||
* rather than this method, since passing the holder allows the player to track the lifecycle of
|
|
||||||
* the surface automatically.
|
|
||||||
*
|
|
||||||
* @param surface The {@link Surface}.
|
|
||||||
*/
|
|
||||||
public void setVideoSurface(Surface surface) {
|
public void setVideoSurface(Surface surface) {
|
||||||
removeSurfaceCallbacks();
|
removeSurfaceCallbacks();
|
||||||
setVideoSurfaceInternal(surface, false);
|
setVideoSurfaceInternal(surface, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Clears the {@link Surface} onto which video is being rendered if it matches the one passed.
|
|
||||||
* Else does nothing.
|
|
||||||
*
|
|
||||||
* @param surface The surface to clear.
|
|
||||||
*/
|
|
||||||
public void clearVideoSurface(Surface surface) {
|
public void clearVideoSurface(Surface surface) {
|
||||||
if (surface != null && surface == this.surface) {
|
if (surface != null && surface == this.surface) {
|
||||||
setVideoSurface(null);
|
setVideoSurface(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the {@link SurfaceHolder} that holds the {@link Surface} onto which video will be
|
|
||||||
* rendered. The player will track the lifecycle of the surface automatically.
|
|
||||||
*
|
|
||||||
* @param surfaceHolder The surface holder.
|
|
||||||
*/
|
|
||||||
public void setVideoSurfaceHolder(SurfaceHolder surfaceHolder) {
|
public void setVideoSurfaceHolder(SurfaceHolder surfaceHolder) {
|
||||||
removeSurfaceCallbacks();
|
removeSurfaceCallbacks();
|
||||||
this.surfaceHolder = surfaceHolder;
|
this.surfaceHolder = surfaceHolder;
|
||||||
@ -238,44 +195,24 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Clears the {@link SurfaceHolder} that holds the {@link Surface} onto which video is being
|
|
||||||
* rendered if it matches the one passed. Else does nothing.
|
|
||||||
*
|
|
||||||
* @param surfaceHolder The surface holder to clear.
|
|
||||||
*/
|
|
||||||
public void clearVideoSurfaceHolder(SurfaceHolder surfaceHolder) {
|
public void clearVideoSurfaceHolder(SurfaceHolder surfaceHolder) {
|
||||||
if (surfaceHolder != null && surfaceHolder == this.surfaceHolder) {
|
if (surfaceHolder != null && surfaceHolder == this.surfaceHolder) {
|
||||||
setVideoSurfaceHolder(null);
|
setVideoSurfaceHolder(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the {@link SurfaceView} onto which video will be rendered. The player will track the
|
|
||||||
* lifecycle of the surface automatically.
|
|
||||||
*
|
|
||||||
* @param surfaceView The surface view.
|
|
||||||
*/
|
|
||||||
public void setVideoSurfaceView(SurfaceView surfaceView) {
|
public void setVideoSurfaceView(SurfaceView surfaceView) {
|
||||||
setVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder());
|
setVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Clears the {@link SurfaceView} onto which video is being rendered if it matches the one passed.
|
|
||||||
* Else does nothing.
|
|
||||||
*
|
|
||||||
* @param surfaceView The texture view to clear.
|
|
||||||
*/
|
|
||||||
public void clearVideoSurfaceView(SurfaceView surfaceView) {
|
public void clearVideoSurfaceView(SurfaceView surfaceView) {
|
||||||
clearVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder());
|
clearVideoSurfaceHolder(surfaceView == null ? null : surfaceView.getHolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the {@link TextureView} onto which video will be rendered. The player will track the
|
|
||||||
* lifecycle of the surface automatically.
|
|
||||||
*
|
|
||||||
* @param textureView The texture view.
|
|
||||||
*/
|
|
||||||
public void setVideoTextureView(TextureView textureView) {
|
public void setVideoTextureView(TextureView textureView) {
|
||||||
removeSurfaceCallbacks();
|
removeSurfaceCallbacks();
|
||||||
this.textureView = textureView;
|
this.textureView = textureView;
|
||||||
@ -292,12 +229,7 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Clears the {@link TextureView} onto which video is being rendered if it matches the one passed.
|
|
||||||
* Else does nothing.
|
|
||||||
*
|
|
||||||
* @param textureView The texture view to clear.
|
|
||||||
*/
|
|
||||||
public void clearVideoTextureView(TextureView textureView) {
|
public void clearVideoTextureView(TextureView textureView) {
|
||||||
if (textureView != null && textureView == this.textureView) {
|
if (textureView != null && textureView == this.textureView) {
|
||||||
setVideoTextureView(null);
|
setVideoTextureView(null);
|
||||||
@ -446,21 +378,13 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
return audioDecoderCounters;
|
return audioDecoderCounters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Adds a listener to receive video events.
|
public void addVideoListener(com.google.android.exoplayer2.video.VideoListener listener) {
|
||||||
*
|
|
||||||
* @param listener The listener to register.
|
|
||||||
*/
|
|
||||||
public void addVideoListener(VideoListener listener) {
|
|
||||||
videoListeners.add(listener);
|
videoListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Removes a listener of video events.
|
public void removeVideoListener(com.google.android.exoplayer2.video.VideoListener listener) {
|
||||||
*
|
|
||||||
* @param listener The listener to unregister.
|
|
||||||
*/
|
|
||||||
public void removeVideoListener(VideoListener listener) {
|
|
||||||
videoListeners.remove(listener);
|
videoListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +392,7 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
* Sets a listener to receive video events, removing all existing listeners.
|
* Sets a listener to receive video events, removing all existing listeners.
|
||||||
*
|
*
|
||||||
* @param listener The listener.
|
* @param listener The listener.
|
||||||
* @deprecated Use {@link #addVideoListener(VideoListener)}.
|
* @deprecated Use {@link #addVideoListener(com.google.android.exoplayer2.video.VideoListener)}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setVideoListener(VideoListener listener) {
|
public void setVideoListener(VideoListener listener) {
|
||||||
@ -479,30 +403,23 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equivalent to {@link #removeVideoListener(VideoListener)}.
|
* Equivalent to {@link #removeVideoListener(com.google.android.exoplayer2.video.VideoListener)}.
|
||||||
*
|
*
|
||||||
* @param listener The listener to clear.
|
* @param listener The listener to clear.
|
||||||
* @deprecated Use {@link #removeVideoListener(VideoListener)}.
|
* @deprecated Use {@link
|
||||||
|
* #removeVideoListener(com.google.android.exoplayer2.video.VideoListener)}.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void clearVideoListener(VideoListener listener) {
|
public void clearVideoListener(VideoListener listener) {
|
||||||
removeVideoListener(listener);
|
removeVideoListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Registers an output to receive text events.
|
|
||||||
*
|
|
||||||
* @param listener The output to register.
|
|
||||||
*/
|
|
||||||
public void addTextOutput(TextOutput listener) {
|
public void addTextOutput(TextOutput listener) {
|
||||||
textOutputs.add(listener);
|
textOutputs.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Removes a text output.
|
|
||||||
*
|
|
||||||
* @param listener The output to remove.
|
|
||||||
*/
|
|
||||||
public void removeTextOutput(TextOutput listener) {
|
public void removeTextOutput(TextOutput listener) {
|
||||||
textOutputs.remove(listener);
|
textOutputs.remove(listener);
|
||||||
}
|
}
|
||||||
@ -532,20 +449,10 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
removeTextOutput(output);
|
removeTextOutput(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers an output to receive metadata events.
|
|
||||||
*
|
|
||||||
* @param listener The output to register.
|
|
||||||
*/
|
|
||||||
public void addMetadataOutput(MetadataOutput listener) {
|
public void addMetadataOutput(MetadataOutput listener) {
|
||||||
metadataOutputs.add(listener);
|
metadataOutputs.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a metadata output.
|
|
||||||
*
|
|
||||||
* @param listener The output to remove.
|
|
||||||
*/
|
|
||||||
public void removeMetadataOutput(MetadataOutput listener) {
|
public void removeMetadataOutput(MetadataOutput listener) {
|
||||||
metadataOutputs.remove(listener);
|
metadataOutputs.remove(listener);
|
||||||
}
|
}
|
||||||
@ -978,7 +885,7 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
||||||
float pixelWidthHeightRatio) {
|
float pixelWidthHeightRatio) {
|
||||||
for (VideoListener videoListener : videoListeners) {
|
for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||||
videoListener.onVideoSizeChanged(width, height, unappliedRotationDegrees,
|
videoListener.onVideoSizeChanged(width, height, unappliedRotationDegrees,
|
||||||
pixelWidthHeightRatio);
|
pixelWidthHeightRatio);
|
||||||
}
|
}
|
||||||
@ -991,7 +898,7 @@ public class SimpleExoPlayer implements ExoPlayer {
|
|||||||
@Override
|
@Override
|
||||||
public void onRenderedFirstFrame(Surface surface) {
|
public void onRenderedFirstFrame(Surface surface) {
|
||||||
if (SimpleExoPlayer.this.surface == surface) {
|
if (SimpleExoPlayer.this.surface == surface) {
|
||||||
for (VideoListener videoListener : videoListeners) {
|
for (com.google.android.exoplayer2.video.VideoListener videoListener : videoListeners) {
|
||||||
videoListener.onRenderedFirstFrame();
|
videoListener.onRenderedFirstFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.video;
|
||||||
|
|
||||||
|
/** A listener for metadata corresponding to video being rendered. */
|
||||||
|
public interface VideoListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called each time there's a change in the size of the video being rendered.
|
||||||
|
*
|
||||||
|
* @param width The video width in pixels.
|
||||||
|
* @param height The video height in pixels.
|
||||||
|
* @param unappliedRotationDegrees For videos that require a rotation, this is the clockwise
|
||||||
|
* rotation in degrees that the application should apply for the video for it to be rendered
|
||||||
|
* in the correct orientation. This value will always be zero on API levels 21 and above,
|
||||||
|
* since the renderer will apply all necessary rotations internally. On earlier API levels
|
||||||
|
* this is not possible. Applications that use {@link android.view.TextureView} can apply the
|
||||||
|
* rotation by calling {@link android.view.TextureView#setTransform}. Applications that do not
|
||||||
|
* expect to encounter rotated videos can safely ignore this parameter.
|
||||||
|
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case of
|
||||||
|
* square pixels this will be equal to 1.0. Different values are indicative of anamorphic
|
||||||
|
* content.
|
||||||
|
*/
|
||||||
|
void onVideoSizeChanged(
|
||||||
|
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a frame is rendered for the first time since setting the surface, and when a frame
|
||||||
|
* is rendered for the first time since a video track was selected.
|
||||||
|
*/
|
||||||
|
void onRenderedFirstFrame();
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
18
library/ui/src/main/res/layout/exo_player_control_view.xml
Normal file
18
library/ui/src/main/res/layout/exo_player_control_view.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<merge>
|
||||||
|
<include layout="@layout/exo_playback_control_view"/>
|
||||||
|
</merge>
|
18
library/ui/src/main/res/layout/exo_player_view.xml
Normal file
18
library/ui/src/main/res/layout/exo_player_view.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<merge>
|
||||||
|
<include layout="@layout/exo_simple_player_view"/>
|
||||||
|
</merge>
|
@ -41,7 +41,7 @@
|
|||||||
</attr>
|
</attr>
|
||||||
<attr name="show_shuffle_button" format="boolean"/>
|
<attr name="show_shuffle_button" format="boolean"/>
|
||||||
|
|
||||||
<declare-styleable name="SimpleExoPlayerView">
|
<declare-styleable name="PlayerView">
|
||||||
<attr name="use_artwork" format="boolean"/>
|
<attr name="use_artwork" format="boolean"/>
|
||||||
<attr name="shutter_background_color" format="color"/>
|
<attr name="shutter_background_color" format="color"/>
|
||||||
<attr name="default_artwork" format="reference"/>
|
<attr name="default_artwork" format="reference"/>
|
||||||
@ -52,7 +52,7 @@
|
|||||||
<attr name="resize_mode"/>
|
<attr name="resize_mode"/>
|
||||||
<attr name="surface_type"/>
|
<attr name="surface_type"/>
|
||||||
<attr name="player_layout_id"/>
|
<attr name="player_layout_id"/>
|
||||||
<!-- PlaybackControlView attrs -->
|
<!-- PlayerControlView attributes -->
|
||||||
<attr name="show_timeout"/>
|
<attr name="show_timeout"/>
|
||||||
<attr name="rewind_increment"/>
|
<attr name="rewind_increment"/>
|
||||||
<attr name="fastforward_increment"/>
|
<attr name="fastforward_increment"/>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<attr name="resize_mode"/>
|
<attr name="resize_mode"/>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="PlaybackControlView">
|
<declare-styleable name="PlayerControlView">
|
||||||
<attr name="show_timeout"/>
|
<attr name="show_timeout"/>
|
||||||
<attr name="rewind_increment"/>
|
<attr name="rewind_increment"/>
|
||||||
<attr name="fastforward_increment"/>
|
<attr name="fastforward_increment"/>
|
||||||
|
@ -32,6 +32,16 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|||||||
*/
|
*/
|
||||||
public abstract class StubExoPlayer implements ExoPlayer {
|
public abstract class StubExoPlayer implements ExoPlayer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VideoComponent getVideoComponent() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponent getTextComponent() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Looper getPlaybackLooper() {
|
public Looper getPlaybackLooper() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user