Ensure ongoing progress updates after using the scroll ball to adjust position.

We use a single outstanding message of type SHOW_PROGRESS to refresh the progress
bar's current position as well as textual display of time and duration. This message
could get lost if the scroll ball was used to adjust the current playback position as
we entered state "mDragging" which would cause the subsequent SHOW_PROGRESS message
to be a no-op and would also cause it to not be re-enqueued.
The change refactors the seekbar logic a little and makes sure that while dragging
there isn't a pending SHOW_PROGRESS message in the queue and once dragging is over,
exactly one SHOW_PROGRESS message is reenqueued.

related to bug 1721227
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index b162a0e..0c9d980 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -444,27 +444,55 @@
         updatePausePlay();
     }
 
+    // There are two scenarios that can trigger the seekbar listener to trigger:
+    //
+    // The first is the user using the touchpad to adjust the posititon of the
+    // seekbar's thumb. In this case onStartTrackingTouch is called followed by
+    // a number of onProgressChanged notifications, concluded by onStopTrackingTouch.
+    // We're setting the field "mDragging" to true for the duration of the dragging
+    // session to avoid jumps in the position in case of ongoing playback.
+    //
+    // The second scenario involves the user operating the scroll ball, in this
+    // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications,
+    // we will simply apply the updated position without suspending regular updates.
     private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
-        long duration;
         public void onStartTrackingTouch(SeekBar bar) {
             show(3600000);
-            duration = mPlayer.getDuration();
+
+            mDragging = true;
+
+            // By removing these pending progress messages we make sure
+            // that a) we won't update the progress while the user adjusts
+            // the seekbar and b) once the user is done dragging the thumb
+            // we will post one of these messages to the queue again and
+            // this ensures that there will be exactly one message queued up.
+            mHandler.removeMessages(SHOW_PROGRESS);
         }
-        public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) {
-            if (fromtouch) {
-                mDragging = true;
-                duration = mPlayer.getDuration();
-                long newposition = (duration * progress) / 1000L;
-                mPlayer.seekTo( (int) newposition);
-                if (mCurrentTime != null)
-                    mCurrentTime.setText(stringForTime( (int) newposition));
+
+        public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
+            if (!fromuser) {
+                // We're not interested in programmatically generated changes to
+                // the progress bar's position.
+                return;
             }
+
+            long duration = mPlayer.getDuration();
+            long newposition = (duration * progress) / 1000L;
+            mPlayer.seekTo( (int) newposition);
+            if (mCurrentTime != null)
+                mCurrentTime.setText(stringForTime( (int) newposition));
         }
+
         public void onStopTrackingTouch(SeekBar bar) {
             mDragging = false;
             setProgress();
             updatePausePlay();
             show(sDefaultTimeout);
+
+            // Ensure that progress is properly updated in the future,
+            // the call to show() does not guarantee this because it is a
+            // no-op if we are already showing.
+            mHandler.sendEmptyMessage(SHOW_PROGRESS);
         }
     };