Browse Source

Improving our own media control: removed 'next' and 'previous' buttons, removed undesired 'show' and 'hide' behaviour, fixed update of progress bar, recovered BACK button

David A. Velasco 12 years ago
parent
commit
ca8a19850b

+ 0 - 10
res/layout/media_control.xml

@@ -32,11 +32,6 @@
         android:orientation="horizontal"
         >
 
-        <ImageButton 
-            android:id="@+id/previousBtn" 
-            style="@android:style/MediaButton.Previous" 
-            android:contentDescription="@string/media_previous_description"
-            />
         <ImageButton 
             android:id="@+id/rewindBtn" 
             style="@android:style/MediaButton.Rew" 
@@ -52,11 +47,6 @@
             style="@android:style/MediaButton.Ffwd" 
             android:contentDescription="@string/media_forward_description"
             />
-        <ImageButton 
-            android:id="@+id/nextBtn" 
-            style="@android:style/MediaButton.Next" 
-            android:contentDescription="@string/media_next_description"
-            />
 
     </LinearLayout>
 

+ 86 - 304
src/com/owncloud/android/media/MediaControlView.java

@@ -19,23 +19,15 @@
 package com.owncloud.android.media;
 
 import android.content.Context;
-import android.graphics.PixelFormat;
-import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnLayoutChangeListener;
-import android.view.View.OnTouchListener;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
@@ -63,52 +55,29 @@ import com.owncloud.android.R;
  * @author David A. Velasco
  */
 
-public class MediaControlView extends FrameLayout implements /* OnLayoutChangeListener, */ OnTouchListener {
+public class MediaControlView extends FrameLayout /* implements OnLayoutChangeListener, OnTouchListener */ implements OnClickListener, OnSeekBarChangeListener {
 
-    private static final String TAG = MediaControlView.class.getSimpleName();
-
-    
     private MediaPlayerControl  mPlayer;
     private Context             mContext;
-    private View                mAnchor;
     private View                mRoot;
-    private WindowManager       mWindowManager;
-    //private Window              mWindow;
-    private View                mDecor;
-    private WindowManager.LayoutParams mDecorLayoutParams;
     private ProgressBar         mProgress;
     private TextView            mEndTime, mCurrentTime;
-    private boolean             mShowing;
     private boolean             mDragging;
-    private static final int    sDefaultTimeout = 3000;
-    private static final int    FADE_OUT = 1;
-    private static final int    SHOW_PROGRESS = 2;
-    private boolean             mUseFastForward;
-    private boolean             mFromXml;
-    private boolean             mListenersSet;
-    private View.OnClickListener mNextListener, mPrevListener;
+    private static final int    SHOW_PROGRESS = 1;
     StringBuilder               mFormatBuilder;
     Formatter                   mFormatter;
     private ImageButton         mPauseButton;
     private ImageButton         mFfwdButton;
     private ImageButton         mRewButton;
-    private ImageButton         mNextButton;
-    private ImageButton         mPrevButton;
     
     public MediaControlView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        //mRoot = this;           // TODO review if this is adequate
         mContext = context;
-        mUseFastForward = true;
-        mFromXml = true;
-        
-        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
         
         FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT
         );
-        //removeAllViews();
         LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mRoot = inflate.inflate(R.layout.media_control, null);
         initControllerView(mRoot);
@@ -122,8 +91,10 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
 
     @Override
     public void onFinishInflate() {
+        /*
         if (mRoot != null)
             initControllerView(mRoot);
+         */
     }
 
     /* TODO REMOVE
@@ -186,6 +157,7 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
 
     // Update the dynamic parts of mDecorLayoutParams
     // Must be called with mAnchor != NULL.
+    /*
     private void updateFloatingWindowLayout() {
         int [] anchorPos = new int[2];
         mAnchor.getLocationOnScreen(anchorPos);
@@ -194,6 +166,7 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
         p.width = mAnchor.getWidth();
         p.y = anchorPos[1] + mAnchor.getHeight();
     }
+    */
 
     /*
     // This is called whenever mAnchor's layout bound changes
@@ -207,6 +180,7 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
     }
     */
     
+    /*
     public boolean onTouch(View v, MotionEvent event) {
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
             if (mShowing) {
@@ -215,94 +189,38 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
         }
             return false;
     }
+    */
     
     
     public void setMediaPlayer(MediaPlayerControl player) {
         mPlayer = player;
+        mHandler.sendEmptyMessage(SHOW_PROGRESS);
         updatePausePlay();
     }
 
-    /*
-    /**
-     * Set the view that acts as the anchor for the control view.
-     * This can for example be a VideoView, or your Activity's main view.
-     * @param view The view to which to anchor the controller when it is visible.
-     *-/
-    public void setAnchorView(View view) {
-        if (mAnchor != null) {
-            mAnchor.removeOnLayoutChangeListener(this);
-        }
-        mAnchor = view;
-        if (mAnchor != null) {
-            mAnchor.addOnLayoutChangeListener(this);
-        }
-
-        FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT
-        );
-
-        removeAllViews();
-        View v = makeControllerView();
-        addView(v, frameParams);
-    }
-    */
     
-    /*
-    /**
-     * Create the view that holds the widgets that control playback.
-     * Derived classes can override this to create their own.
-     * @return The controller view.
-     * @hide This doesn't work as advertised
-     *-/
-    protected View makeControllerView() {
-        LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mRoot = inflate.inflate(R.layout.media_control, null);
-
-        initControllerView(mRoot);
-
-        return mRoot;
-    }
-    */
-
     private void initControllerView(View v) {
         mPauseButton = (ImageButton) v.findViewById(R.id.playBtn);
         if (mPauseButton != null) {
             mPauseButton.requestFocus();
-            mPauseButton.setOnClickListener(mPauseListener);
+            mPauseButton.setOnClickListener(this);
         }
 
         mFfwdButton = (ImageButton) v.findViewById(R.id.forwardBtn);
         if (mFfwdButton != null) {
-            mFfwdButton.setOnClickListener(mFfwdListener);
-            if (!mFromXml) {
-                mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
-            }
+            mFfwdButton.setOnClickListener(this);
         }
 
         mRewButton = (ImageButton) v.findViewById(R.id.rewindBtn);
         if (mRewButton != null) {
-            mRewButton.setOnClickListener(mRewListener);
-            if (!mFromXml) {
-                mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
-            }
-        }
-
-        // By default these are hidden. They will be enabled when setPrevNextListeners() is called 
-        mNextButton = (ImageButton) v.findViewById(R.id.nextBtn);
-        if (mNextButton != null && !mFromXml && !mListenersSet) {
-            mNextButton.setVisibility(View.GONE);
-        }
-        mPrevButton = (ImageButton) v.findViewById(R.id.previousBtn);
-        if (mPrevButton != null && !mFromXml && !mListenersSet) {
-            mPrevButton.setVisibility(View.GONE);
+            mRewButton.setOnClickListener(this);
         }
 
         mProgress = (ProgressBar) v.findViewById(R.id.progressBar);
         if (mProgress != null) {
             if (mProgress instanceof SeekBar) {
                 SeekBar seeker = (SeekBar) mProgress;
-                seeker.setOnSeekBarChangeListener(mSeekListener);
+                seeker.setOnSeekBarChangeListener(this);
             }
             mProgress.setMax(1000);
         }
@@ -312,17 +230,9 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
         mFormatBuilder = new StringBuilder();
         mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
 
-        installPrevNextListeners();
-    }
-
-    /**
-     * Show the controller on screen. It will go away
-     * automatically after 3 seconds of inactivity.
-     */
-    public void show() {
-        show(sDefaultTimeout);
     }
 
+    
     /**
      * Disable pause or seek buttons if the stream cannot be paused or seeked.
      * This requires the control interface to be a MediaPlayerControlExt
@@ -346,72 +256,15 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
         }
     }
     
-    /**
-     * Show the controller on screen. It will go away
-     * automatically after 'timeout' milliseconds of inactivity.
-     * @param timeout The timeout in milliseconds. Use 0 to show
-     * the controller until hide() is called.
-     */
-    public void show(int timeout) {
-        if (!mShowing && mAnchor != null) {
-            setProgress();
-            if (mPauseButton != null) {
-                mPauseButton.requestFocus();
-            }
-            disableUnsupportedButtons();
-            //updateFloatingWindowLayout();
-            mWindowManager.addView(mDecor, mDecorLayoutParams);
-            mShowing = true;
-        }
-        updatePausePlay();
-        
-        // cause the progress bar to be updated even if mShowing
-        // was already true.  This happens, for example, if we're
-        // paused with the progress bar showing the user hits play.
-        mHandler.sendEmptyMessage(SHOW_PROGRESS);
-
-        Message msg = mHandler.obtainMessage(FADE_OUT);
-        if (timeout != 0) {
-            mHandler.removeMessages(FADE_OUT);
-            mHandler.sendMessageDelayed(msg, timeout);
-        }
-    }
     
-    public boolean isShowing() {
-        return mShowing;
-    }
-
-    /**
-     * Remove the controller from the screen.
-     */
-    public void hide() {
-        /*
-        if (mAnchor == null)
-            return;
-
-        if (mShowing) {
-            try {
-                mHandler.removeMessages(SHOW_PROGRESS);
-                mWindowManager.removeView(mDecor);
-            } catch (IllegalArgumentException ex) {
-                Log.w(TAG, "already removed");
-            }
-            mShowing = false;
-        }
-        */
-    }
-
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             int pos;
             switch (msg.what) {
-                case FADE_OUT:
-                    hide();
-                    break;
                 case SHOW_PROGRESS:
                     pos = setProgress();
-                    if (!mDragging && mShowing && mPlayer.isPlaying()) {
+                    if (!mDragging) {
                         msg = obtainMessage(SHOW_PROGRESS);
                         sendMessageDelayed(msg, 1000 - (pos % 1000));
                     }
@@ -458,18 +311,7 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
 
         return position;
     }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        show(sDefaultTimeout);
-        return true;
-    }
-
-    @Override
-    public boolean onTrackballEvent(MotionEvent ev) {
-        show(sDefaultTimeout);
-        return false;
-    }
+    
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
@@ -481,7 +323,7 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
                 || keyCode == KeyEvent.KEYCODE_SPACE) {
             if (uniqueDown) {
                 doPauseResume();
-                show(sDefaultTimeout);
+                //show(sDefaultTimeout);
                 if (mPauseButton != null) {
                     mPauseButton.requestFocus();
                 }
@@ -491,7 +333,7 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
             if (uniqueDown && !mPlayer.isPlaying()) {
                 mPlayer.start();
                 updatePausePlay();
-                show(sDefaultTimeout);
+                //show(sDefaultTimeout);
             }
             return true;
         } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
@@ -499,34 +341,16 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
             if (uniqueDown && mPlayer.isPlaying()) {
                 mPlayer.pause();
                 updatePausePlay();
-                show(sDefaultTimeout);
-            }
-            return true;
-        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                || keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE
-                || keyCode == KeyEvent.KEYCODE_CAMERA) {
-            // don't show the controls for volume adjustment
-            return super.dispatchKeyEvent(event);
-        } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
-            if (uniqueDown) {
-                hide();
+                //show(sDefaultTimeout);
             }
             return true;
         }
 
-        show(sDefaultTimeout);
+        //show(sDefaultTimeout);
         return super.dispatchKeyEvent(event);
     }
 
-    private View.OnClickListener mPauseListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            doPauseResume();
-            show(sDefaultTimeout);
-        }
-    };
-
-    private void updatePausePlay() {
+    public void updatePausePlay() {
         if (mRoot == null || mPauseButton == null)
             return;
 
@@ -546,58 +370,6 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
         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() {
-        public void onStartTrackingTouch(SeekBar bar) {
-            show(3600000);
-
-            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 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);
-        }
-    };
-
     @Override
     public void setEnabled(boolean enabled) {
         if (mPauseButton != null) {
@@ -609,12 +381,6 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
         if (mRewButton != null) {
             mRewButton.setEnabled(enabled);
         }
-        if (mNextButton != null) {
-            mNextButton.setEnabled(enabled && mNextListener != null);
-        }
-        if (mPrevButton != null) {
-            mPrevButton.setEnabled(enabled && mPrevListener != null);
-        }
         if (mProgress != null) {
             mProgress.setEnabled(enabled);
         }
@@ -623,66 +389,82 @@ public class MediaControlView extends FrameLayout implements /* OnLayoutChangeLi
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(MediaControlView.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(MediaControlView.class.getName());
-    }
+    public void onClick(View v) {
+        int pos;
+        switch (v.getId()) {
+        
+        case R.id.playBtn: 
+            doPauseResume();
+            break;
 
-    private View.OnClickListener mRewListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            int pos = mPlayer.getCurrentPosition();
-            pos -= 5000; // milliseconds
+        case R.id.rewindBtn:
+            pos = mPlayer.getCurrentPosition();
+            pos -= 5000;
             mPlayer.seekTo(pos);
             setProgress();
+            break;
 
-            show(sDefaultTimeout);
-        }
-    };
-
-    private View.OnClickListener mFfwdListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            int pos = mPlayer.getCurrentPosition();
-            pos += 15000; // milliseconds
+        case R.id.forwardBtn:
+            pos = mPlayer.getCurrentPosition();
+            pos += 15000;
             mPlayer.seekTo(pos);
             setProgress();
-
-            show(sDefaultTimeout);
+            break;
+        
         }
-    };
-
-    private void installPrevNextListeners() {
-        if (mNextButton != null) {
-            mNextButton.setOnClickListener(mNextListener);
-            mNextButton.setEnabled(mNextListener != null);
+    }
+    
+    
+    @Override
+    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+        if (!fromUser) {
+            // We're not interested in programmatically generated changes to
+            // the progress bar's position.
+            return;
         }
 
-        if (mPrevButton != null) {
-            mPrevButton.setOnClickListener(mPrevListener);
-            mPrevButton.setEnabled(mPrevListener != null);
-        }
+        long duration = mPlayer.getDuration();
+        long newposition = (duration * progress) / 1000L;
+        mPlayer.seekTo( (int) newposition);
+        if (mCurrentTime != null)
+            mCurrentTime.setText(stringForTime( (int) newposition));
+    }
+    
+    /**
+     * Called in devices with touchpad when the user starts to adjust the 
+     * position of the seekbar's thumb.
+     * 
+     * Will be followed by several onProgressChanged notifications.
+     */
+    @Override
+    public void onStartTrackingTouch(SeekBar seekBar) {
+        mDragging = true;                           // monitors the duration of dragging 
+        mHandler.removeMessages(SHOW_PROGRESS);     // grants no more updates with media player progress while dragging 
     }
 
-    public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) {
-        mNextListener = next;
-        mPrevListener = prev;
-        mListenersSet = true;
+    
+    /**
+     * Called in devices with touchpad when the user finishes the
+     * adjusting of the seekbar.
+     */
+    @Override
+    public void onStopTrackingTouch(SeekBar seekBar) {
+        mDragging = false;
+        setProgress();
+        updatePausePlay();
+        mHandler.sendEmptyMessage(SHOW_PROGRESS);    // grants future updates with media player progress 
+    }
 
-        if (mRoot != null) {
-            installPrevNextListeners();
-            
-            if (mNextButton != null && !mFromXml) {
-                mNextButton.setVisibility(View.VISIBLE);
-            }
-            if (mPrevButton != null && !mFromXml) {
-                mPrevButton.setVisibility(View.VISIBLE);
-            }
-        }
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setClassName(MediaControlView.class.getName());
     }
 
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setClassName(MediaControlView.class.getName());
+    }
+    
 }

+ 10 - 13
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -329,18 +329,13 @@ public class PreviewMediaFragment extends SherlockFragment implements
     }
     
     private void playVideo() {
+        // create and prepare control panel for the user
+        mMediaController.setMediaPlayer(mVideoPreview);
+        
         // load the video file in the video player ; when done, VideoHelper#onPrepared() will be called
         mVideoPreview.setVideoPath(mFile.getStoragePath()); 
 
-        // create and prepare control panel for the user
-        //mMediaController = new MediaController(getActivity());
-        if (mMediaController != null) {
-            mMediaController.setMediaPlayer(mVideoPreview);
-            //mMediaController.setAnchorView(mVideoPreview);
-            //mVideoPreview.setMediaController(mMediaController);
-        } else {
-            Toast.makeText(getActivity(), "No media controller to play video", Toast.LENGTH_SHORT).show();
-        }
+        //mVideoPreview.setMediaController(mMediaController);
     }
     
 
@@ -357,6 +352,8 @@ public class PreviewMediaFragment extends SherlockFragment implements
         public void onPrepared(MediaPlayer vp) {
             mVideoPreview.seekTo(mSavedPlaybackPosition);
             mVideoPreview.start();
+            mMediaController.setEnabled(true);
+            mMediaController.updatePausePlay();
             //mMediaController.show(MediaService.MEDIA_CONTROL_SHORT_LIFE);  
         }
         
@@ -486,6 +483,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
             if (!mMediaServiceBinder.isPlaying()) {
                 mMediaServiceBinder.start();
             }
+            /*
             if (!mMediaController.isShowing() && isVisible()) {
                 //mMediaController.show(MediaService.MEDIA_CONTROL_PERMANENT);
                 // TODO - fix strange bug; steps to trigger :
@@ -495,6 +493,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
                 // 4. go to notification bar and click on the "ownCloud music app" notification
                 // PUM!
             }
+            */
         }
     }
 
@@ -540,10 +539,8 @@ public class PreviewMediaFragment extends SherlockFragment implements
             //mMediaServiceBinder.registerMediaController(mMediaController);
             if (mMediaController != null) {
                 mMediaController.setMediaPlayer(mMediaServiceBinder);
-                //mMediaController.setAnchorView(getView());
-                mMediaController.setEnabled(mMediaServiceBinder.isInPlaybackState());
-            } else {
-                Toast.makeText(getActivity(), "No media controller to prepare when connected to media service", Toast.LENGTH_SHORT).show();
+                mMediaController.setEnabled(true);
+                mMediaController.updatePausePlay();
             }
         }