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 năm trước cách đây
mục cha
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();
             }
         }