FileDocCategorySizeDatePackage
NotificationPlayer.javaAPI DocAndroid 5.1 API15971Thu Mar 12 22:22:42 GMT 2015com.android.systemui.media

NotificationPlayer

public class NotificationPlayer extends Object implements android.media.MediaPlayer.OnCompletionListener
hide
This class is provides the same interface and functionality as android.media.AsyncPlayer with the following differences: - whenever audio is played, audio focus is requested, - whenever audio playback is stopped or the playback completed, audio focus is abandoned.

Fields Summary
private static final int
PLAY
private static final int
STOP
private static final boolean
mDebug
private LinkedList
mCmdQueue
private android.os.Looper
mLooper
private String
mTag
private CmdThread
mThread
private CreationAndCompletionThread
mCompletionThread
private final Object
mCompletionHandlingLock
private android.media.MediaPlayer
mPlayer
private PowerManager.WakeLock
mWakeLock
private final Object
mQueueAudioFocusLock
private android.media.AudioManager
mAudioManagerWithAudioFocus
private int
mState
Constructors Summary
public NotificationPlayer(String tag)
Construct a NotificationPlayer object.

param
tag a string to use for debugging


                     
       
        if (tag != null) {
            mTag = tag;
        } else {
            mTag = "NotificationPlayer";
        }
    
Methods Summary
private voidacquireWakeLock()

        if (mWakeLock != null) {
            mWakeLock.acquire();
        }
    
private voidenqueueLocked(com.android.systemui.media.NotificationPlayer$Command cmd)

        mCmdQueue.add(cmd);
        if (mThread == null) {
            acquireWakeLock();
            mThread = new CmdThread();
            mThread.start();
        }
    
public voidonCompletion(android.media.MediaPlayer mp)

        synchronized(mQueueAudioFocusLock) {
            if (mAudioManagerWithAudioFocus != null) {
                if (mDebug) Log.d(mTag, "onCompletion() abandonning AudioFocus");
                mAudioManagerWithAudioFocus.abandonAudioFocus(null);
                mAudioManagerWithAudioFocus = null;
            } else {
                if (mDebug) Log.d(mTag, "onCompletion() no need to abandon AudioFocus");
            }
        }
        // if there are no more sounds to play, end the Looper to listen for media completion
        synchronized (mCmdQueue) {
            if (mCmdQueue.size() == 0) {
                synchronized(mCompletionHandlingLock) {
                    if(mLooper != null) {
                        mLooper.quit();
                    }
                    mCompletionThread = null;
                }
            }
        }
    
public voidplay(android.content.Context context, android.net.Uri uri, boolean looping, int stream)
Start playing the sound. It will actually start playing at some point in the future. There are no guarantees about latency here. Calling this before another audio file is done playing will stop that one and start the new one.

param
context Your application's context.
param
uri The URI to play. (see {@link MediaPlayer#setDataSource(Context, Uri)})
param
looping Whether the audio should loop forever. (see {@link MediaPlayer#setLooping(boolean)})
param
stream the AudioStream to use. (see {@link MediaPlayer#setAudioStreamType(int)})
deprecated
use {@link #play(Context, Uri, boolean, AudioAttributes)} instead.

        Command cmd = new Command();
        cmd.requestTime = SystemClock.uptimeMillis();
        cmd.code = PLAY;
        cmd.context = context;
        cmd.uri = uri;
        cmd.looping = looping;
        cmd.attributes = new AudioAttributes.Builder().setInternalLegacyStreamType(stream).build();
        synchronized (mCmdQueue) {
            enqueueLocked(cmd);
            mState = PLAY;
        }
    
public voidplay(android.content.Context context, android.net.Uri uri, boolean looping, android.media.AudioAttributes attributes)
Start playing the sound. It will actually start playing at some point in the future. There are no guarantees about latency here. Calling this before another audio file is done playing will stop that one and start the new one.

param
context Your application's context.
param
uri The URI to play. (see {@link MediaPlayer#setDataSource(Context, Uri)})
param
looping Whether the audio should loop forever. (see {@link MediaPlayer#setLooping(boolean)})
param
attributes the AudioAttributes to use. (see {@link MediaPlayer#setAudioAttributes(AudioAttributes)})

        Command cmd = new Command();
        cmd.requestTime = SystemClock.uptimeMillis();
        cmd.code = PLAY;
        cmd.context = context;
        cmd.uri = uri;
        cmd.looping = looping;
        cmd.attributes = attributes;
        synchronized (mCmdQueue) {
            enqueueLocked(cmd);
            mState = PLAY;
        }
    
private voidreleaseWakeLock()

        if (mWakeLock != null) {
            mWakeLock.release();
        }
    
public voidsetUsesWakeLock(android.content.Context context)
We want to hold a wake lock while we do the prepare and play. The stop probably is optional, but it won't hurt to have it too. The problem is that if you start a sound while you're holding a wake lock (e.g. an alarm starting a notification), you want the sound to play, but if the CPU turns off before mThread gets to work, it won't. The simplest way to deal with this is to make it so there is a wake lock held while the thread is starting or running. You're going to need the WAKE_LOCK permission if you're going to call this. This must be called before the first time play is called.

hide

        if (mWakeLock != null || mThread != null) {
            // if either of these has happened, we've already played something.
            // and our releases will be out of sync.
            throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
                    + " mThread=" + mThread);
        }
        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
    
private voidstartSound(com.android.systemui.media.NotificationPlayer$Command cmd)

        // Preparing can be slow, so if there is something else
        // is playing, let it continue until we're done, so there
        // is less of a glitch.
        try {
            if (mDebug) Log.d(mTag, "Starting playback");
            //-----------------------------------
            // This is were we deviate from the AsyncPlayer implementation and create the
            // MediaPlayer in a new thread with which we're synchronized
            synchronized(mCompletionHandlingLock) {
                // if another sound was already playing, it doesn't matter we won't get notified
                // of the completion, since only the completion notification of the last sound
                // matters
                if((mLooper != null)
                        && (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
                    mLooper.quit();
                }
                mCompletionThread = new CreationAndCompletionThread(cmd);
                synchronized(mCompletionThread) {
                    mCompletionThread.start();
                    mCompletionThread.wait();
                }
            }
            //-----------------------------------

            long delay = SystemClock.uptimeMillis() - cmd.requestTime;
            if (delay > 1000) {
                Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
            }
        }
        catch (Exception e) {
            Log.w(mTag, "error loading sound for " + cmd.uri, e);
        }
    
public voidstop()
Stop a previously played sound. It can't be played again or unpaused at this point. Calling this multiple times has no ill effects.

        synchronized (mCmdQueue) {
            // This check allows stop to be called multiple times without starting
            // a thread that ends up doing nothing.
            if (mState != STOP) {
                Command cmd = new Command();
                cmd.requestTime = SystemClock.uptimeMillis();
                cmd.code = STOP;
                enqueueLocked(cmd);
                mState = STOP;
            }
        }