Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
65d8ff80
authored
May 19, 2021
by
christosts
Committed by
Oliver Woodman
May 19, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
ForwardingPlayer only forwards Player operations
PiperOrigin-RevId: 374621615
parent
41afb6ac
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
226 additions
and
662 deletions
library/common/src/main/java/com/google/android/exoplayer2/ForwardingPlayer.java
library/common/src/test/java/com/google/android/exoplayer2/ForwardingPlayerTest.java
library/common/src/main/java/com/google/android/exoplayer2/ForwardingPlayer.java
View file @
65d8ff80
/*
* Copyright
(C)
2021 The Android Open Source Project
* Copyright 2021 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.
...
...
@@ -15,74 +15,32 @@
*/
package
com
.
google
.
android
.
exoplayer2
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
android.os.Looper
;
import
android.view.Surface
;
import
android.view.SurfaceHolder
;
import
android.view.SurfaceView
;
import
android.view.TextureView
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.VisibleForTesting
;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.device.DeviceInfo
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.trackselection.TrackSelectionArray
;
import
com.google.android.exoplayer2.util.Clock
;
import
com.google.android.exoplayer2.util.ListenerSet
;
import
com.google.android.exoplayer2.video.VideoSize
;
import
java.util.List
;
/**
* A {@link Player} that forwards operations to another {@link Player}. Applications can use this
* class to suppress or modify specific operations, by overriding the respective methods.
*
* <p>An application can {@link #setDisabledCommands disable available commands}. When the wrapped
* player advertises available commands, either with {@link Player#isCommandAvailable(int)} or with
* {@link Listener#onAvailableCommandsChanged}, the disabled commands will be filtered out.
*/
public
class
ForwardingPlayer
implements
Player
{
private
final
Player
player
;
private
final
Clock
clock
;
@Nullable
private
ForwardingListener
forwardingListener
;
private
Commands
disabledCommands
;
@Nullable
private
Commands
unfilteredCommands
;
@Nullable
private
Commands
filteredCommands
;
private
final
Player
player
;
/** Creates a new instance that forwards all operations to {@code player}. */
public
ForwardingPlayer
(
Player
player
)
{
this
(
player
,
Clock
.
DEFAULT
);
}
@VisibleForTesting
/* package */
ForwardingPlayer
(
Player
player
,
Clock
clock
)
{
this
.
player
=
player
;
this
.
clock
=
clock
;
this
.
disabledCommands
=
Commands
.
EMPTY
;
}
/**
* Sets the disabled {@link Commands}.
*
* <p>When querying for available commands with {@link #isCommandAvailable(int)}, or when the
* wrapped player advertises available commands with {@link Listener#isCommandAvailable}, disabled
* commands will be filtered out.
*/
public
void
setDisabledCommands
(
Commands
commands
)
{
checkState
(
player
.
getApplicationLooper
().
equals
(
Looper
.
myLooper
()));
disabledCommands
=
commands
;
filteredCommands
=
null
;
if
(
forwardingListener
!=
null
)
{
forwardingListener
.
maybeAdvertiseAvailableCommands
();
}
}
/** Returns the disabled commands. */
public
Commands
getDisabledCommands
()
{
return
disabledCommands
;
}
@Override
...
...
@@ -91,35 +49,25 @@ public class ForwardingPlayer implements Player {
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Implementing deprecated method.
public
void
addListener
(
EventListener
listener
)
{
addListener
(
new
EventListenerWrapper
(
listener
));
player
.
addListener
(
new
ForwardingEventListener
(
this
,
listener
));
}
@Override
public
void
addListener
(
Listener
listener
)
{
if
(
forwardingListener
==
null
)
{
forwardingListener
=
new
ForwardingListener
(
this
);
}
if
(!
forwardingListener
.
isRegistered
())
{
forwardingListener
.
registerTo
(
player
);
}
forwardingListener
.
addListener
(
listener
);
player
.
addListener
(
new
ForwardingListener
(
this
,
listener
));
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Implementing deprecated method.
public
void
removeListener
(
EventListener
listener
)
{
removeListener
(
new
EventListenerWrapper
(
listener
));
player
.
removeListener
(
new
ForwardingEventListener
(
this
,
listener
));
}
@Override
public
void
removeListener
(
Listener
listener
)
{
if
(
forwardingListener
==
null
)
{
return
;
}
forwardingListener
.
removeListener
(
listener
);
if
(!
forwardingListener
.
hasListeners
())
{
forwardingListener
.
unregisterFrom
(
player
);
}
player
.
removeListener
(
new
ForwardingListener
(
this
,
listener
));
}
@Override
...
...
@@ -200,17 +148,12 @@ public class ForwardingPlayer implements Player {
@Override
public
boolean
isCommandAvailable
(
@Command
int
command
)
{
return
!
disabledCommands
.
contains
(
command
)
&&
player
.
isCommandAvailable
(
command
);
return
player
.
isCommandAvailable
(
command
);
}
@Override
public
Commands
getAvailableCommands
()
{
Commands
commands
=
player
.
getAvailableCommands
();
if
(
filteredCommands
==
null
||
!
commands
.
equals
(
unfilteredCommands
))
{
filteredCommands
=
filterCommands
(
commands
,
disabledCommands
);
unfilteredCommands
=
commands
;
}
return
filteredCommands
;
return
player
.
getAvailableCommands
();
}
@Override
...
...
@@ -602,456 +545,233 @@ public class ForwardingPlayer implements Player {
player
.
setDeviceMuted
(
muted
);
}
/**
* Wraps a {@link Listener} and intercepts {@link Listener#onAvailableCommandsChanged} in order to
* filter disabled commands. All other operations are forwarded to the wrapped {@link Listener}.
*/
private
static
class
ForwardingListener
implements
Listener
{
private
final
ForwardingPlayer
player
;
private
final
ListenerSet
<
Listener
>
listeners
;
private
boolean
registered
;
private
Commands
lastReceivedCommands
;
private
Commands
lastAdvertisedCommands
;
public
ForwardingListener
(
ForwardingPlayer
forwardingPlayer
)
{
this
.
player
=
forwardingPlayer
;
listeners
=
new
ListenerSet
<>(
forwardingPlayer
.
player
.
getApplicationLooper
(),
forwardingPlayer
.
clock
,
(
listener
,
flags
)
->
listener
.
onEvents
(
forwardingPlayer
,
new
Events
(
flags
)));
lastReceivedCommands
=
Commands
.
EMPTY
;
lastAdvertisedCommands
=
Commands
.
EMPTY
;
}
public
void
registerTo
(
Player
player
)
{
checkState
(!
registered
);
player
.
addListener
(
this
);
lastReceivedCommands
=
player
.
getAvailableCommands
();
lastAdvertisedCommands
=
lastReceivedCommands
;
registered
=
true
;
}
public
void
unregisterFrom
(
Player
player
)
{
checkState
(
registered
);
player
.
removeListener
(
this
);
registered
=
false
;
}
public
boolean
isRegistered
()
{
return
registered
;
}
public
void
addListener
(
Listener
listener
)
{
listeners
.
add
(
listener
);
}
public
void
removeListener
(
Listener
listener
)
{
listeners
.
remove
(
listener
);
}
public
boolean
hasListeners
()
{
return
listeners
.
size
()
>
0
;
}
// VideoListener callbacks
@Override
public
void
onVideoSizeChanged
(
VideoSize
videoSize
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onVideoSizeChanged
(
videoSize
));
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onVideoSizeChanged
(
int
width
,
int
height
,
int
unappliedRotationDegrees
,
float
pixelWidthHeightRatio
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onVideoSizeChanged
(
width
,
height
,
unappliedRotationDegrees
,
pixelWidthHeightRatio
));
}
@Override
public
void
onSurfaceSizeChanged
(
int
width
,
int
height
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onSurfaceSizeChanged
(
width
,
height
));
}
@Override
public
void
onRenderedFirstFrame
()
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
Listener:
:
onRenderedFirstFrame
);
}
// AudioListener callbacks
@SuppressWarnings
(
"deprecation"
)
// Use of deprecated type for backwards compatibility.
private
static
class
ForwardingEventListener
implements
EventListener
{
@Override
public
void
onAudioSessionIdChanged
(
int
audioSessionId
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onAudioSessionIdChanged
(
audioSessionId
));
}
@Override
public
void
onAudioAttributesChanged
(
AudioAttributes
audioAttributes
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onAudioAttributesChanged
(
audioAttributes
));
}
@Override
public
void
onVolumeChanged
(
float
volume
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onVolumeChanged
(
volume
));
}
@Override
public
void
onSkipSilenceEnabledChanged
(
boolean
skipSilenceEnabled
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onSkipSilenceEnabledChanged
(
skipSilenceEnabled
));
}
// TextOutput callbacks
@Override
public
void
onCues
(
List
<
Cue
>
cues
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onCues
(
cues
));
}
// MetadataOutput callbacks
@Override
public
void
onMetadata
(
Metadata
metadata
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onMetadata
(
metadata
));
}
// DeviceListener callbacks
@Override
public
void
onDeviceInfoChanged
(
DeviceInfo
deviceInfo
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onDeviceInfoChanged
(
deviceInfo
));
}
private
final
ForwardingPlayer
forwardingPlayer
;
private
final
EventListener
eventListener
;
@Override
public
void
onDeviceVolumeChanged
(
int
volume
,
boolean
muted
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onDeviceVolumeChanged
(
volume
,
muted
));
private
ForwardingEventListener
(
ForwardingPlayer
forwardingPlayer
,
EventListener
eventListener
)
{
this
.
forwardingPlayer
=
forwardingPlayer
;
this
.
eventListener
=
eventListener
;
}
// EventListener callbacks
@Override
public
void
onTimelineChanged
(
Timeline
timeline
,
@TimelineChangeReason
int
reason
)
{
listeners
.
sendEvent
(
EVENT_TIMELINE_CHANGED
,
listener
->
listener
.
onTimelineChanged
(
timeline
,
reason
));
eventListener
.
onTimelineChanged
(
timeline
,
reason
);
}
@Override
public
void
onMediaItemTransition
(
@Nullable
MediaItem
mediaItem
,
@MediaItemTransitionReason
int
reason
)
{
listeners
.
sendEvent
(
EVENT_MEDIA_ITEM_TRANSITION
,
listener
->
listener
.
onMediaItemTransition
(
mediaItem
,
reason
));
eventListener
.
onMediaItemTransition
(
mediaItem
,
reason
);
}
@Override
public
void
onTracksChanged
(
TrackGroupArray
trackGroups
,
TrackSelectionArray
trackSelections
)
{
listeners
.
sendEvent
(
EVENT_TRACKS_CHANGED
,
listener
->
listener
.
onTracksChanged
(
trackGroups
,
trackSelections
));
eventListener
.
onTracksChanged
(
trackGroups
,
trackSelections
);
}
@Override
public
void
onStaticMetadataChanged
(
List
<
Metadata
>
metadataList
)
{
listeners
.
sendEvent
(
EVENT_STATIC_METADATA_CHANGED
,
listener
->
listener
.
onStaticMetadataChanged
(
metadataList
));
eventListener
.
onStaticMetadataChanged
(
metadataList
);
}
@Override
public
void
onMediaMetadataChanged
(
MediaMetadata
mediaMetadata
)
{
listeners
.
sendEvent
(
EVENT_MEDIA_METADATA_CHANGED
,
listener
->
listener
.
onMediaMetadataChanged
(
mediaMetadata
));
eventListener
.
onMediaMetadataChanged
(
mediaMetadata
);
}
@Override
public
void
onIsLoadingChanged
(
boolean
isLoading
)
{
listeners
.
sendEvent
(
EVENT_IS_LOADING_CHANGED
,
listener
->
listener
.
onIsLoadingChanged
(
isLoading
));
eventListener
.
onIsLoadingChanged
(
isLoading
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onLoadingChanged
(
boolean
isLoading
)
{
listeners
.
sendEvent
(
EVENT_IS_LOADING_CHANGED
,
listener
->
listener
.
onLoadingChanged
(
isLoading
));
eventListener
.
onIsLoadingChanged
(
isLoading
);
}
@Override
public
void
onAvailableCommandsChanged
(
Commands
availableCommands
)
{
lastReceivedCommands
=
availableCommands
;
maybeAdvertiseAvailableCommands
();
eventListener
.
onAvailableCommandsChanged
(
availableCommands
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onPlayerStateChanged
(
boolean
playWhenReady
,
@State
int
playbackState
)
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
listener
->
listener
.
onPlayerStateChanged
(
playWhenReady
,
playbackState
));
eventListener
.
onPlayerStateChanged
(
playWhenReady
,
playbackState
);
}
@Override
public
void
onPlaybackStateChanged
(
@State
int
state
)
{
listeners
.
sendEvent
(
EVENT_PLAYBACK_STATE_CHANGED
,
listener
->
listener
.
onPlaybackStateChanged
(
state
));
eventListener
.
onPlaybackStateChanged
(
state
);
}
@Override
public
void
onPlayWhenReadyChanged
(
boolean
playWhenReady
,
@State
int
reason
)
{
listeners
.
sendEvent
(
EVENT_PLAY_WHEN_READY_CHANGED
,
listener
->
listener
.
onPlayWhenReadyChanged
(
playWhenReady
,
reason
));
public
void
onPlayWhenReadyChanged
(
boolean
playWhenReady
,
@PlayWhenReadyChangeReason
int
reason
)
{
eventListener
.
onPlayWhenReadyChanged
(
playWhenReady
,
reason
);
}
@Override
public
void
onPlaybackSuppressionReasonChanged
(
@PlaybackSuppressionReason
int
playbackSuppressionReason
)
{
listeners
.
sendEvent
(
EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED
,
listener
->
listener
.
onPlaybackSuppressionReasonChanged
(
playbackSuppressionReason
));
@PlayWhenReadyChangeReason
int
playbackSuppressionReason
)
{
eventListener
.
onPlaybackStateChanged
(
playbackSuppressionReason
);
}
@Override
public
void
onIsPlayingChanged
(
boolean
isPlaying
)
{
listeners
.
sendEvent
(
EVENT_IS_PLAYING_CHANGED
,
listener
->
listener
.
onIsPlayingChanged
(
isPlaying
));
eventListener
.
onIsPlayingChanged
(
isPlaying
);
}
@Override
public
void
onRepeatModeChanged
(
@RepeatMode
int
repeatMode
)
{
listeners
.
sendEvent
(
EVENT_REPEAT_MODE_CHANGED
,
listener
->
listener
.
onRepeatModeChanged
(
repeatMode
));
eventListener
.
onRepeatModeChanged
(
repeatMode
);
}
@Override
public
void
onShuffleModeEnabledChanged
(
boolean
shuffleModeEnabled
)
{
listeners
.
sendEvent
(
EVENT_SHUFFLE_MODE_ENABLED_CHANGED
,
listener
->
listener
.
onShuffleModeEnabledChanged
(
shuffleModeEnabled
));
eventListener
.
onShuffleModeEnabledChanged
(
shuffleModeEnabled
);
}
@Override
public
void
onPlayerError
(
ExoPlaybackException
error
)
{
listeners
.
sendEvent
(
EVENT_PLAYER_ERROR
,
listener
->
listener
.
onPlayerError
(
error
)
);
eventListener
.
onPlayerError
(
error
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onPositionDiscontinuity
(
@DiscontinuityReason
int
reason
)
{
listeners
.
sendEvent
(
EVENT_POSITION_DISCONTINUITY
,
listener
->
listener
.
onPositionDiscontinuity
(
reason
));
eventListener
.
onPositionDiscontinuity
(
reason
);
}
@Override
public
void
onPositionDiscontinuity
(
PositionInfo
oldPosition
,
PositionInfo
newPosition
,
@DiscontinuityReason
int
reason
)
{
listeners
.
sendEvent
(
EVENT_POSITION_DISCONTINUITY
,
listener
->
listener
.
onPositionDiscontinuity
(
oldPosition
,
newPosition
,
reason
));
eventListener
.
onPositionDiscontinuity
(
oldPosition
,
newPosition
,
reason
);
}
@Override
public
void
onPlaybackParametersChanged
(
PlaybackParameters
playbackParameters
)
{
listeners
.
sendEvent
(
EVENT_PLAYBACK_PARAMETERS_CHANGED
,
listener
->
listener
.
onPlaybackParametersChanged
(
playbackParameters
));
eventListener
.
onPlaybackParametersChanged
(
playbackParameters
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onSeekProcessed
()
{
listeners
.
sendEvent
(
C
.
INDEX_UNSET
,
EventListener:
:
onSeekProcessed
);
eventListener
.
onSeekProcessed
(
);
}
@Override
public
void
onEvents
(
Player
player
,
Events
events
)
{
//
Do nothing, individual callbacks will trigger this event on behalf of the forwarding
// player.
//
Replace player with forwarding player.
eventListener
.
onEvents
(
forwardingPlayer
,
events
);
}
public
void
maybeAdvertiseAvailableCommands
()
{
Commands
commandsToAdvertise
=
filterCommands
(
lastReceivedCommands
,
player
.
disabledCommands
);
if
(
!
commandsToAdvertise
.
equals
(
lastAdvertisedCommands
)
)
{
lastAdvertisedCommands
=
commandsToAdvertis
e
;
listeners
.
sendEvent
(
EVENT_AVAILABLE_COMMANDS_CHANGED
,
listener
->
listener
.
onAvailableCommandsChanged
(
commandsToAdvertise
))
;
@Override
public
boolean
equals
(
@Nullable
Object
o
)
{
if
(
this
==
o
)
{
return
tru
e
;
}
if
(!(
o
instanceof
ForwardingEventListener
))
{
return
false
;
}
}
}
/**
* Wraps an {@link EventListener} as a {@link Listener} so that it can be used by the {@link
* ForwardingListener}.
*/
private
static
class
EventListenerWrapper
implements
Listener
{
private
final
EventListener
listener
;
/** Wraps an {@link EventListener}. */
public
EventListenerWrapper
(
EventListener
listener
)
{
this
.
listener
=
listener
;
}
// EventListener callbacks
@Override
public
void
onTimelineChanged
(
Timeline
timeline
,
@TimelineChangeReason
int
reason
)
{
listener
.
onTimelineChanged
(
timeline
,
reason
);
}
ForwardingEventListener
that
=
(
ForwardingEventListener
)
o
;
@Override
public
void
onMediaItemTransition
(
@Nullable
MediaItem
mediaItem
,
@MediaItemTransitionReason
int
reason
)
{
listener
.
onMediaItemTransition
(
mediaItem
,
reason
);
if
(!
forwardingPlayer
.
equals
(
that
.
forwardingPlayer
))
{
return
false
;
}
return
eventListener
.
equals
(
that
.
eventListener
);
}
@Override
public
void
onTracksChanged
(
TrackGroupArray
trackGroups
,
TrackSelectionArray
trackSelections
)
{
listener
.
onTracksChanged
(
trackGroups
,
trackSelections
);
public
int
hashCode
()
{
int
result
=
forwardingPlayer
.
hashCode
();
result
=
31
*
result
+
eventListener
.
hashCode
();
return
result
;
}
}
@Override
public
void
onStaticMetadataChanged
(
List
<
Metadata
>
metadataList
)
{
listener
.
onStaticMetadataChanged
(
metadataList
);
}
private
static
final
class
ForwardingListener
extends
ForwardingEventListener
implements
Listener
{
@Override
public
void
onMediaMetadataChanged
(
MediaMetadata
mediaMetadata
)
{
listener
.
onMediaMetadataChanged
(
mediaMetadata
);
}
private
final
Listener
listener
;
@Override
public
void
onIsLoadingChanged
(
boolean
isLoading
)
{
listener
.
onIsLoadingChanged
(
isLoading
)
;
public
ForwardingListener
(
ForwardingPlayer
forwardingPlayer
,
Listener
listener
)
{
super
(
forwardingPlayer
,
listener
);
this
.
listener
=
listener
;
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onLoadingChanged
(
boolean
isLoading
)
{
listener
.
onLoadingChanged
(
isLoading
);
}
// VideoListener methods.
@Override
public
void
on
AvailableCommandsChanged
(
Commands
availableCommands
)
{
listener
.
on
AvailableCommandsChanged
(
availableCommands
);
public
void
on
VideoSizeChanged
(
VideoSize
videoSize
)
{
listener
.
on
VideoSizeChanged
(
videoSize
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onPlayerStateChanged
(
boolean
playWhenReady
,
@State
int
playbackState
)
{
listener
.
onPlayerStateChanged
(
playWhenReady
,
playbackState
);
}
@Override
public
void
onPlaybackStateChanged
(
@State
int
state
)
{
listener
.
onPlaybackStateChanged
(
state
);
}
@Override
public
void
onPlayWhenReadyChanged
(
boolean
playWhenReady
,
@PlayWhenReadyChangeReason
int
reason
)
{
listener
.
onPlayWhenReadyChanged
(
playWhenReady
,
reason
);
}
@Override
public
void
onPlaybackSuppressionReasonChanged
(
@PlaybackSuppressionReason
int
playbackSuppressionReason
)
{
listener
.
onPlaybackSuppressionReasonChanged
(
playbackSuppressionReason
);
public
void
onVideoSizeChanged
(
int
width
,
int
height
,
int
unappliedRotationDegrees
,
float
pixelWidthHeightRatio
)
{
listener
.
onVideoSizeChanged
(
width
,
height
,
unappliedRotationDegrees
,
pixelWidthHeightRatio
);
}
@Override
public
void
on
IsPlayingChanged
(
boolean
isPlaying
)
{
listener
.
on
IsPlayingChanged
(
isPlaying
);
public
void
on
SurfaceSizeChanged
(
int
width
,
int
height
)
{
listener
.
on
SurfaceSizeChanged
(
width
,
height
);
}
@Override
public
void
onRe
peatModeChanged
(
@RepeatMode
int
repeatMode
)
{
listener
.
onRe
peatModeChanged
(
repeatMode
);
public
void
onRe
nderedFirstFrame
(
)
{
listener
.
onRe
nderedFirstFrame
(
);
}
@Override
public
void
onShuffleModeEnabledChanged
(
boolean
shuffleModeEnabled
)
{
listener
.
onShuffleModeEnabledChanged
(
shuffleModeEnabled
);
}
// AudioListener methods
@Override
public
void
on
PlayerError
(
ExoPlaybackException
error
)
{
listener
.
on
PlayerError
(
error
);
public
void
on
AudioSessionIdChanged
(
int
audioSessionId
)
{
listener
.
on
AudioSessionIdChanged
(
audioSessionId
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onPositionDiscontinuity
(
@DiscontinuityReason
int
reason
)
{
listener
.
onPositionDiscontinuity
(
reason
);
public
void
onAudioAttributesChanged
(
AudioAttributes
audioAttributes
)
{
listener
.
onAudioAttributesChanged
(
audioAttributes
);
}
@Override
public
void
onPositionDiscontinuity
(
PositionInfo
oldPosition
,
PositionInfo
newPosition
,
@DiscontinuityReason
int
reason
)
{
listener
.
onPositionDiscontinuity
(
oldPosition
,
newPosition
,
reason
);
public
void
onVolumeChanged
(
float
volume
)
{
listener
.
onVolumeChanged
(
volume
);
}
@Override
public
void
on
PlaybackParametersChanged
(
PlaybackParameters
playbackParameters
)
{
listener
.
on
PlaybackParametersChanged
(
playbackParameters
);
public
void
on
SkipSilenceEnabledChanged
(
boolean
skipSilenceEnabled
)
{
listener
.
on
SkipSilenceEnabledChanged
(
skipSilenceEnabled
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Forwarding to deprecated method.
public
void
onSeekProcessed
()
{
listener
.
onSeekProcessed
();
}
// TextOutput methods.
@Override
public
void
on
Events
(
Player
player
,
Events
event
s
)
{
listener
.
on
Events
(
player
,
event
s
);
public
void
on
Cues
(
List
<
Cue
>
cue
s
)
{
listener
.
on
Cues
(
cue
s
);
}
//
Other Listener callbacks, they should never be invoked on this wrapper
.
//
MetadataOutput methods
.
@Override
public
void
onMetadata
(
Metadata
metadata
)
{
throw
new
IllegalStateException
(
);
listener
.
onMetadata
(
metadata
);
}
@Override
public
void
onCues
(
List
<
Cue
>
cues
)
{
throw
new
IllegalStateException
();
}
// DeviceListener callbacks
@Override
public
boolean
equals
(
@Nullable
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(!(
o
instanceof
EventListenerWrapper
))
{
return
false
;
}
EventListenerWrapper
that
=
(
EventListenerWrapper
)
o
;
return
listener
.
equals
(
that
.
listener
);
public
void
onDeviceInfoChanged
(
DeviceInfo
deviceInfo
)
{
listener
.
onDeviceInfoChanged
(
deviceInfo
);
}
@Override
public
int
hashCode
()
{
return
listener
.
hashCode
();
}
}
/** Returns the remaining available commands after removing disabled commands. */
private
static
Commands
filterCommands
(
Commands
availableCommands
,
Commands
disabledCommands
)
{
if
(
disabledCommands
.
size
()
==
0
)
{
return
availableCommands
;
}
Commands
.
Builder
builder
=
new
Commands
.
Builder
();
for
(
int
i
=
0
;
i
<
availableCommands
.
size
();
i
++)
{
int
command
=
availableCommands
.
get
(
i
);
builder
.
addIf
(
command
,
!
disabledCommands
.
contains
(
command
));
public
void
onDeviceVolumeChanged
(
int
volume
,
boolean
muted
)
{
listener
.
onDeviceVolumeChanged
(
volume
,
muted
);
}
return
builder
.
build
();
}
}
library/common/src/test/java/com/google/android/exoplayer2/ForwardingPlayerTest.java
View file @
65d8ff80
/*
* Copyright
(C)
2021 The Android Open Source Project
* Copyright 2021 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.
...
...
@@ -15,26 +15,18 @@
*/
package
com
.
google
.
android
.
exoplayer2
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
COMMAND_PLAY_PAUSE
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
COMMAND_PREPARE_STOP
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
COMMAND_SEEK_TO_MEDIA_ITEM
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
EVENT_AVAILABLE_COMMANDS_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
EVENT_PLAYBACK_STATE_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
STATE_READY
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
EVENT_IS_PLAYING_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
EVENT_MEDIA_ITEM_TRANSITION
;
import
static
com
.
google
.
android
.
exoplayer2
.
Player
.
EVENT_TIMELINE_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
argThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
same
;
import
static
org
.
mockito
.
Mockito
.
inOrder
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
spy
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
verifyNoMoreInteractions
;
import
android.os.Looper
;
import
androidx.annotation.Nullable
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.testutil.StubExoPlayer
;
import
com.google.android.exoplayer2.util.ExoFlags
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Modifier
;
import
java.util.ArrayDeque
;
...
...
@@ -46,220 +38,112 @@ import java.util.Queue;
import
java.util.Set
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.mockito.ArgumentMatcher
;
import
org.mockito.InOrder
;
import
org.robolectric.shadows.ShadowLooper
;
import
org.mockito.ArgumentCaptor
;
/** Unit test for {@link ForwardingPlayer}. */
/** Unit test
s
for {@link ForwardingPlayer}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
class
ForwardingPlayerTest
{
@Test
public
void
getAvailableCommands_withDisabledCommands_filtersDisabledCommands
()
{
Player
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_PREPARE_STOP
));
assertThat
(
forwardingPlayer
.
getAvailableCommands
())
.
isEqualTo
(
buildCommands
(
COMMAND_PLAY_PAUSE
));
}
@Test
public
void
getAvailableCommands_playerAvailableCommandsChanged_returnsFreshCommands
()
{
FakePlayer
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_PREPARE_STOP
));
assertThat
(
forwardingPlayer
.
getAvailableCommands
())
.
isEqualTo
(
buildCommands
(
COMMAND_PLAY_PAUSE
));
player
.
setAvailableCommands
(
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
,
COMMAND_SEEK_TO_MEDIA_ITEM
));
assertThat
(
forwardingPlayer
.
getAvailableCommands
())
.
isEqualTo
(
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_SEEK_TO_MEDIA_ITEM
));
}
@Test
public
void
isCommandAvailable_withDisabledCommands_filtersDisabledCommands
()
{
Player
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_PREPARE_STOP
));
assertThat
(
forwardingPlayer
.
isCommandAvailable
(
COMMAND_PLAY_PAUSE
)).
isTrue
();
assertThat
(
forwardingPlayer
.
isCommandAvailable
(
COMMAND_PREPARE_STOP
)).
isFalse
();
}
@Test
public
void
setDisabledCommands_triggersOnCommandsAvailableChanged
()
{
Player
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
Player
.
Listener
listener
=
mock
(
Player
.
Listener
.
class
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
addListener
(
listener
);
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_PREPARE_STOP
));
ShadowLooper
.
idleMainLooper
();
InOrder
inOrder
=
inOrder
(
listener
);
inOrder
.
verify
(
listener
).
onAvailableCommandsChanged
(
buildCommands
(
COMMAND_PLAY_PAUSE
));
inOrder
.
verify
(
listener
)
.
onEvents
(
same
(
forwardingPlayer
),
argThat
(
new
EventsMatcher
(
EVENT_AVAILABLE_COMMANDS_CHANGED
)));
inOrder
.
verifyNoMoreInteractions
();
}
public
void
addListener_addsForwardingListener
()
{
FakePlayer
player
=
new
FakePlayer
();
Player
.
Listener
listener1
=
mock
(
Player
.
Listener
.
class
);
Player
.
Listener
listener2
=
mock
(
Player
.
Listener
.
class
);
@Test
public
void
setDisabledCommands_withoutChangingAvailableCommands_noCallbackTriggered
()
{
Player
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
Player
.
Listener
listener
=
mock
(
Player
.
Listener
.
class
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
addListener
(
listener
);
forwardingPlayer
.
addListener
(
listener1
);
// Add listener1 again.
forwardingPlayer
.
addListener
(
listener1
);
forwardingPlayer
.
addListener
(
listener2
);
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_SEEK_TO_MEDIA_ITEM
));
ShadowLooper
.
idleMainLooper
();
verifyNoMoreInteractions
(
listener
);
assertThat
(
player
.
listeners
).
hasSize
(
2
);
}
@Test
public
void
setDisabledCommands_multipleTimes_availableCommandsUpdated
()
{
Player
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_SEEK_TO_MEDIA_ITEM
));
assertThat
(
forwardingPlayer
.
getAvailableCommands
())
.
isEqualTo
(
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
));
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_PREPARE_STOP
,
COMMAND_SEEK_TO_MEDIA_ITEM
));
assertThat
(
forwardingPlayer
.
getAvailableCommands
())
.
isEqualTo
(
buildCommands
(
COMMAND_PLAY_PAUSE
));
}
@SuppressWarnings
(
"deprecation"
)
// Testing backwards compatibility with deprecated method.
public
void
addEventListener_addsForwardingListener
()
{
FakePlayer
player
=
new
FakePlayer
();
Player
.
EventListener
listener1
=
mock
(
Player
.
EventListener
.
class
);
Player
.
EventListener
listener2
=
mock
(
Player
.
EventListener
.
class
);
@Test
public
void
onCommandsAvailableChanged_listenerChangesCommandsRecursively_secondCallbackCalled
()
{
FakePlayer
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
Player
.
Listener
listener
=
spy
(
new
Player
.
Listener
()
{
@Override
public
void
onAvailableCommandsChanged
(
Player
.
Commands
availableCommands
)
{
// The callback changes the forwarding player's disabled commands triggering
// exactly one more callback.
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_PREPARE_STOP
));
}
});
forwardingPlayer
.
addListener
(
listener
);
Player
.
Commands
updatedCommands
=
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
,
COMMAND_SEEK_TO_MEDIA_ITEM
);
player
.
setAvailableCommands
(
updatedCommands
);
player
.
forwardingListener
.
onAvailableCommandsChanged
(
updatedCommands
);
ShadowLooper
.
idleMainLooper
();
forwardingPlayer
.
addListener
(
listener1
);
// Add listener1 again.
forwardingPlayer
.
addListener
(
listener1
);
forwardingPlayer
.
addListener
(
listener2
);
InOrder
inOrder
=
inOrder
(
listener
);
inOrder
.
verify
(
listener
)
.
onAvailableCommandsChanged
(
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
,
COMMAND_SEEK_TO_MEDIA_ITEM
));
inOrder
.
verify
(
listener
)
.
onAvailableCommandsChanged
(
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_SEEK_TO_MEDIA_ITEM
));
inOrder
.
verify
(
listener
)
.
onEvents
(
same
(
forwardingPlayer
),
argThat
(
new
EventsMatcher
(
EVENT_AVAILABLE_COMMANDS_CHANGED
)));
inOrder
.
verifyNoMoreInteractions
();
assertThat
(
player
.
eventListeners
).
hasSize
(
2
);
}
@Test
public
void
interceptingOnAvailableCommandsChanged_withDisabledCommands_filtersDisabledCommands
()
{
public
void
removeListener_removesForwardingListener
()
{
FakePlayer
player
=
new
FakePlayer
();
Player
.
Listener
listener
=
mock
(
Player
.
Listener
.
class
);
Player
.
Listener
listener1
=
mock
(
Player
.
Listener
.
class
);
Player
.
Listener
listener2
=
mock
(
Player
.
Listener
.
class
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
addListener
(
listener
);
forwardingPlayer
.
addListener
(
listener1
);
forwardingPlayer
.
addListener
(
listener2
);
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_PREPARE_STOP
));
ShadowLooper
.
idleMainLooper
();
// Setting the disabled commands did not affect the available commands, hence no callback was
// triggered.
verifyNoMoreInteractions
(
listener
);
// The wrapped player advertises new available commands.
Player
.
Commands
updatedCommands
=
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
player
.
setAvailableCommands
(
updatedCommands
);
player
.
forwardingListener
.
onAvailableCommandsChanged
(
updatedCommands
);
ShadowLooper
.
idleMainLooper
();
verify
(
listener
).
onAvailableCommandsChanged
(
buildCommands
(
COMMAND_PLAY_PAUSE
));
verify
(
listener
)
.
onEvents
(
same
(
forwardingPlayer
),
argThat
(
new
EventsMatcher
(
EVENT_AVAILABLE_COMMANDS_CHANGED
)));
verifyNoMoreInteractions
(
listener
);
forwardingPlayer
.
removeListener
(
listener1
);
assertThat
(
player
.
listeners
).
hasSize
(
1
);
// Remove same listener again.
forwardingPlayer
.
removeListener
(
listener1
);
assertThat
(
player
.
listeners
).
hasSize
(
1
);
forwardingPlayer
.
removeListener
(
listener2
);
assertThat
(
player
.
listeners
).
isEmpty
();
}
@Test
public
void
interceptingOnAvailableCommandsChanged_withDisabledCommandsButAvailableCommandsNotChanged_doesNotForwardCallback
()
{
FakePlayer
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
Player
.
Listener
listener
=
mock
(
Player
.
Listener
.
class
);
@SuppressWarnings
(
"deprecation"
)
// Testing backwards compatibility with deprecated method.
public
void
removeEventListener_removesForwardingListener
()
{
FakePlayer
player
=
new
FakePlayer
();
Player
.
EventListener
listener1
=
mock
(
Player
.
EventListener
.
class
);
Player
.
EventListener
listener2
=
mock
(
Player
.
EventListener
.
class
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
addListener
(
listener
);
forwardingPlayer
.
addListener
(
listener1
);
forwardingPlayer
.
addListener
(
listener2
);
// Disable commands that do not affect the available commands.
forwardingPlayer
.
setDisabledCommands
(
buildCommands
(
COMMAND_SEEK_TO_MEDIA_ITEM
));
ShadowLooper
.
idleMainLooper
();
verifyNoMoreInteractions
(
listener
);
// The wrapped player advertises new available commands which, after filtering the disabled
// commands, do not change the available commands.
Player
.
Commands
updatedCommands
=
buildCommands
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
,
COMMAND_SEEK_TO_MEDIA_ITEM
);
player
.
setAvailableCommands
(
updatedCommands
);
player
.
forwardingListener
.
onAvailableCommandsChanged
(
updatedCommands
);
ShadowLooper
.
idleMainLooper
();
verifyNoMoreInteractions
(
listener
);
forwardingPlayer
.
removeListener
(
listener1
);
assertThat
(
player
.
eventListeners
).
hasSize
(
1
);
// Remove same listener again.
forwardingPlayer
.
removeListener
(
listener1
);
assertThat
(
player
.
eventListeners
).
hasSize
(
1
);
forwardingPlayer
.
removeListener
(
listener2
);
assertThat
(
player
.
eventListeners
).
isEmpty
();
}
@Test
public
void
removeListener_removesListenerFromPlayer
()
{
FakePlayer
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
public
void
onEvents_passesForwardingPlayerAsArgument
()
{
FakePlayer
player
=
new
FakePlayer
();
Player
.
Listener
listener
=
mock
(
Player
.
Listener
.
class
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
addListener
(
listener
);
assertThat
(
player
.
forwardingListener
).
isNotNull
();
forwardingPlayer
.
removeListener
(
listener
);
assertThat
(
player
.
forwardingListener
).
isNull
();
}
@Test
public
void
addEventListener_forwardsEventListenerEvents
()
{
FakePlayer
player
=
new
FakePlayer
(
COMMAND_PLAY_PAUSE
,
COMMAND_PREPARE_STOP
);
Player
.
EventListener
eventListener
=
mock
(
Player
.
EventListener
.
class
);
ForwardingPlayer
forwardingPlayer
=
new
ForwardingPlayer
(
player
);
forwardingPlayer
.
addListener
(
eventListener
);
player
.
forwardingListener
.
onPlaybackStateChanged
(
STATE_READY
);
ShadowLooper
.
idleMainLooper
();
InOrder
inOrder
=
inOrder
(
eventListener
);
inOrder
.
verify
(
eventListener
).
onPlaybackStateChanged
(
STATE_READY
);
inOrder
.
verify
(
eventListener
)
.
onEvents
(
same
(
forwardingPlayer
),
argThat
(
new
EventsMatcher
(
EVENT_PLAYBACK_STATE_CHANGED
)));
inOrder
.
verifyNoMoreInteractions
();
Player
.
Listener
forwardingListener
=
player
.
listeners
.
iterator
().
next
();
forwardingListener
.
onEvents
(
player
,
new
Player
.
Events
(
new
ExoFlags
.
Builder
()
.
addAll
(
EVENT_TIMELINE_CHANGED
,
EVENT_MEDIA_ITEM_TRANSITION
,
EVENT_IS_PLAYING_CHANGED
)
.
build
()));
ArgumentCaptor
<
Player
.
Events
>
eventsArgumentCaptor
=
ArgumentCaptor
.
forClass
(
Player
.
Events
.
class
);
verify
(
listener
).
onEvents
(
same
(
forwardingPlayer
),
eventsArgumentCaptor
.
capture
());
Player
.
Events
receivedEvents
=
eventsArgumentCaptor
.
getValue
();
assertThat
(
receivedEvents
.
size
()).
isEqualTo
(
3
);
assertThat
(
receivedEvents
.
contains
(
EVENT_TIMELINE_CHANGED
)).
isTrue
();
assertThat
(
receivedEvents
.
contains
(
EVENT_MEDIA_ITEM_TRANSITION
)).
isTrue
();
assertThat
(
receivedEvents
.
contains
(
EVENT_IS_PLAYING_CHANGED
)).
isTrue
();
}
@Test
public
void
forwardingPlayer_overridesAllPlayerMethods
()
throws
Exception
{
// Check with reflection that ForwardingPlayer overrides all Player methods.
List
<
Method
>
playerM
ethods
=
getPublicMethods
(
Player
.
class
);
for
(
int
i
=
0
;
i
<
playerM
ethods
.
size
();
i
++)
{
Method
method
=
playerM
ethods
.
get
(
i
);
List
<
Method
>
m
ethods
=
getPublicMethods
(
Player
.
class
);
for
(
int
i
=
0
;
i
<
m
ethods
.
size
();
i
++)
{
Method
method
=
m
ethods
.
get
(
i
);
assertThat
(
ForwardingPlayer
.
class
.
getDeclaredMethod
(
method
.
getName
(),
method
.
getParameterTypes
()))
...
...
@@ -268,13 +152,13 @@ public class ForwardingPlayerTest {
}
@Test
public
void
forwardingListener_overridesAllListenerMethods
()
throws
Exception
{
// Check with reflection that ForwardingListener in ForwardingPlayer overrides all Listener
// methods.
Class
<?>
forwardingListenerClass
=
get
NestedClass
(
"Forwarding
Listener"
);
List
<
Method
>
publicListenerMethods
=
getPublicMethods
(
Player
.
Listener
.
class
);
for
(
int
i
=
0
;
i
<
publicListenerM
ethods
.
size
();
i
++)
{
Method
method
=
publicListenerM
ethods
.
get
(
i
);
@SuppressWarnings
(
"deprecation"
)
// Testing backwards compatibility with deprecated type.
public
void
forwardingEventListener_overridesAllEventListenerMethods
()
throws
Exception
{
//
Check with reflection that ForwardingListener overrides all Listener
methods.
Class
<?>
forwardingListenerClass
=
get
InnerClass
(
"ForwardingEvent
Listener"
);
List
<
Method
>
methods
=
getPublicMethods
(
Player
.
Event
Listener
.
class
);
for
(
int
i
=
0
;
i
<
m
ethods
.
size
();
i
++)
{
Method
method
=
m
ethods
.
get
(
i
);
assertThat
(
forwardingListenerClass
.
getDeclaredMethod
(
method
.
getName
(),
method
.
getParameterTypes
()))
...
...
@@ -283,99 +167,20 @@ public class ForwardingPlayerTest {
}
@Test
public
void
eventListenerWrapper_overridesAllEventListenerMethods
()
throws
Exception
{
// Check with reflection that EventListenerWrapper in ForwardingPlayer overrides all
// EventListener methods.
Class
<?>
listenerWrapperClass
=
getNestedClass
(
"EventListenerWrapper"
);
List
<
Method
>
publicListenerMethods
=
getPublicMethods
(
Player
.
EventListener
.
class
);
for
(
int
i
=
0
;
i
<
publicListenerMethods
.
size
();
i
++)
{
Method
method
=
publicListenerMethods
.
get
(
i
);
assertThat
(
listenerWrapperClass
.
getDeclaredMethod
(
method
.
getName
(),
method
.
getParameterTypes
()))
public
void
forwardingListener_overridesAllListenerMethods
()
throws
Exception
{
// Check with reflection that ForwardingListener overrides all Listener methods.
Class
<?>
forwardingListenerClass
=
getInnerClass
(
"ForwardingListener"
);
List
<
Method
>
methods
=
getPublicMethods
(
Player
.
Listener
.
class
);
for
(
int
i
=
0
;
i
<
methods
.
size
();
i
++)
{
Method
method
=
methods
.
get
(
i
);
assertThat
(
forwardingListenerClass
.
getMethod
(
method
.
getName
(),
method
.
getParameterTypes
()))
.
isNotNull
();
}
}
private
static
class
FakePlayer
extends
StubExoPlayer
{
private
Commands
availableCommands
;
/**
* Supports up to 1 registered listener, named deliberately forwardingListener to emphasize its
* purpose.
*/
@Nullable
private
Listener
forwardingListener
;
public
FakePlayer
()
{
this
.
availableCommands
=
Commands
.
EMPTY
;
}
public
FakePlayer
(
@Command
int
...
commands
)
{
this
.
availableCommands
=
new
Commands
.
Builder
().
addAll
(
commands
).
build
();
}
@Override
public
void
addListener
(
Listener
listener
)
{
checkState
(
this
.
forwardingListener
==
null
);
this
.
forwardingListener
=
listener
;
}
@Override
public
void
removeListener
(
Listener
listener
)
{
checkState
(
this
.
forwardingListener
.
equals
(
listener
));
this
.
forwardingListener
=
null
;
}
@Override
public
Commands
getAvailableCommands
()
{
return
availableCommands
;
}
@Override
public
Looper
getApplicationLooper
()
{
return
Looper
.
getMainLooper
();
}
public
void
setAvailableCommands
(
Commands
availableCommands
)
{
this
.
availableCommands
=
availableCommands
;
}
}
private
static
Player
.
Commands
buildCommands
(
@Player
.
Command
int
...
commands
)
{
return
new
Player
.
Commands
.
Builder
().
addAll
(
commands
).
build
();
}
private
Class
<?>
getNestedClass
(
String
className
)
{
for
(
Class
<?>
declaredClass
:
ForwardingPlayer
.
class
.
getDeclaredClasses
())
{
if
(
declaredClass
.
getSimpleName
().
equals
(
className
))
{
return
declaredClass
;
}
}
throw
new
IllegalStateException
();
}
private
static
class
EventsMatcher
implements
ArgumentMatcher
<
Player
.
Events
>
{
private
final
int
[]
events
;
private
EventsMatcher
(
int
...
events
)
{
this
.
events
=
events
;
}
@Override
public
boolean
matches
(
Player
.
Events
argument
)
{
if
(
events
.
length
!=
argument
.
size
())
{
return
false
;
}
for
(
int
event
:
events
)
{
if
(!
argument
.
contains
(
event
))
{
return
false
;
}
}
return
true
;
}
}
/** Returns all the methods of Java interface. */
/** Returns all the public methods of a Java interface. */
private
static
List
<
Method
>
getPublicMethods
(
Class
<?>
anInterface
)
{
assertThat
(
anInterface
.
isInterface
()).
isTrue
(
);
checkArgument
(
anInterface
.
isInterface
()
);
// Run a BFS over all extended interfaces to inspect them all.
Queue
<
Class
<?>>
interfacesQueue
=
new
ArrayDeque
<>();
interfacesQueue
.
add
(
anInterface
);
...
...
@@ -398,4 +203,43 @@ public class ForwardingPlayerTest {
return
list
;
}
private
static
Class
<?>
getInnerClass
(
String
className
)
{
for
(
Class
<?>
innerClass
:
ForwardingPlayer
.
class
.
getDeclaredClasses
())
{
if
(
innerClass
.
getSimpleName
().
equals
(
className
))
{
return
innerClass
;
}
}
throw
new
IllegalStateException
();
}
private
static
class
FakePlayer
extends
StubExoPlayer
{
@SuppressWarnings
(
"deprecation"
)
// Use of deprecated type for backwards compatibility.
private
final
Set
<
EventListener
>
eventListeners
=
new
HashSet
<>();
private
final
Set
<
Listener
>
listeners
=
new
HashSet
<>();
@Override
@SuppressWarnings
(
"deprecation"
)
// Implementing deprecated method.
public
void
addListener
(
EventListener
listener
)
{
eventListeners
.
add
(
listener
);
}
@Override
public
void
addListener
(
Listener
listener
)
{
listeners
.
add
(
listener
);
}
@Override
@SuppressWarnings
(
"deprecation"
)
// Implementing deprecated method.
public
void
removeListener
(
EventListener
listener
)
{
eventListeners
.
remove
(
listener
);
}
@Override
public
void
removeListener
(
Listener
listener
)
{
listeners
.
remove
(
listener
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment