@Implements(android.media.MediaPlayer.class) public class ShadowMediaPlayer extends ShadowPlayerBase
MediaPlayer
with Robolectric.
This shadow implementation provides much of the functionality needed to emulate MediaPlayer
initialization and playback behavior without having to play actual media files. A
summary of the features included are:
ShadowMediaPlayer.CreateListener
so that newly-created MediaPlayer
instances can have their shadows configured before they are used.
OnCompletionListener
, OnErrorListener
,
OnInfoListener
, OnPreparedListener
and OnSeekCompleteListener
.
MediaPlayer
internal states and their transition map.
setSeekDelay(int)
.
ShadowMediaPlayer.MediaInfo
inner class.
setInvalidStateBehavior(org.robolectric.shadows.ShadowMediaPlayer.InvalidStateBehavior)
).
setDataSource()
, using addMediaInfo(org.robolectric.shadows.util.DataSource, org.robolectric.shadows.ShadowMediaPlayer.MediaInfo)
.
setDataSource(org.robolectric.shadows.util.DataSource)
using addException(org.robolectric.shadows.util.DataSource, java.lang.RuntimeException)
.
ShadowMediaPlayer.MediaInfo
instance for that data source (using addException(DataSource, IOException)
or addMediaInfo(DataSource, MediaInfo)
respectively) before calling setDataSource(org.robolectric.shadows.util.DataSource)
, otherwise you'll get an IllegalArgumentException
.
The current features of ShadowMediaPlayer
were focused on development for testing
playback of audio tracks. Thus support for emulating timed text and video events is incomplete.
None of these features would be particularly onerous to add/fix - contributions welcome, of
course!
Modifier and Type | Class | Description |
---|---|---|
static interface |
ShadowMediaPlayer.CreateListener |
Callback interface for clients that wish to be informed when a new
MediaPlayer instance is constructed. |
static class |
ShadowMediaPlayer.InvalidStateBehavior |
Possible behavior modes for the media player when a method is invoked in an
invalid state.
|
static interface |
ShadowMediaPlayer.MediaEvent |
|
static class |
ShadowMediaPlayer.MediaInfo |
Class specifying information for an emulated media object.
|
static class |
ShadowMediaPlayer.State |
Possible states for the media player to be in.
|
Modifier and Type | Field | Description |
---|---|---|
protected static ShadowMediaPlayer.CreateListener |
createListener |
Listener that is called when a new MediaPlayer is constructed.
|
static int |
MEDIA_EVENT |
Constructor | Description |
---|---|
ShadowMediaPlayer() |
Modifier and Type | Method | Description |
---|---|---|
protected void |
__constructor__() |
|
protected static void |
__staticInitializer__() |
|
protected void |
_pause() |
Simulates
MediaPlayer._pause() . |
protected void |
_release() |
Simulates call to
MediaPlayer._release() . |
protected void |
_reset() |
Simulates call to
MediaPlayer._reset() . |
protected void |
_stop() |
Simulates call to
MediaPlayer.release() . |
static void |
addException(DataSource dataSource,
IOException e) |
|
static void |
addException(DataSource dataSource,
RuntimeException e) |
|
static void |
addMediaInfo(DataSource dataSource,
ShadowMediaPlayer.MediaInfo info) |
|
protected void |
attachAuxEffect(int effectId) |
|
protected static MediaPlayer |
create(Context context,
int resId) |
|
protected static MediaPlayer |
create(Context context,
Uri uri) |
|
void |
doSetDataSource(DataSource dataSource) |
Sets the data source without doing any other emulation.
|
void |
doStart() |
Starts simulated playback.
|
void |
doStop() |
Pauses simulated playback.
|
protected int |
getAudioSessionId() |
|
int |
getAuxEffect() |
Useful for assertions.
|
protected int |
getCurrentPosition() |
Simulates call to
MediaPlayer.getCurrentPosition() . |
int |
getCurrentPositionRaw() |
Retrieves the current position without doing the state checking that the
emulated version of
getCurrentPosition() does. |
DataSource |
getDataSource() |
Retrieves the data source (if any) that was passed in to
setDataSource(DataSource) . |
protected int |
getDuration() |
Simulates call to
MediaPlayer.getDuration() . |
int |
getDurationRaw() |
Retrieves the current duration without doing the state checking that the
emulated version does.
|
Handler |
getHandler() |
Retrieves the
Handler object used by this
ShadowMediaPlayer . |
ShadowMediaPlayer.InvalidStateBehavior |
getInvalidStateBehavior() |
Retrieves current flag specifying the behavior of the media player when a
method is invoked in an invalid state.
|
float |
getLeftVolume() |
Retrieves the current setting for the left channel volume.
|
ShadowMediaPlayer.MediaInfo |
getMediaInfo() |
Retrieves the currently selected
ShadowMediaPlayer.MediaInfo . |
static ShadowMediaPlayer.MediaInfo |
getMediaInfo(DataSource dataSource) |
|
MediaPlayer.OnCompletionListener |
getOnCompletionListener() |
|
MediaPlayer.OnPreparedListener |
getOnPreparedListener() |
|
int |
getPendingSeek() |
Retrieves the pending seek setting.
|
float |
getRightVolume() |
|
int |
getSeekDelay() |
|
int |
getSourceResId() |
Retrieves the resource ID used in the call to
create(Context, int)
(if any). |
Uri |
getSourceUri() |
Retrieves the source path (if any) that was passed in to
MediaPlayer.setDataSource(Context, Uri, Map) or
MediaPlayer.setDataSource(Context, Uri) . |
ShadowMediaPlayer.State |
getState() |
Retrieves the current state of the
MediaPlayer . |
int |
getTheAudioStreamType() |
Note: This has a funny name at the
moment to avoid having to produce an API-specific shadow -
if it were called
getAudioStreamType() then
the RobolectricWiringTest will inform us that
it should be annotated with Implementation , because
there is a private method in the later API versions with
the same name, however this would fail on earlier versions. |
protected int |
getVideoHeight() |
|
protected int |
getVideoWidth() |
|
void |
invokeCompletionListener() |
Simulates end-of-playback.
|
void |
invokeErrorListener(int what,
int extra) |
Allows test cases to directly simulate invocation of the OnError event.
|
void |
invokeInfoListener(int what,
int extra) |
Allows test cases to directly simulate invocation of the OnInfo event.
|
void |
invokePreparedListener() |
Allows test cases to simulate 'prepared' state by invoking callback.
|
void |
invokeSeekCompleteListener() |
Allows test cases to simulate seek completion by invoking callback.
|
protected boolean |
isLooping() |
|
protected boolean |
isPlaying() |
|
boolean |
isPrepared() |
Tests to see if the player is in the PREPARED state.
|
boolean |
isReallyPlaying() |
Tests to see if the player is really playing.
|
void |
postEvent(ShadowMediaPlayer.MediaEvent e) |
|
void |
postEventDelayed(ShadowMediaPlayer.MediaEvent e,
long delay) |
|
protected void |
prepare() |
Simulates
MediaPlayer.prepareAsync() . |
protected void |
prepareAsync() |
Simulates
MediaPlayer.prepareAsync() . |
static void |
resetStaticState() |
|
protected void |
seekTo(int seekTo) |
Simulates seeking to specified position.
|
protected void |
seekTo(long seekTo,
int mode) |
|
protected void |
setAudioSessionId(int sessionId) |
|
protected void |
setAudioStreamType(int audioStreamType) |
|
static void |
setCreateListener(ShadowMediaPlayer.CreateListener createListener) |
Sets a listener that is invoked whenever a new shadowed
MediaPlayer
object is constructed. |
void |
setCurrentPosition(int position) |
Sets the current position, bypassing the normal state checking.
|
protected void |
setDataSource(Context context,
Uri uri) |
|
protected void |
setDataSource(Context context,
Uri uri,
Map<String,String> headers) |
|
protected void |
setDataSource(Context context,
Uri uri,
Map<String,String> headers,
List<HttpCookie> cookies) |
|
protected void |
setDataSource(AssetFileDescriptor assetFileDescriptor) |
|
protected void |
setDataSource(MediaDataSource mediaDataSource) |
|
protected void |
setDataSource(FileDescriptor fd,
long offset,
long length) |
|
protected void |
setDataSource(String path) |
|
protected void |
setDataSource(String uri,
Map<String,String> headers) |
|
void |
setDataSource(DataSource dataSource) |
Common code path for all
setDataSource() implementations. |
void |
setInvalidStateBehavior(ShadowMediaPlayer.InvalidStateBehavior invalidStateBehavior) |
Specifies how the media player should behave when a method is invoked in an invalid state.
|
protected void |
setLooping(boolean looping) |
|
protected void |
setOnCompletionListener(MediaPlayer.OnCompletionListener listener) |
|
protected void |
setOnErrorListener(MediaPlayer.OnErrorListener listener) |
|
protected void |
setOnInfoListener(MediaPlayer.OnInfoListener listener) |
|
protected void |
setOnPreparedListener(MediaPlayer.OnPreparedListener listener) |
|
protected void |
setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener) |
|
void |
setSeekDelay(int seekDelay) |
Sets the length of time (ms) that seekTo() will delay before completing.
|
void |
setState(ShadowMediaPlayer.State state) |
Forces the @link MediaPlayer} into the specified state.
|
protected void |
setVolume(float left,
float right) |
|
protected void |
start() |
Simulates private native method
MediaPlayer._start() . |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
getService
protected static ShadowMediaPlayer.CreateListener createListener
setCreateListener(CreateListener)
public static final int MEDIA_EVENT
@Implementation protected static void __staticInitializer__()
public void postEvent(ShadowMediaPlayer.MediaEvent e)
public void postEventDelayed(ShadowMediaPlayer.MediaEvent e, long delay)
@Implementation protected static MediaPlayer create(Context context, int resId)
@Implementation protected static MediaPlayer create(Context context, Uri uri)
@Implementation protected void __constructor__()
public void setDataSource(DataSource dataSource) throws IOException
setDataSource()
implementations.
* Checks for any specified exceptions for the specified data source and throws them. *
Checks the current state and throws an exception if it is in an invalid state. * If no
exception is thrown in either of the previous two steps, then doSetDataSource(DataSource)
is called to set the data source. * Sets the player state to
INITIALIZED
. Usually this method would not be called directly, but indirectly through
one of the other setDataSource(String)
implementations, which use DataSource.toDataSource(String)
methods to convert their discrete parameters into a single
DataSource
instance.
dataSource
- the data source that is being set.IOException
- if the specified data source has been configured to throw an IO exception.addException(DataSource, IOException)
,
addException(DataSource, RuntimeException)
,
doSetDataSource(DataSource)
@Implementation protected void setDataSource(String path) throws IOException
IOException
@Implementation(maxSdk=25) protected void setDataSource(Context context, Uri uri) throws IOException
IOException
@Implementation(minSdk=14, maxSdk=25) protected void setDataSource(Context context, Uri uri, Map<String,String> headers) throws IOException
IOException
@Implementation(minSdk=26) protected void setDataSource(Context context, Uri uri, Map<String,String> headers, List<HttpCookie> cookies) throws IOException
IOException
@Implementation protected void setDataSource(String uri, Map<String,String> headers) throws IOException
IOException
@Implementation protected void setDataSource(FileDescriptor fd, long offset, long length) throws IOException
IOException
@Implementation(minSdk=23) protected void setDataSource(MediaDataSource mediaDataSource) throws IOException
IOException
@Implementation(minSdk=24) protected void setDataSource(AssetFileDescriptor assetFileDescriptor) throws IOException
IOException
public void doSetDataSource(DataSource dataSource)
ShadowMediaPlayer
instance during
specific testing so that you don't have to clutter your tests catching exceptions you know
won't be thrown.dataSource
- the data source that is being set.setDataSource(DataSource)
public static ShadowMediaPlayer.MediaInfo getMediaInfo(DataSource dataSource)
public static void addMediaInfo(DataSource dataSource, ShadowMediaPlayer.MediaInfo info)
public static void addException(DataSource dataSource, RuntimeException e)
public static void addException(DataSource dataSource, IOException e)
@Implementation protected void setOnCompletionListener(MediaPlayer.OnCompletionListener listener)
@Implementation protected void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener)
@Implementation protected void setOnPreparedListener(MediaPlayer.OnPreparedListener listener)
@Implementation protected void setOnInfoListener(MediaPlayer.OnInfoListener listener)
@Implementation protected void setOnErrorListener(MediaPlayer.OnErrorListener listener)
@Implementation protected boolean isLooping()
@Implementation protected void setLooping(boolean looping)
@Implementation protected void setVolume(float left, float right)
@Implementation protected boolean isPlaying()
@Implementation protected void prepare()
MediaPlayer.prepareAsync()
. Sleeps for preparationDelay
ms by calling SystemClock.sleep(long)
before calling invokePreparedListener()
.
If preparationDelay
is not positive and non-zero, there is no sleep.
@Implementation protected void prepareAsync()
MediaPlayer.prepareAsync()
. Sets state to PREPARING and posts a callback to
invokePreparedListener()
if the current preparation delay for the current media (see
getMediaInfo()
) is >= 0, otherwise the test suite is responsible for calling invokePreparedListener()
directly if required.@Implementation protected void start()
MediaPlayer._start()
. Sets state to STARTED and calls
doStart()
to start scheduling playback callback events.
If the current state is PLAYBACK_COMPLETED, the current position is reset to zero before starting playback.
doStart()
public boolean isReallyPlaying()
currentPosition
is being updated as time
passes. Note that while the player will normally be really playing if in
the STARTED state, this is not always the case - for example, if a pending
seek is in progress, or perhaps a buffer underrun is being simulated.public void doStart()
isReallyPlaying()
for a definition of
"really playing").
This method is used internally by the various shadow method implementations
of the MediaPlayer public API, but may also be called directly by the test
suite if you wish to simulate an internal pause. For example, to simulate
a buffer underrun (player is in PLAYING state but isn't actually advancing
the current position through the media), you could call doStop()
to
mark the start of the buffer underrun and doStart()
to mark its
end and restart normal playback (which is what
scheduleBufferUnderrunAtOffset()
does).isReallyPlaying()
,
doStop()
public void doStop()
isReallyPlaying()
for a definition of
"really playing").
This method is used internally by the various shadow method implementations
of the MediaPlayer public API, but may also be called directly by the test
suite if you wish to simulate an internal pause.isReallyPlaying()
,
doStart()
@Implementation protected void _pause()
MediaPlayer._pause()
. Invokes doStop()
to suspend playback event
callbacks and sets the state to PAUSED.doStop()
@Implementation protected void _release()
MediaPlayer._release()
. Calls doStop()
to suspend playback
event callbacks and sets the state to END.@Implementation protected void _reset()
MediaPlayer._reset()
. Calls doStop()
to suspend playback
event callbacks and sets the state to IDLE.@Implementation protected void _stop()
MediaPlayer.release()
. Calls doStop()
to suspend playback
event callbacks and sets the state to STOPPED.@Implementation protected void attachAuxEffect(int effectId)
@Implementation protected int getAudioSessionId()
@Implementation protected int getCurrentPosition()
MediaPlayer.getCurrentPosition()
. Simply does the state validity
checks and then invokes getCurrentPositionRaw()
to calculate the simulated playback
position.getCurrentPositionRaw()
@Implementation protected int getDuration()
MediaPlayer.getDuration()
. Retrieves the duration as defined by the
current ShadowMediaPlayer.MediaInfo
instance.addMediaInfo(DataSource, MediaInfo)
@Implementation protected int getVideoHeight()
@Implementation protected int getVideoWidth()
@Implementation protected void seekTo(int seekTo)
seekDelay
ms
(defaults to 0), or else if seekDelay is negative then the controlling test is expected to
simulate seek completion by manually invoking invokeSeekCompleteListener()
.seekTo
- the offset (in ms) from the start of the track to seek to.@Implementation(minSdk=26) protected void seekTo(long seekTo, int mode)
@Implementation protected void setAudioSessionId(int sessionId)
@Implementation protected void setAudioStreamType(int audioStreamType)
public static void setCreateListener(ShadowMediaPlayer.CreateListener createListener)
MediaPlayer
object is constructed.
Registering a listener gives you a chance to
customize the shadowed object appropriately without needing to modify the
application-under-test to provide access to the instance at the appropriate
point in its life cycle. This is useful because normally a new
MediaPlayer
is created and setDataSource()
is invoked soon after, without a break in the code. Using this callback
means you don't have to change this common pattern just so that you can
customize the shadow for testing.createListener
- the listener to be invokedpublic Handler getHandler()
Handler
object used by this
ShadowMediaPlayer
. Can be used for posting custom asynchronous
events to the thread (eg, asynchronous errors). Use this for scheduling
events to take place at a particular "real" time (ie, time as measured by
the scheduler). For scheduling events to occur at a particular playback
offset (no matter how long playback may be paused for, or where you seek
to, etc), see ShadowMediaPlayer.MediaInfo.scheduleEventAtOffset(int, ShadowMediaPlayer.MediaEvent)
and
its various helpers.public ShadowMediaPlayer.InvalidStateBehavior getInvalidStateBehavior()
setInvalidStateBehavior(InvalidStateBehavior)
for a discussion of
the available modes and their associated behaviors.setInvalidStateBehavior(org.robolectric.shadows.ShadowMediaPlayer.InvalidStateBehavior)
public void setInvalidStateBehavior(ShadowMediaPlayer.InvalidStateBehavior invalidStateBehavior)
ShadowMediaPlayer.InvalidStateBehavior
enum):
SILENT
This mode is provided primarily for backwards compatibility, and for this reason it is the default. For proper testing one of the other two modes is probably preferable.
EMULATE
MediaPlayer
implementation. This is based on a reading of the documentation and on actual experiments done
on a Jelly Bean device. The official documentation is not all that clear, but basically methods
fall into three categories:
onError()
. An example is getVideoHeight()
.
IllegalStateException
but don't invoke onError()
. Examples are prepare()
and setDataSource(String)
.
onError()
.
IllegalStateException
when invoked from the END state.
To complicate matters slightly, the official documentation sometimes contradicts observed
behavior. For example, the documentation says it is illegal to call setDataSource(org.robolectric.shadows.util.DataSource)
from
the ERROR state - however, in practice it works fine. Conversely, the documentation says that
it is legal to invoke getCurrentPosition()
from the INITIALIZED state, however testing
showed that this caused an error. Wherever there is a discrepancy between documented and
observed behavior, this implementation has gone with the most conservative implementation (ie,
it is illegal to invoke setDataSource(org.robolectric.shadows.util.DataSource)
from the ERROR state and likewise illegal to
invoke getCurrentPosition()
from the INITIALIZED state.
ASSERT
invalidStateBehavior
- the behavior mode for this shadow to use during testing.getInvalidStateBehavior()
public ShadowMediaPlayer.MediaInfo getMediaInfo()
ShadowMediaPlayer.MediaInfo
. This instance is used
to define current duration, preparation delay, exceptions for
setDataSource()
, playback events, etc.ShadowMediaPlayer.MediaInfo
.addMediaInfo(org.robolectric.shadows.util.DataSource, org.robolectric.shadows.ShadowMediaPlayer.MediaInfo)
,
doSetDataSource(DataSource)
public void setCurrentPosition(int position)
position
- the new playback position.public int getCurrentPositionRaw()
getCurrentPosition()
does.public int getDurationRaw()
public ShadowMediaPlayer.State getState()
MediaPlayer
. Uses the states as
defined in the MediaPlayer
documentation.MediaPlayer
, as defined in the
MediaPlayer documentation.setState(org.robolectric.shadows.ShadowMediaPlayer.State)
,
MediaPlayer
public void setState(ShadowMediaPlayer.State state)
MediaPlayer
documentation.
Note that by invoking this method directly you can get the player into an
inconsistent state that a real player could not be put in (eg, in the END
state but with playback events still happening). Use with care.state
- the new state of the MediaPlayer
, as defined in the
MediaPlayer documentation.getState()
,
MediaPlayer
public int getTheAudioStreamType()
getAudioStreamType()
then
the RobolectricWiringTest
will inform us that
it should be annotated with Implementation
, because
there is a private method in the later API versions with
the same name, however this would fail on earlier versions.public int getSeekDelay()
public void setSeekDelay(int seekDelay)
seekDelay
- length of time to delay (ms)public int getAuxEffect()
auxEffect
setting.public int getPendingSeek()
seekTo(int)
but before a call
to invokeSeekCompleteListener()
). Returns -1
if no seek is in progress.public DataSource getDataSource()
setDataSource(DataSource)
.
Useful for assertions.setDataSource
.public Uri getSourceUri()
MediaPlayer.setDataSource(Context, Uri, Map)
or
MediaPlayer.setDataSource(Context, Uri)
.setDataSource
.public int getSourceResId()
create(Context, int)
(if any).create()
, or
-1
if a different method of setting the source was
used.public float getLeftVolume()
public float getRightVolume()
public boolean isPrepared()
getState()
may be more useful for new testing applications.true
if the MediaPlayer is in the PREPARED state,
false otherwise.public MediaPlayer.OnCompletionListener getOnCompletionListener()
public MediaPlayer.OnPreparedListener getOnPreparedListener()
public void invokePreparedListener()
preparedListener()
public void invokeCompletionListener()
onCompletion()
if a listener has been set.public void invokeSeekCompleteListener()
public void invokeInfoListener(int what, int extra)
what
- parameter to pass in to what
in
MediaPlayer.OnInfoListener.onInfo(MediaPlayer, int, int)
.extra
- parameter to pass in to extra
in
MediaPlayer.OnInfoListener.onInfo(MediaPlayer, int, int)
.public void invokeErrorListener(int what, int extra)
what
- parameter to pass in to what
in
MediaPlayer.OnErrorListener.onError(MediaPlayer, int, int)
.extra
- parameter to pass in to extra
in
MediaPlayer.OnErrorListener.onError(MediaPlayer, int, int)
.@Resetter public static void resetStaticState()