Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1df49c9 authored by Marie Janssen's avatar Marie Janssen Committed by Andre Eisenbach
Browse files

AVRCP: Use MediaController

RemoteController has been depreciated since M.
MediaController lets us track a lot more things and update data as the
state of audio changes.  We track and log some of these changes for bug
followup.

This also should fix some bugs related to metadata display not happening
on startup / track change / app change.

Bug: 27178384
Bug: 27745277
Bug: 26837775
Bug: 27534794
Bug: 27153373
Change-Id: I246d9641a5e921ed4434495f5c2dfac67d568952
parent 2dfcff23
Loading
Loading
Loading
Loading
+147 −160
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.bluetooth.avrcp;
import java.util.Timer;
import java.util.TimerTask;

import android.app.PendingIntent;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAvrcp;
import android.content.Context;
@@ -28,11 +27,11 @@ import android.content.res.Resources;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.IRemoteControlDisplay;
import android.media.MediaMetadataRetriever;
import android.media.RemoteControlClient;
import android.media.RemoteController;
import android.media.RemoteController.MetadataEditor;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -72,11 +71,13 @@ public final class Avrcp {
    private Context mContext;
    private final AudioManager mAudioManager;
    private AvrcpMessageHandler mHandler;
    private RemoteController mRemoteController;
    private RemoteControllerWeak mRemoteControllerCb;
    private MediaSessionManager mMediaSessionManager;
    private MediaSessionChangeListener mSessionChangeListener;
    private MediaController mMediaController;
    private MediaControllerListener mMediaControllerCb;
    private Metadata mMetadata;
    private int mTransportControlFlags;
    private int mCurrentPlayState;
    private PlaybackState mCurrentPlayState;
    private int mPlayStatusChangedNT;
    private int mTrackChangedNT;
    private long mTrackNumber;
@@ -136,10 +137,6 @@ public final class Avrcp {
    private static final int MESSAGE_REWIND = 11;
    private static final int MESSAGE_CHANGE_PLAY_POS = 12;
    private static final int MESSAGE_SET_A2DP_AUDIO_STATE = 13;
    private static final int MSG_UPDATE_STATE = 100;
    private static final int MSG_SET_METADATA = 101;
    private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
    private static final int MSG_SET_GENERATION_ID = 104;

    private static final int BUTTON_TIMEOUT_TIME = 2000;
    private static final int BASE_SKIP_AMOUNT = 2000;
@@ -159,11 +156,11 @@ public final class Avrcp {

    private Avrcp(Context context) {
        mMetadata = new Metadata();
        mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
        mCurrentPlayState = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE, -1L, 0.0f).build();
        mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
        mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
        mTrackNumber = -1L;
        mCurrentPosMs = RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN;
        mCurrentPosMs = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
        mPlayStartTimeMs = -1L;
        mSongLengthMs = 0L;
        mPlaybackIntervalMs = 0L;
@@ -185,6 +182,7 @@ public final class Avrcp {

        initNative();

        mMediaSessionManager = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax);
@@ -199,10 +197,14 @@ public final class Avrcp {
        thread.start();
        Looper looper = thread.getLooper();
        mHandler = new AvrcpMessageHandler(looper);
        mRemoteControllerCb = new RemoteControllerWeak(mHandler);
        mRemoteController = new RemoteController(mContext, mRemoteControllerCb);
        mAudioManager.registerRemoteController(mRemoteController);
        mRemoteController.setSynchronizationMode(RemoteController.POSITION_SYNCHRONIZATION_CHECK);

        mSessionChangeListener = new MediaSessionChangeListener();
        mMediaSessionManager.addOnActiveSessionsChangedListener(mSessionChangeListener, null, mHandler);
        List<MediaController> sessions = mMediaSessionManager.getActiveSessions(null);
        mMediaControllerCb = new MediaControllerListener();
        if (sessions.size() > 0) {
            updateCurrentMediaController(sessions.get(0));
        }
    }

    public static Avrcp make(Context context) {
@@ -218,7 +220,7 @@ public final class Avrcp {
        if (looper != null) {
            looper.quit();
        }
        mAudioManager.unregisterRemoteController(mRemoteController);
        mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionChangeListener);
    }

    public void cleanup() {
@@ -227,61 +229,53 @@ public final class Avrcp {
            mVolumeMapping.clear();
    }

    private static class RemoteControllerWeak implements RemoteController.OnClientUpdateListener {
        private final WeakReference<Handler> mLocalHandler;

        public RemoteControllerWeak(Handler handler) {
            mLocalHandler = new WeakReference<Handler>(handler);
    private class MediaControllerListener extends MediaController.Callback {
        @Override
        public void onMetadataChanged(MediaMetadata metadata) {
            Log.v(TAG, "MediaController metadata changed");
            updateMetadata(metadata);
        }

        @Override
        public void onClientChange(boolean clearing) {
            Handler handler = mLocalHandler.get();
            if (handler != null) {
                handler.obtainMessage(MSG_SET_GENERATION_ID,
                        0, (clearing ? 1 : 0), null).sendToTarget();
            }
        public void onPlaybackStateChanged(PlaybackState state) {
            Log.v(TAG, "MediaController playback changed: " + state.toString());
            updatePlayPauseState(state);
        }

        @Override
        public void onClientPlaybackStateUpdate(int state) {
            // Should never be called with the existing code, but just in case
            if (DEBUG) Log.v(TAG, "RemoteControlDisplayer: Update playbackState state=" + state + " position=null");
            Handler handler = mLocalHandler.get();
            if (handler != null) {
                handler.obtainMessage(MSG_UPDATE_STATE, 0, state,
                        new Long(RemoteControlClient.PLAYBACK_POSITION_INVALID)).sendToTarget();
        public void onSessionDestroyed() {
            Log.v(TAG, "MediaController session destroyed");
        }
    }

        @Override
        public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
                long currentPosMs, float speed) {
            if (DEBUG) Log.v(TAG, "RemoteControlDisplayer: Update playbackState state=" + state + " position=" + currentPosMs);
            Handler handler = mLocalHandler.get();
            if (handler != null) {
                handler.obtainMessage(MSG_UPDATE_STATE, 0, state,
                        new Long(currentPosMs)).sendToTarget();
            }
    private class MediaSessionChangeListener implements MediaSessionManager.OnActiveSessionsChangedListener {
        public MediaSessionChangeListener() {
        }

        @Override
        public void onClientTransportControlUpdate(int transportControlFlags) {
            Handler handler = mLocalHandler.get();
            if (handler != null) {
                handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, 0, transportControlFlags)
                        .sendToTarget();
        public void onActiveSessionsChanged(List<MediaController> controllers) {
            Log.v(TAG, "Active sessions changed, " + controllers.size() + " sessions");
            if (controllers.size() > 0) {
                updateCurrentMediaController(controllers.get(0));
            }
        }
    }

        @Override
        public void onClientMetadataUpdate(MetadataEditor metadataEditor) {
            Log.v(TAG, "RemoteControlDisplayer: Update Metadata");
            Handler handler = mLocalHandler.get();
            if (handler != null) {
                handler.obtainMessage(MSG_SET_METADATA, 0, 0, metadataEditor).sendToTarget();
    private void updateCurrentMediaController(MediaController controller) {
        Log.v(TAG, "Updating media controller to " + controller + " from " +
                   controller.getPackageName());
        if (mMediaController != null) {
            mMediaController.unregisterCallback(mMediaControllerCb);
        }
        mMediaController = controller;
        if (mMediaController == null) {
            updateMetadata(null);
            updatePlayPauseState(null);
            return;
        }
        mMediaController.registerCallback(mMediaControllerCb, mHandler);
        updateMetadata(mMediaController.getMetadata());
        updatePlayPauseState(mMediaController.getPlaybackState());
    }

    /** Handles Avrcp messages. */
@@ -293,22 +287,6 @@ public final class Avrcp {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_UPDATE_STATE:
                updatePlayPauseState(msg.arg2, ((Long) msg.obj).longValue());
                break;

            case MSG_SET_METADATA:
                updateMetadata((MetadataEditor) msg.obj);
                break;

            case MSG_SET_TRANSPORT_CONTROLS:
                updateTransportControls(msg.arg2);
                break;

            case MSG_SET_GENERATION_ID:
                Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
                break;

            case MESSAGE_GET_RC_FEATURES:
                String address = (String) msg.obj;
                if (DEBUG) Log.v(TAG, "MESSAGE_GET_RC_FEATURES: address="+address+
@@ -397,8 +375,7 @@ public final class Avrcp {
                    }
                }

                if (mLocalVolume != volIndex &&
                                                   (msg.arg2 == AVRC_RSP_ACCEPT ||
                if (mLocalVolume != volIndex && (msg.arg2 == AVRC_RSP_ACCEPT ||
                                                 msg.arg2 == AVRC_RSP_CHANGED ||
                                                 msg.arg2 == AVRC_RSP_INTERIM)) {
                    /* If the volume has successfully changed */
@@ -569,22 +546,22 @@ public final class Avrcp {
            case MESSAGE_FAST_FORWARD:
            case MESSAGE_REWIND:
                if (msg.what == MESSAGE_FAST_FORWARD) {
                    if((mTransportControlFlags &
                        RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD) != 0) {
                    if ((mCurrentPlayState.getActions() &
                                PlaybackState.ACTION_FAST_FORWARD) != 0) {
                        int keyState = msg.arg1 == KEY_STATE_PRESS ?
                                KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
                        KeyEvent keyEvent =
                                new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
                    mRemoteController.sendMediaKeyEvent(keyEvent);
                        mMediaController.dispatchMediaButtonEvent(keyEvent);
                        break;
                    }
                } else if((mTransportControlFlags &
                        RemoteControlClient.FLAG_KEY_MEDIA_REWIND) != 0) {
                } else if ((mCurrentPlayState.getActions() &
                            PlaybackState.ACTION_REWIND) != 0) {
                    int keyState = msg.arg1 == KEY_STATE_PRESS ?
                            KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
                    KeyEvent keyEvent =
                            new KeyEvent(keyState, KeyEvent.KEYCODE_MEDIA_REWIND);
                    mRemoteController.sendMediaKeyEvent(keyEvent);
                    mMediaController.dispatchMediaButtonEvent(keyEvent);
                    break;
                }

@@ -642,40 +619,53 @@ public final class Avrcp {
        boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING);
        if (isPlaying != isPlayingState(mCurrentPlayState)) {
            /* if a2dp is streaming, check to make sure music is active */
            if ( (isPlaying) && !mAudioManager.isMusicActive())
            if (isPlaying && !mAudioManager.isMusicActive())
                return;
            updatePlayPauseState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING :
                                 RemoteControlClient.PLAYSTATE_PAUSED,
                                 RemoteControlClient.PLAYBACK_POSITION_INVALID);
            PlaybackState.Builder builder = new PlaybackState.Builder();
            if (isPlaying) {
                builder.setState(PlaybackState.STATE_PLAYING,
                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f);
            } else {
                builder.setState(PlaybackState.STATE_PAUSED,
                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f);
            }
            updatePlayPauseState(builder.build());
        }
    }

    private void updatePlayPauseState(int state, long currentPosMs) {
    private void updatePlayPauseState(PlaybackState state) {
        if (DEBUG) Log.v(TAG,
                "updatePlayPauseState, old=" + mCurrentPlayState + ", state=" + state);
        boolean oldPosValid = (mCurrentPosMs !=
                               RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN);
                "updatePlayPauseState: old=" + mCurrentPlayState + ", state=" + state);
        if (state == null) {
          state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE,
                         PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build();
        }
        boolean oldPosValid = (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN);
        int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState);
        int newPlayStatus = convertPlayStateToPlayStatus(state);

        if ((mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) &&
        if ((mCurrentPlayState.getState() == PlaybackState.STATE_PLAYING) &&
                (mCurrentPlayState != state) && oldPosValid) {
            mCurrentPosMs = getPlayPosition();
        }

        if (currentPosMs != RemoteControlClient.PLAYBACK_POSITION_INVALID) {
            mCurrentPosMs = currentPosMs;
        if (state.getState() == PlaybackState.STATE_NONE ||
                state.getState() == PlaybackState.STATE_ERROR) {
            mCurrentPosMs = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
        } else {
            mCurrentPosMs = state.getPosition();
        }
        if ((state == RemoteControlClient.PLAYSTATE_PLAYING) &&
            ((currentPosMs != RemoteControlClient.PLAYBACK_POSITION_INVALID) ||
            (mCurrentPlayState != RemoteControlClient.PLAYSTATE_PLAYING))) {

        if ((state.getState() == PlaybackState.STATE_PLAYING) &&
                (mCurrentPlayState.getState() != PlaybackState.STATE_PLAYING)) {
            mPlayStartTimeMs = SystemClock.elapsedRealtime();
        }

        mCurrentPlayState = state;

        boolean newPosValid = (mCurrentPosMs !=
                               RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN);
        boolean newPosValid = mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN;
        long playPosition = getPlayPosition();

        mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
        /* need send play position changed notification when play status is changed */
        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
@@ -685,7 +675,7 @@ public final class Avrcp {
            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPosition);
        }
        if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) && newPosValid &&
            (state == RemoteControlClient.PLAYSTATE_PLAYING)) {
                (state.getState() == PlaybackState.STATE_PLAYING)) {
            Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
            mHandler.sendMessageDelayed(msg, mNextPosMs - playPosition);
        }
@@ -717,11 +707,17 @@ public final class Avrcp {
        }
    }

    private void updateMetadata(MetadataEditor data) {
    private void updateMetadata(MediaMetadata data) {
        String oldMetadata = mMetadata.toString();
        mMetadata.artist = data.getString(MediaMetadataRetriever.METADATA_KEY_ARTIST, null);
        mMetadata.trackTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_TITLE, null);
        mMetadata.albumTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_ALBUM, null);
        if (data == null) {
            mMetadata = new Metadata();
            mSongLengthMs = 0L;
        } else {
            mMetadata.artist = data.getString(MediaMetadata.METADATA_KEY_ARTIST);
            mMetadata.trackTitle = data.getString(MediaMetadata.METADATA_KEY_TITLE);
            mMetadata.albumTitle = data.getString(MediaMetadata.METADATA_KEY_ALBUM);
            mSongLengthMs = data.getLong(MediaMetadata.METADATA_KEY_DURATION);
        }
        if (!oldMetadata.equals(mMetadata.toString())) {
            Log.v(TAG, "Metadata Changed to " + mMetadata.toString());
            mTrackNumber++;
@@ -730,11 +726,10 @@ public final class Avrcp {
                sendTrackChangedRsp();
            }

            if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
                if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
            if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN &&
                isPlayingState(mCurrentPlayState)) {
                mPlayStartTimeMs = SystemClock.elapsedRealtime();
            }
            }
            /* need send play position changed notification when track is changed */
            if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) {
                mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
@@ -743,11 +738,9 @@ public final class Avrcp {
                mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
            }
        } else {
          Log.v(TAG, "Metadata updated but no change!");
            Log.v(TAG, "Updated " + mMetadata.toString() + " but no change!");
        }

        mSongLengthMs = data.getLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
                RemoteControlClient.PLAYBACK_POSITION_INVALID);
    }

    private void getRcFeatures(byte[] address, int features) {
@@ -785,6 +778,7 @@ public final class Avrcp {
                break;

            case EVT_TRACK_CHANGED:
                Log.v(TAG, "Track changed notification enabled");
                mTrackChangedNT = NOTIFICATION_TYPE_INTERIM;
                sendTrackChangedRsp();
                break;
@@ -793,10 +787,10 @@ public final class Avrcp {
                long songPosition = getPlayPosition();
                mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM;
                mPlaybackIntervalMs = (long)param * 1000L;
                if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
                if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
                    mNextPosMs = songPosition + mPlaybackIntervalMs;
                    mPrevPosMs = songPosition - mPlaybackIntervalMs;
                    if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
                    if (isPlayingState(mCurrentPlayState)) {
                        Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
                        mHandler.sendMessageDelayed(msg, mPlaybackIntervalMs);
                    }
@@ -832,7 +826,7 @@ public final class Avrcp {
        long currentPosMs = getPlayPosition();
        if (currentPosMs == -1L) return;
        long newPosMs = Math.max(0L, currentPosMs + amount);
        mRemoteController.seekTo(newPosMs);
        mMediaController.getTransportControls().seekTo(newPosMs);
    }

    private int getSkipMultiplier() {
@@ -848,7 +842,8 @@ public final class Avrcp {
           0xFFFFFFFFFFFFFFFF in the interim response */
        long trackNumberRsp = -1L;

        if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
        if (mCurrentPlayState.getState() != PlaybackState.STATE_NONE &&
            mCurrentPlayState.getState() != PlaybackState.STATE_ERROR) {
            trackNumberRsp = mTrackNumber;
        }

@@ -861,8 +856,8 @@ public final class Avrcp {

    private long getPlayPosition() {
        long songPosition = -1L;
        if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
            if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
        if (mCurrentPosMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
            if (mCurrentPlayState.getState() == PlaybackState.STATE_PLAYING) {
                songPosition = SystemClock.elapsedRealtime() -
                        mPlayStartTimeMs + mCurrentPosMs;
            } else {
@@ -902,34 +897,35 @@ public final class Avrcp {
        return attrStr;
    }

    private int convertPlayStateToPlayStatus(int playState) {
    private int convertPlayStateToPlayStatus(PlaybackState state) {
        int playStatus = PLAYSTATUS_ERROR;
        switch (playState) {
            case RemoteControlClient.PLAYSTATE_PLAYING:
            case RemoteControlClient.PLAYSTATE_BUFFERING:
        switch (state.getState()) {
            case PlaybackState.STATE_PLAYING:
            case PlaybackState.STATE_BUFFERING:
                playStatus = PLAYSTATUS_PLAYING;
                break;

            case RemoteControlClient.PLAYSTATE_STOPPED:
            case RemoteControlClient.PLAYSTATE_NONE:
            case PlaybackState.STATE_STOPPED:
            case PlaybackState.STATE_NONE:
                playStatus = PLAYSTATUS_STOPPED;
                break;

            case RemoteControlClient.PLAYSTATE_PAUSED:
            case PlaybackState.STATE_PAUSED:
                playStatus = PLAYSTATUS_PAUSED;
                break;

            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
            case PlaybackState.STATE_FAST_FORWARDING:
            case PlaybackState.STATE_SKIPPING_TO_NEXT:
            case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
                playStatus = PLAYSTATUS_FWD_SEEK;
                break;

            case RemoteControlClient.PLAYSTATE_REWINDING:
            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
            case PlaybackState.STATE_REWINDING:
            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
                playStatus = PLAYSTATUS_REV_SEEK;
                break;

            case RemoteControlClient.PLAYSTATE_ERROR:
            case PlaybackState.STATE_ERROR:
                playStatus = PLAYSTATUS_ERROR;
                break;

@@ -937,18 +933,9 @@ public final class Avrcp {
        return playStatus;
    }

    private boolean isPlayingState(int playState) {
        boolean isPlaying = false;
        switch (playState) {
            case RemoteControlClient.PLAYSTATE_PLAYING:
            case RemoteControlClient.PLAYSTATE_BUFFERING:
                isPlaying = true;
                break;
            default:
                isPlaying = false;
                break;
        }
        return isPlaying;
    private boolean isPlayingState(PlaybackState state) {
        return (state.getState() == PlaybackState.STATE_PLAYING) ||
               (state.getState() == PlaybackState.STATE_BUFFERING);
    }

    /**