@Implements(value=android.media.MediaPlayer.class) public class ShadowMediaPlayer extends Object
MediaPlayer.
Automated testing of media playback can be a difficult thing - especially
testing that your code properly handles asynchronous errors and events. This
near impossible task is made quite straightforward using this implementation
of ShadowMediaPlayer with Robolectric.
This shadow implementation provides much of the functionality needed to
emulate MediaPlayer initialization & 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.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(org.robolectric.shadows.util.DataSource, java.lang.RuntimeException) or addMediaInfo respectively) before
calling setDataSource(org.robolectric.shadows.util.DataSource), otherwise you'll get an
IllegalArgumentException.
The current features of ShadowMediaPlayer were focussed 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 and 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 and Description |
|---|---|
protected static ShadowMediaPlayer.CreateListener |
createListener
Listener that is called when a new MediaPlayer is constructed.
|
static int |
MEDIA_EVENT |
| Constructor and Description |
|---|
ShadowMediaPlayer() |
| Modifier and Type | Method and Description |
|---|---|
void |
__constructor__() |
static void |
__staticInitializer__() |
void |
_pause()
Simulates
MediaPlayer._pause(). |
void |
_release()
Simulates call to
MediaPlayer._release(). |
void |
_reset()
Simulates call to
MediaPlayer._reset(). |
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) |
void |
attachAuxEffect(int effectId) |
static android.media.MediaPlayer |
create(android.content.Context context,
int resId) |
static android.media.MediaPlayer |
create(android.content.Context context,
android.net.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.
|
int |
getAudioSessionId() |
int |
getAuxEffect()
Non-Android accessor.
|
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). |
int |
getDuration()
Simulates call to
MediaPlayer.getDuration(). |
int |
getDurationRaw()
Retrieves the current duration without doing the state checking that the
emulated version does.
|
android.os.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) |
android.media.MediaPlayer.OnCompletionListener |
getOnCompletionListener()
Non-Android accessor.
|
android.media.MediaPlayer.OnPreparedListener |
getOnPreparedListener()
Non-Android accessor.
|
int |
getPendingSeek()
Retrieves the pending seek setting.
|
float |
getRightVolume()
Non-Android accessor.
|
int |
getSeekDelay()
Non-Android accessor.
|
int |
getSourceResId()
Retrieves the resource ID used in the call to
create(Context, int)
(if any). |
android.net.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()
Non-Android accessor.
|
int |
getVideoHeight() |
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.
|
boolean |
isLooping() |
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) |
void |
prepare()
Simulates
MediaPlayer.prepareAsync(). |
void |
prepareAsync()
Simulates
MediaPlayer.prepareAsync(). |
static void |
resetStaticState() |
void |
seekTo(int seekTo)
Simulates seeking to specified position.
|
void |
setAudioSessionId(int sessionId) |
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.
|
void |
setDataSource(android.content.Context context,
android.net.Uri uri,
Map<String,String> headers) |
void |
setDataSource(DataSource dataSource)
Common code path for all
setDataSource() implementations. |
void |
setDataSource(FileDescriptor fd,
long offset,
long length) |
void |
setDataSource(String path) |
void |
setDataSource(String uri,
Map<String,String> headers) |
void |
setInvalidStateBehavior(ShadowMediaPlayer.InvalidStateBehavior invalidStateBehavior)
Specifies how the media player should behave when a method is invoked in an
invalid state.
|
void |
setLooping(boolean looping) |
void |
setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener listener) |
void |
setOnErrorListener(android.media.MediaPlayer.OnErrorListener listener) |
void |
setOnInfoListener(android.media.MediaPlayer.OnInfoListener listener) |
void |
setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener listener) |
void |
setOnSeekCompleteListener(android.media.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.
|
void |
setVolume(float left,
float right) |
void |
start()
Simulates private native method
MediaPlayer._start(). |
protected static ShadowMediaPlayer.CreateListener createListener
setCreateListener(CreateListener)public static final int MEDIA_EVENT
public static void __staticInitializer__()
public void postEvent(ShadowMediaPlayer.MediaEvent e)
public void postEventDelayed(ShadowMediaPlayer.MediaEvent e, long delay)
@Implementation
public static android.media.MediaPlayer create(android.content.Context context,
int resId)
@Implementation
public static android.media.MediaPlayer create(android.content.Context context,
android.net.Uri uri)
public void __constructor__()
public void setDataSource(DataSource dataSource) throws IOException
setDataSource() implementations.
doSetDataSource(DataSource)
is called to set the data source.INITIALIZED.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)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)@Implementation public void setDataSource(String path) throws IOException
IOException@Implementation
public void setDataSource(android.content.Context context,
android.net.Uri uri,
Map<String,String> headers)
throws IOException
IOException@Implementation public void setDataSource(String uri, Map<String,String> headers) throws IOException
IOException@Implementation public void setDataSource(FileDescriptor fd, long offset, long length) throws IOException
IOExceptionpublic 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 public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener listener)
@Implementation public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener listener)
@Implementation public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener listener)
@Implementation public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener listener)
@Implementation public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener listener)
@Implementation public boolean isLooping()
@Implementation public void setLooping(boolean looping)
@Implementation
public void setVolume(float left,
float right)
@Implementation public boolean isPlaying()
@Implementation public void prepare()
MediaPlayer.prepareAsync(). Sleeps for
preparationDelay ms by calling
SystemClock.sleep(long) before calling
invokePreparedListener().
If preparationDelay is not positigetve and non-zero, there is no
sleep.@Implementation public 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 public 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 public void _pause()
MediaPlayer._pause(). Invokes doStop() to suspend
playback event callbacks and sets the state to PAUSED.doStop()@Implementation public void _release()
MediaPlayer._release(). Calls doStop() to
suspend playback event callbacks and sets the state to END.@Implementation public void _reset()
MediaPlayer._reset(). Calls doStop() to
suspend playback event callbacks and sets the state to IDLE.@Implementation public void _stop()
MediaPlayer.release(). Calls doStop() to
suspend playback event callbacks and sets the state to STOPPED.@Implementation public void attachAuxEffect(int effectId)
@Implementation public int getAudioSessionId()
@Implementation public int getCurrentPosition()
MediaPlayer.getCurrentPosition(). Simply does the
state validity checks and then invokes getCurrentPositionRaw() to
calculate the simulated playback position.getCurrentPositionRaw()@Implementation public int getDuration()
MediaPlayer.getDuration(). Retrieves the duration
as defined by the current ShadowMediaPlayer.MediaInfo instance.addMediaInfo@Implementation public int getVideoHeight()
@Implementation public int getVideoWidth()
@Implementation public 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 public void setAudioSessionId(int sessionId)
@Implementation public 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 android.os.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):
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.
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. Non-Android
accessor.public int getDurationRaw()
public ShadowMediaPlayer.State getState()
MediaPlayer. Uses the states as
defined in the MediaPlayer documentation. Non-Android accessor.
Used for assertions.MediaPlayer, as defined in the
MediaPlayer documentation.setState(org.robolectric.shadows.ShadowMediaPlayer.State),
MediaPlayerpublic 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(),
MediaPlayerpublic 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).
Non-Android accessor. Use for assertions.setDataSource.public android.net.Uri getSourceUri()
MediaPlayer.setDataSource(Context, Uri, Map) or
MediaPlayer.setDataSource(Context, Uri).
Non-Android accessor. Use for assertions.setDataSource.public int getSourceResId()
create(Context, int)
(if any).
Non-Android accessor. Use for assertions.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 android.media.MediaPlayer.OnCompletionListener getOnCompletionListener()
public android.media.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
onInfo().extra - parameter to pass in to extra in
onInfo().public void invokeErrorListener(int what,
int extra)
what - parameter to pass in to what in
onError().extra - parameter to pass in to extra in
onError().@Resetter public static void resetStaticState()
Copyright © 2016. All rights reserved.