Android Open Source - PlayerHater Stately Player






From Project

Back to project page PlayerHater.

License

The source code is released under:

Apache License

If you think the Android project PlayerHater listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*******************************************************************************
 * Copyright 2013 Chris Rhoden, Rebecca Nesson, Public Radio Exchange
 * /*w w w  .j  a v a  2  s .  c o m*/
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package org.prx.playerhater.mediaplayer;

import java.io.IOException;

import org.prx.playerhater.util.Log;

import android.content.ContentProviderClient;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;

public class StatelyPlayer extends Player implements OnBufferingUpdateListener,
    OnCompletionListener, OnErrorListener, OnInfoListener,
    OnPreparedListener, OnSeekCompleteListener {

    private static final String PERMISSION = "android.permission.WAKE_LOCK";
    private static final int GRANTED = PackageManager.PERMISSION_GRANTED;
    private static final int WAKE_LOCK = PowerManager.PARTIAL_WAKE_LOCK;

  /**
   * An invalid state for a {@linkplain MediaPlayer} to be in.
   */
  public static final int INVALID_STATE = -1;

  /**
   * The state a {@linkplain MediaPlayer} is in when initialized. Nothing is
   * loaded into the player.
   */
  public static final int IDLE = 0;

  /**
   * The state a {@linkplain MediaPlayer} enters after
   * {@linkplain MediaPlayer#release()} is called on it. This
   * {@linkplain MediaPlayer} will be unusable until {@linkplain #reset()} is
   * called on it.
   */
  public static final int END = 1;

  /**
   * The state a {@linkplain MediaPlayer} is in when
   * {@linkplain #setDataSource(Context, Uri)} is called on it.
   */
  public static final int INITIALIZED = 2;

  /**
   * The state a {@linkplain MediaPlayer} is in when
   * {@linkplain #prepareAsync()} is called on it.
   */
  public static final int PREPARING = 4;

  /**
   * The state a {@linkplain MediaPlayer} is in when
   * {@linkplain #prepareAsync()} is complete or when {prepare()} is
   * called.
   */
  public static final int PREPARED = 8;

  /**
   * The state a {@linkplain MediaPlayer} is in when playing.
   */
  public static final int STARTED = 16;

  /**
   * The state a {@linkplain MediaPlayer} is in when {{@link #stop()} is
   * called.
   */
  public static final int STOPPED = 32;

  /**
   * The state a {@linkplain MediaPlayer} is in when {{@link #pause()} is
   * called.
   */
  public static final int PAUSED = 64;

  /**
   * The state a {@linkplain MediaPlayer} is in when it has reached the end of
   * the data loaded into it.
   */
  public static final int PLAYBACK_COMPLETED = 128;

  /**
   * Internal state used for content:// URIs
   */
  public static final int LOADING_CONTENT = -256;

  /**
   * Internal state used for content:// URIs
   */
  public static final int PREPARING_CONTENT = -512;

  /**
   * The state a {@linkplain MediaPlayer} is in when an error has occurred.
   */
  public static final int ERROR = 1024;

  /**
   * Used in a statemask to indicate that the player is getting ready to play.
   */
  public static final int WILL_PLAY = 65536;

  /**
   * Used in a statemask to indicate that the player is not able to seek.
   */
  public static final int NOT_SEEKABLE = 2048;

  public static boolean willPlay(int stateMask) {
    return (stateMask & WILL_PLAY) == WILL_PLAY;
  }

  public static boolean seekable(int stateMask) {
    return (stateMask & NOT_SEEKABLE) != NOT_SEEKABLE;
  }

  public static int mediaPlayerState(int stateMask) {
    if (willPlay(stateMask)) {
      stateMask &= ~WILL_PLAY;
    }
    if (!seekable(stateMask)) {
      stateMask &= ~NOT_SEEKABLE;
    }
    return stateMask;
  }

  private final MediaPlayer mMediaPlayer;
  private StateChangeListener mStateChangeListener;
  private boolean mBuffering = false;
  private boolean mNotSeekable = false;

  public static class ListenerCollection {
    public OnErrorListener errorListener;
    public OnPreparedListener preparedListener;
    public OnCompletionListener completionListener;
    public OnBufferingUpdateListener bufferingUpdateListener;
    public OnInfoListener infoListener;
    public OnSeekCompleteListener seekCompleteListener;
  }

  private final ListenerCollection mListenerCollection;

  private int mState;
  private int mPrevState;

  private boolean mInErrorCallback;

  public StatelyPlayer(Context context) {
    mMediaPlayer = new MediaPlayer();
        setWakeLock(context);
    setState(IDLE);
    mListenerCollection = new ListenerCollection();
    getBarePlayer().setOnBufferingUpdateListener(this);
    getBarePlayer().setOnCompletionListener(this);
    getBarePlayer().setOnErrorListener(this);
    getBarePlayer().setOnInfoListener(this);
    getBarePlayer().setOnPreparedListener(this);
    getBarePlayer().setOnSeekCompleteListener(this);
  }

  @Override
  public void setStateChangeListener(StateChangeListener listener) {
    mStateChangeListener = listener;
  }

  @Override
  public synchronized int getState() {
    return getPublicState(getInternalState());
  }

  public synchronized int getStateMask() {
    return getState() | (isWaitingToPlay() ? WILL_PLAY : 0)
        | (mNotSeekable ? NOT_SEEKABLE : 0);
  }

  private synchronized int getInternalState() {
    return mState;
  }

  private int getPublicState(int internalState) {
    if (internalState >= 0) {
      return internalState;
    }
    switch (internalState) {
    case PREPARING_CONTENT:
      return PREPARING;
    case LOADING_CONTENT:
      return INITIALIZED;
    default:
      return INVALID_STATE;
    }
  }

  private synchronized void setState(int state) {
    mState = state;
    mInErrorCallback = false;
    onStateChanged();
  }

  protected void onStateChanged() {
    if (mStateChangeListener != null) {
      mStateChangeListener.onStateChanged(this, getStateMask());
    }
  }

  public static String getStateName(int state) {
    switch (state) {
    case END:
      return "end";
    case ERROR:
      return "error";
    case IDLE:
      return "idle";
    case INITIALIZED:
      return "initialized";
    case LOADING_CONTENT:
      return "initialized(content uri)";
    case PAUSED:
      return "paused";
    case PLAYBACK_COMPLETED:
      return "playback completed";
    case PREPARED:
      return "prepared";
    case PREPARING:
      return "preparing";
    case PREPARING_CONTENT:
      return "preparing(content uri)";
    case STARTED:
      return "started";
    case STOPPED:
      return "stopped";
    }
    throw new IllegalStateException("Impossible state index: " + state);
  }

  @Override
  public synchronized String getStateName() {
    return getStateName(getInternalState());
  }

  @Override
  public synchronized void reset() {
    try {
      if (getState() != IDLE) {
        mMediaPlayer.reset();
      }
    } catch (IllegalStateException e) {
      Log.e("We got an error", e);
      Log.e(getStateName(), e);
      throw e;
    }
    setState(IDLE);
  }

  @Override
  public synchronized void release() {
    mMediaPlayer.release();
    setState(END);
  }

  @Override
  public synchronized void prepareAsync() throws IllegalStateException {
    int state = getInternalState();
    if ((state & (INITIALIZED | STOPPED)) != 0) {
      mMediaPlayer.prepareAsync();
      setState(PREPARING);
    } else if (state == LOADING_CONTENT) {
      setState(PREPARING_CONTENT);
    } else {
      throw illegalState("prepareAsync");
    }
  }

  private static final int START_BITMASK = PREPARED | STARTED | PAUSED
      | PLAYBACK_COMPLETED;

  @Override
  public synchronized void start() throws IllegalStateException {
    int state = getInternalState();
    if ((state & START_BITMASK) != 0) {
      mMediaPlayer.start();
      setState(STARTED);
    } else {
      throw illegalState("start");
    }
  }

  private static final int PAUSE_BITMASK = STARTED | PAUSED;

  @Override
  public synchronized void pause() throws IllegalStateException {
    int state = getInternalState();
    if ((state & PAUSE_BITMASK) != 0) {
      mMediaPlayer.pause();
      setState(PAUSED);
    } else {
      throw illegalState("pause");
    }
  }

  private static final int STOP_BITMASK = PREPARED | STARTED | STOPPED
      | PAUSED | PLAYBACK_COMPLETED;

  @Override
  public synchronized void stop() throws IllegalStateException {
    int state = getInternalState();
    if ((state & (STOP_BITMASK)) != 0) {
      mMediaPlayer.stop();
      setState(STOPPED);
    } else {
      throw illegalState("stop");
    }
  }

  private static final int SEEK_TO_BITMASK = PREPARED | STARTED | PAUSED
      | PLAYBACK_COMPLETED;

  @Override
  public synchronized void seekTo(int msec) {
    int state = getInternalState();
    if ((state & SEEK_TO_BITMASK) != 0) {
      mPrevState = getInternalState();
      setState(PREPARING);
      mMediaPlayer.seekTo(msec);
    } else {
      throw illegalState("seekTo");
    }
  }

  @Override
  public synchronized boolean isPlaying() {
    return mMediaPlayer.isPlaying();
  }

  private static final int GET_POSITION_BITMASK = STARTED | PAUSED | STOPPED
      | PLAYBACK_COMPLETED;

  @Override
  public synchronized int getCurrentPosition() {
    int state = getInternalState();
    if ((state & GET_POSITION_BITMASK) != 0) {
      return mMediaPlayer.getCurrentPosition();
    }
    return 0;
  }

  private static final int GET_DURATION_BITMASK = PREPARED | STARTED | PAUSED
      | PLAYBACK_COMPLETED;

  @Override
  public synchronized int getDuration() {
    int state = getInternalState();
    if ((state & GET_DURATION_BITMASK) != 0) {
      return mMediaPlayer.getDuration();
    }
    return 0;
  }

  @Override
  public synchronized void setAudioStreamType(int streamtype) {
    mMediaPlayer.setAudioStreamType(streamtype);
  }

  @Override
  public synchronized void setDataSource(final Context context, final Uri uri)
      throws IllegalStateException, IOException,
      IllegalArgumentException, SecurityException {
    if (uri.getScheme().equals("content")) {
      setState(LOADING_CONTENT);
      (new Thread() {
        @Override
        public void run() {
          synchronized (StatelyPlayer.this) {
                        final ContentProviderClient contentProviderClient = context.getContentResolver().acquireContentProviderClient(uri);
            try {
              ParcelFileDescriptor fd = contentProviderClient.openFile(
                      uri, "r");
              mMediaPlayer.setDataSource(fd.getFileDescriptor());
              int state = getInternalState();
              setState(INITIALIZED);
              if ((state & PREPARING_CONTENT) != 0) {
                prepareAsync();
              }
            } catch (Exception e) {
              Log.e("Whoops", e);
              try {
                mMediaPlayer.setDataSource(uri.toString());
                int state = getInternalState();
                setState(INITIALIZED);
                if ((state & PREPARING_CONTENT) != 0) {
                  prepareAsync();
                }
              } catch (Exception e1) {
                Log.e("Whoops", e1);
              }
            } finally {
                            contentProviderClient.release();
                        }
                    }
        }
      }).start();
    } else if (uri.getScheme().equals("http") || uri.getScheme().equals("https")) {
        mMediaPlayer.setDataSource(uri.toString());
        setState(INITIALIZED);
    } else { 
      mMediaPlayer.setDataSource(context, uri); 
      setState(INITIALIZED); 
    } 
  }

  @Override
  public synchronized void setOnErrorListener(OnErrorListener errorListener) {
    mListenerCollection.errorListener = errorListener;
  }

  @Override
  public synchronized void setOnPreparedListener(
      OnPreparedListener preparedListener) {
    mListenerCollection.preparedListener = preparedListener;
  }

  @Override
  public synchronized void setOnBufferingUpdateListener(
      OnBufferingUpdateListener bufferingUpdateListener) {
    mListenerCollection.bufferingUpdateListener = bufferingUpdateListener;
  }

  @Override
  public synchronized void setOnCompletionListener(
      OnCompletionListener completionListener) {
    mListenerCollection.completionListener = completionListener;
  }

  @Override
  public synchronized void setOnInfoListener(OnInfoListener infoListener) {
    mListenerCollection.infoListener = infoListener;
  }

  @Override
  public synchronized void setOnSeekCompleteListener(
      OnSeekCompleteListener seekCompleteListener) {
    mListenerCollection.seekCompleteListener = seekCompleteListener;
  }

  @Override
  public synchronized void onBufferingUpdate(MediaPlayer mp, int percent) {
    if (mListenerCollection.bufferingUpdateListener != null) {
      mListenerCollection.bufferingUpdateListener.onBufferingUpdate(mp,
          percent);
    }
  }

  @Override
  public synchronized void onCompletion(MediaPlayer mp) {
    if (mListenerCollection.completionListener != null) {
      mListenerCollection.completionListener.onCompletion(mp);
    }
    setState(PLAYBACK_COMPLETED);
  }

  @Override
  public synchronized boolean onError(MediaPlayer mp, int what, int extra) {
    if (mListenerCollection.errorListener != null) {
      mInErrorCallback = true;
      if (mListenerCollection.errorListener.onError(mp, what, extra)) {
        if (mInErrorCallback) {
          setState(ERROR);
        }
        return true;
      }
    }
    setState(ERROR);
    return false;
  }

  @Override
  public synchronized boolean onInfo(MediaPlayer mp, int what, int extra) {
    boolean handled = false;
    if (mListenerCollection.infoListener != null) {
      handled = mListenerCollection.infoListener.onInfo(mp, what, extra);
    }

    switch (what) {
    case MediaPlayer.MEDIA_INFO_BUFFERING_START:
      mBuffering = true;
      setState(PREPARING);
      return true;
    case MediaPlayer.MEDIA_INFO_BUFFERING_END:
      mBuffering = false;
      setState(STARTED);
      return true;
    case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
      mNotSeekable = true;
      return true;
    default:
      return handled;
    }
  }

  @Override
  public synchronized void onPrepared(MediaPlayer mp) {
    if (mListenerCollection.preparedListener != null) {
      mListenerCollection.preparedListener.onPrepared(mp);
    }
    setState(PREPARED);
  }

  @Override
  public synchronized void onSeekComplete(MediaPlayer mp) {
    setState(mPrevState);
    if (mListenerCollection.seekCompleteListener != null) {
      mListenerCollection.seekCompleteListener.onSeekComplete(mp);
    }
  }

  @Override
  public synchronized void setVolume(float leftVolume, float rightVolume) {
    mMediaPlayer.setVolume(leftVolume, rightVolume);
  }

  @Override
  public synchronized boolean equals(MediaPlayer mp) {
    return mp == mMediaPlayer;
  }

  @Override
  public boolean isWaitingToPlay() {
    return super.isWaitingToPlay() || mBuffering;
  }

    private void setWakeLock(Context context) {
        PackageManager pm = context.getPackageManager();
        String packageName = context.getPackageName();

        if (pm.checkPermission(PERMISSION, packageName) == GRANTED) {
            mMediaPlayer.setWakeMode(context, WAKE_LOCK);
        } else {
            Log.d("You need to request wake lock permission to enable wake locking during playback.");
        }
    }

  protected synchronized MediaPlayer getBarePlayer() {
    return mMediaPlayer;
  }

  @Override
  public String toString() {
    return mMediaPlayer.toString() + " (" + getStateName() + ")";
  }

  private IllegalStateException illegalState(String methodName) {
    IllegalStateException e = new IllegalStateException("Cannot call "
        + methodName + " in the " + getStateName(getState())
        + " state. (" + mMediaPlayer.toString() + ")");
    e.printStackTrace();
    return e;
  }
}




Java Source Code List

.AbstractPlugin.java
.AudioFocusPlugin.java
.BackgroundedPlugin.java
.BoundPlayerHater.java
.BroadcastReceiver.java
.ClientPlugin.java
.Config.java
.ExpandableNotificationPlugin.java
.HeadphoneButtonGestureHelper.java
.IPlayerHater.java
.LockScreenControlsPlugin.java
.Log.java
.MediaPlayerPool.java
.NotificationPlugin.java
.OnAudioFocusChangedListener.java
.PebblePlugin.java
.PlaybackService.java
.PlayerHaterClient.java
.PlayerHaterListenerPlugin.java
.PlayerHaterListener.java
.PlayerHaterPlugin.java
.PlayerHaterServer.java
.PlayerHaterService.java
.PlayerHater.java
.PlayerStateWatcher.java
.Player.java
.PlaylistParser.java
.PlaylistSupportingPlayer.java
.PluginCollection.java
.Receiver.java
.RemoteControlButtonReceiver.java
.RemoteSong.java
.ServerPlayerHater.java
.ServicePlayerHater.java
.SongHost.java
.SongQueue.java
.Song.java
.Songs.java
.StatelyPlayer.java
.SynchronousPlayer.java
.ThreadsafePlayerHater.java
.ThreadsafeServicePlayerHater.java
.TouchableNotificationPlugin.java
org.prx.playerhater.BroadcastReceiver.java
org.prx.playerhater.PlaybackService.java
org.prx.playerhater.PlayerHaterListener.java
org.prx.playerhater.PlayerHaterPlugin.java
org.prx.playerhater.PlayerHater.java
org.prx.playerhater.Song.java
org.prx.playerhater.broadcast.HeadphoneButtonGestureHelper.java
org.prx.playerhater.broadcast.OnAudioFocusChangedListener.java
org.prx.playerhater.broadcast.Receiver.java
org.prx.playerhater.broadcast.RemoteControlButtonReceiver.java
org.prx.playerhater.ipc.ClientPlugin.java
org.prx.playerhater.ipc.PlayerHaterClient.java
org.prx.playerhater.ipc.PlayerHaterServer.java
org.prx.playerhater.ipc.ServerPlayerHater.java
org.prx.playerhater.mediaplayer.MediaPlayerPool.java
org.prx.playerhater.mediaplayer.Player.java
org.prx.playerhater.mediaplayer.PlaylistSupportingPlayer.java
org.prx.playerhater.mediaplayer.StatelyPlayer.java
org.prx.playerhater.mediaplayer.SynchronousPlayer.java
org.prx.playerhater.plugins.AbstractPlugin.java
org.prx.playerhater.plugins.AudioFocusPlugin.java
org.prx.playerhater.plugins.BackgroundedPlugin.java
org.prx.playerhater.plugins.ExpandableNotificationPlugin.java
org.prx.playerhater.plugins.LockScreenControlsPlugin.java
org.prx.playerhater.plugins.NotificationPlugin.java
org.prx.playerhater.plugins.PebblePlugin.java
org.prx.playerhater.plugins.PlayerHaterListenerPlugin.java
org.prx.playerhater.plugins.PluginCollection.java
org.prx.playerhater.plugins.ScrubbableLockScreenControlsPlugin.java
org.prx.playerhater.plugins.TouchableNotificationPlugin.java
org.prx.playerhater.service.PlayerHaterService.java
org.prx.playerhater.service.PlayerStateWatcher.java
org.prx.playerhater.songs.RemoteSong.java
org.prx.playerhater.songs.SongHost.java
org.prx.playerhater.songs.SongQueue.java
org.prx.playerhater.songs.Songs.java
org.prx.playerhater.util.Config.java
org.prx.playerhater.util.IPlayerHater.java
org.prx.playerhater.util.Log.java
org.prx.playerhater.util.PlaylistParser.java
org.prx.playerhater.wrappers.BoundPlayerHater.java
org.prx.playerhater.wrappers.ServicePlayerHater.java
org.prx.playerhater.wrappers.ThreadsafePlayerHater.java
org.prx.playerhater.wrappers.ThreadsafeServicePlayerHater.java