OSDN Git Service

Fix bugs in play status and play pos notifications
authorMarie Janssen <jamuraa@google.com>
Tue, 26 Jul 2016 23:23:54 +0000 (16:23 -0700)
committerMarie Janssen <jamuraa@google.com>
Mon, 1 Aug 2016 15:59:50 +0000 (08:59 -0700)
Fix multiple issues with status notificatios:
  * Playback state was not being sent when state wasn't sent
    accompanying a metadata change
  * Play state was being sent without an update
  * Position was being sent without a change and with the wrong
    indicator
  * Position was not being scheduled for update when playing.
  * Position was being scheduled for update when paused / stopped.

Bug: 30459664
Bug: 29400658
Bug: 28639383
Change-Id: Ic550dcab0430be45187b0267cc77875740388a2a
(cherry picked from commit fa81085f6cda571d56c62eb1d646ae4a52cb90ee)

src/com/android/bluetooth/avrcp/Avrcp.java

index 6ce7123..57c98a8 100755 (executable)
@@ -85,6 +85,7 @@ public final class Avrcp {
     private long mTrackNumber;
     private long mSongLengthMs;
     private long mPlaybackIntervalMs;
+    private long mLastReportedPosition;
     private long mNextPosMs;
     private long mPrevPosMs;
     private long mSkipStartTime;
@@ -163,6 +164,7 @@ public final class Avrcp {
         mSongLengthMs = 0L;
         mPlaybackIntervalMs = 0L;
         mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
+        mLastReportedPosition = -1;
         mNextPosMs = -1;
         mPrevPosMs = -1;
         mFeatures = 0;
@@ -634,21 +636,27 @@ public final class Avrcp {
     }
 
     private void updatePlaybackState(PlaybackState state) {
-        if (DEBUG) Log.v(TAG,
-                "updatePlaybackState: old=" + mCurrentPlayState + ", new=" + state);
         if (state == null) {
           state = new PlaybackState.Builder().setState(PlaybackState.STATE_NONE,
                          PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f).build();
         }
 
+        int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState);
         int newPlayStatus = convertPlayStateToPlayStatus(state);
 
+        if (DEBUG) {
+            Log.v(TAG, "updatePlaybackState (" + mPlayStatusChangedNT + "): "+
+                       "old=" + mCurrentPlayState + "(" + oldPlayStatus + "), "+
+                       "new=" + state + "(" + newPlayStatus + ")");
+        }
+
         mCurrentPlayState = state;
         mLastStateUpdate = SystemClock.elapsedRealtime();
 
         sendPlayPosNotificationRsp(false);
 
-        if (mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) {
+        if (mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM &&
+            (oldPlayStatus != newPlayStatus)) {
             mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
             registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus);
         }
@@ -778,14 +786,6 @@ public final class Avrcp {
             Log.v(TAG, "MediaAttributes Changed to " + mMediaAttributes.toString());
             mTrackNumber++;
 
-            // Update the play state, which sends play state and play position
-            // notifications if needed.
-            if (mMediaController != null) {
-              updatePlaybackState(mMediaController.getPlaybackState());
-            } else {
-              updatePlaybackState(null);
-            }
-
             if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) {
                 mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
                 sendTrackChangedRsp();
@@ -794,6 +794,13 @@ public final class Avrcp {
             Log.v(TAG, "Updated " + mMediaAttributes.toString() + " but no change!");
         }
 
+        // Update the play state, which sends play state and play position
+        // notifications if needed.
+        if (mMediaController != null) {
+          updatePlaybackState(mMediaController.getPlaybackState());
+        } else {
+          updatePlaybackState(null);
+        }
     }
 
     private void getRcFeatures(byte[] address, int features) {
@@ -837,8 +844,8 @@ public final class Avrcp {
 
             case EVT_PLAY_POS_CHANGED:
                 mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM;
-                sendPlayPosNotificationRsp(true);
                 mPlaybackIntervalMs = (long)param * 1000L;
+                sendPlayPosNotificationRsp(true);
                 break;
 
         }
@@ -958,6 +965,11 @@ public final class Avrcp {
      * TG.
      */
     private void sendPlayPosNotificationRsp(boolean requested) {
+        if (!requested && mPlayPosChangedNT != NOTIFICATION_TYPE_INTERIM) {
+            if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: Not registered or requesting.");
+            return;
+        }
+
         long playPositionMs = getPlayPosition();
 
         // mNextPosMs is set to -1 when the previous position was invalid
@@ -965,10 +977,13 @@ public final class Avrcp {
         // mPlayPositionMs is set to -1 when the new position is invalid,
         // and the old mPrevPosMs is >= 0 so this is true when the new is invalid
         // and the old was valid.
-        if (requested || ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
-             ((playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs)))) {
+        if (DEBUG) Log.d(TAG, "sendPlayPosNotificationRsp: (" + requested + ") "
+            + mPrevPosMs + " <=? " + playPositionMs + " <=? " + mNextPosMs);
+        if (requested || ((mLastReportedPosition != playPositionMs) &&
+              (playPositionMs >= mNextPosMs) || (playPositionMs <= mPrevPosMs))) {
             if (!requested) mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
-            registerNotificationRspPlayPosNative(mPlayStatusChangedNT, (int)playPositionMs);
+            registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPositionMs);
+            mLastReportedPosition = playPositionMs;
             if (playPositionMs != PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
                 mNextPosMs = playPositionMs + mPlaybackIntervalMs;
                 mPrevPosMs = playPositionMs - mPlaybackIntervalMs;
@@ -979,12 +994,13 @@ public final class Avrcp {
         }
 
         mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
-        if (mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) {
+        if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM && isPlayingState(mCurrentPlayState)) {
             Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
             long delay = mPlaybackIntervalMs;
             if (mNextPosMs != -1) {
                 delay = mNextPosMs - (playPositionMs > 0 ? playPositionMs : 0);
             }
+            if (DEBUG) Log.d(TAG, "PLAY_INTERVAL_TIMEOUT set for " + delay + "ms from now");
             mHandler.sendMessageDelayed(msg, delay);
         }
     }