Advertisement
Guest User

Vitamio's MediaController.java

a guest
Aug 30th, 2016
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 15.64 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2006 The Android Open Source Project
  3.  * Copyright (C) 2013 YIXIA.COM
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17.  
  18. package io.vov.vitamio.widget;
  19.  
  20. import android.annotation.SuppressLint;
  21. import android.annotation.TargetApi;
  22. import android.content.Context;
  23. import android.graphics.Rect;
  24. import android.media.AudioManager;
  25. import android.os.Build;
  26. import android.os.Handler;
  27. import android.os.Message;
  28. import android.util.AttributeSet;
  29. import android.view.Gravity;
  30. import android.view.KeyEvent;
  31. import android.view.LayoutInflater;
  32. import android.view.MotionEvent;
  33. import android.view.View;
  34. import android.view.WindowManager;
  35. import android.widget.FrameLayout;
  36. import android.widget.ImageButton;
  37. import android.widget.PopupWindow;
  38. import android.widget.SeekBar;
  39. import android.widget.SeekBar.OnSeekBarChangeListener;
  40. import android.widget.TextView;
  41.  
  42. import java.lang.reflect.Method;
  43.  
  44. import io.vov.vitamio.utils.Log;
  45. import io.vov.vitamio.utils.StringUtils;
  46.  
  47. /**
  48.  * A view containing controls for a MediaPlayer. Typically contains the buttons
  49.  * like "Play/Pause" and a progress slider. It takes care of synchronizing the
  50.  * controls with the state of the MediaPlayer.
  51.  * <p/>
  52.  * The way to use this class is to a) instantiate it programatically or b)
  53.  * create it in your xml layout.
  54.  * <p/>
  55.  * a) The MediaController will create a default set of controls and put them in
  56.  * a window floating above your application. Specifically, the controls will
  57.  * float above the view specified with setAnchorView(). By default, the window
  58.  * will disappear if left idle for three seconds and reappear when the user
  59.  * touches the anchor view. To customize the MediaController's style, layout and
  60.  * controls you should extend MediaController and override the {#link
  61.  * {@link #makeControllerView()} method.
  62.  * <p/>
  63.  * b) The MediaController is a FrameLayout, you can put it in your layout xml
  64.  * and get it through {@link #findViewById(int)}.
  65.  * <p/>
  66.  * NOTES: In each way, if you want customize the MediaController, the SeekBar's
  67.  * id must be mediacontroller_progress, the Play/Pause's must be
  68.  * mediacontroller_pause, current time's must be mediacontroller_time_current,
  69.  * total time's must be mediacontroller_time_total, file name's must be
  70.  * mediacontroller_file_name. And your resources must have a pause_button
  71.  * drawable and a play_button drawable.
  72.  * <p/>
  73.  * Functions like show() and hide() have no effect when MediaController is
  74.  * created in an xml layout.
  75.  */
  76. public class MediaController extends FrameLayout {
  77.   private static final int sDefaultTimeout = 3000;
  78.   private static final int FADE_OUT = 1;
  79.   private static final int SHOW_PROGRESS = 2;
  80.   private MediaPlayerControl mPlayer;
  81.   private Context mContext;
  82.   private PopupWindow mWindow;
  83.   private int mAnimStyle;
  84.   private View mAnchor;
  85.   private View mRoot;
  86.   private SeekBar mProgress;
  87.   private TextView mEndTime, mCurrentTime;
  88.   private TextView mFileName;
  89.   private OutlineTextView mInfoView;
  90.   private String mTitle;
  91.   private long mDuration;
  92.   private boolean mShowing;
  93.   private boolean mDragging;
  94.   private boolean mInstantSeeking = false;
  95.   private boolean mFromXml = false;
  96.   private ImageButton mPauseButton;
  97.   private AudioManager mAM;
  98.   private OnShownListener mShownListener;
  99.   private OnHiddenListener mHiddenListener;
  100.   @SuppressLint("HandlerLeak")
  101.   private Handler mHandler = new Handler() {
  102.     @Override
  103.     public void handleMessage(Message msg) {
  104.       long pos;
  105.       switch (msg.what) {
  106.         case FADE_OUT:
  107.           hide();
  108.           break;
  109.         case SHOW_PROGRESS:
  110.           pos = setProgress();
  111.           if (!mDragging && mShowing) {
  112.             msg = obtainMessage(SHOW_PROGRESS);
  113.             sendMessageDelayed(msg, 1000 - (pos % 1000));
  114.             updatePausePlay();
  115.           }
  116.           break;
  117.       }
  118.     }
  119.   };
  120.   private View.OnClickListener mPauseListener = new View.OnClickListener() {
  121.     public void onClick(View v) {
  122.       doPauseResume();
  123.       show(sDefaultTimeout);
  124.     }
  125.   };
  126.   private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
  127.     public void onStartTrackingTouch(SeekBar bar) {
  128.       mDragging = true;
  129.       show(3600000);
  130.       mHandler.removeMessages(SHOW_PROGRESS);
  131.       if (mInstantSeeking)
  132.         mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
  133.       if (mInfoView != null) {
  134.         mInfoView.setText("");
  135.         mInfoView.setVisibility(View.VISIBLE);
  136.       }
  137.     }
  138.  
  139.     public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
  140.       if (!fromuser)
  141.         return;
  142.  
  143.       long newposition = (mDuration * progress) / 1000;
  144.       String time = StringUtils.generateTime(newposition);
  145.       if (mInstantSeeking)
  146.         mPlayer.seekTo(newposition);
  147.       if (mInfoView != null)
  148.         mInfoView.setText(time);
  149.       if (mCurrentTime != null)
  150.         mCurrentTime.setText(time);
  151.     }
  152.  
  153.     public void onStopTrackingTouch(SeekBar bar) {
  154.       if (!mInstantSeeking)
  155.         mPlayer.seekTo((mDuration * bar.getProgress()) / 1000);
  156.       if (mInfoView != null) {
  157.         mInfoView.setText("");
  158.         mInfoView.setVisibility(View.GONE);
  159.       }
  160.       show(sDefaultTimeout);
  161.       mHandler.removeMessages(SHOW_PROGRESS);
  162.       mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
  163.       mDragging = false;
  164.       mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
  165.     }
  166.   };
  167.  
  168.   public MediaController(Context context, AttributeSet attrs) {
  169.     super(context, attrs);
  170.     mRoot = this;
  171.     mFromXml = true;
  172.     initController(context);
  173.   }
  174.  
  175.   public MediaController(Context context) {
  176.     super(context);
  177.     if (!mFromXml && initController(context))
  178.       initFloatingWindow();
  179.   }
  180.  
  181.   private boolean initController(Context context) {
  182.     mContext = context;
  183.     mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
  184.     return true;
  185.   }
  186.  
  187.   @Override
  188.   public void onFinishInflate() {
  189.     if (mRoot != null)
  190.       initControllerView(mRoot);
  191.   }
  192.  
  193.   private void initFloatingWindow() {
  194.     mWindow = new PopupWindow(mContext);
  195.     mWindow.setFocusable(false);
  196.     mWindow.setBackgroundDrawable(null);
  197.     mWindow.setOutsideTouchable(true);
  198.     mAnimStyle = android.R.style.Animation;
  199.   }
  200.  
  201.   @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  202.     public void setWindowLayoutType() {
  203.         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
  204.             try {
  205.                 mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
  206.                 Method setWindowLayoutType = PopupWindow.class.getMethod("setWindowLayoutType", new Class[] { int.class });
  207.                 setWindowLayoutType.invoke(mWindow, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
  208.             } catch (Exception e) {
  209.                 Log.e("setWindowLayoutType", e);
  210.             }
  211.         }
  212.     }
  213.  
  214.   /**
  215.    * Set the view that acts as the anchor for the control view. This can for
  216.    * example be a VideoView, or your Activity's main view.
  217.    *
  218.    * @param view The view to which to anchor the controller when it is visible.
  219.    */
  220.   public void setAnchorView(View view) {
  221.     mAnchor = view;
  222.     if (!mFromXml) {
  223.       removeAllViews();
  224.       mRoot = makeControllerView();
  225.       mWindow.setContentView(mRoot);
  226.       mWindow.setWidth(LayoutParams.MATCH_PARENT);
  227.       mWindow.setHeight(LayoutParams.WRAP_CONTENT);
  228.     }
  229.     initControllerView(mRoot);
  230.   }
  231.  
  232.   /**
  233.    * Create the view that holds the widgets that control playback. Derived
  234.    * classes can override this to create their own.
  235.    *
  236.    * @return The controller view.
  237.    */
  238.   protected View makeControllerView() {
  239.     return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(getResources().getIdentifier("mediacontroller", "layout", mContext.getPackageName()), this);
  240.   }
  241.  
  242.   private void initControllerView(View v) {
  243.     mPauseButton = (ImageButton) v.findViewById(getResources().getIdentifier("mediacontroller_play_pause", "id", mContext.getPackageName()));
  244.     if (mPauseButton != null) {
  245.       mPauseButton.requestFocus();
  246.       mPauseButton.setOnClickListener(mPauseListener);
  247.     }
  248.  
  249.     mProgress = (SeekBar) v.findViewById(getResources().getIdentifier("mediacontroller_seekbar", "id", mContext.getPackageName()));
  250.     if (mProgress != null) {
  251.       if (mProgress instanceof SeekBar) {
  252.         SeekBar seeker = (SeekBar) mProgress;
  253.         seeker.setOnSeekBarChangeListener(mSeekListener);
  254.       }
  255.       mProgress.setMax(1000);
  256.     }
  257.  
  258.     mEndTime = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_time_total", "id", mContext.getPackageName()));
  259.     mCurrentTime = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_time_current", "id", mContext.getPackageName()));
  260.     mFileName = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_file_name", "id", mContext.getPackageName()));
  261.     if (mFileName != null)
  262.       mFileName.setText(mTitle);
  263.   }
  264.  
  265.   public void setMediaPlayer(MediaPlayerControl player) {
  266.     mPlayer = player;
  267.     updatePausePlay();
  268.   }
  269.  
  270.   /**
  271.    * Control the action when the seekbar dragged by user
  272.    *
  273.    * @param seekWhenDragging True the media will seek periodically
  274.    */
  275.   public void setInstantSeeking(boolean seekWhenDragging) {
  276.     mInstantSeeking = seekWhenDragging;
  277.   }
  278.  
  279.   public void show() {
  280.     show(sDefaultTimeout);
  281.   }
  282.  
  283.   /**
  284.    * Set the content of the file_name TextView
  285.    *
  286.    * @param name
  287.    */
  288.   public void setFileName(String name) {
  289.     mTitle = name;
  290.     if (mFileName != null)
  291.       mFileName.setText(mTitle);
  292.   }
  293.  
  294.   /**
  295.    * Set the View to hold some information when interact with the
  296.    * MediaController
  297.    *
  298.    * @param v
  299.    */
  300.   public void setInfoView(OutlineTextView v) {
  301.     mInfoView = v;
  302.   }
  303.  
  304.   /**
  305.    * <p>
  306.    * Change the animation style resource for this controller.
  307.    * </p>
  308.    * <p/>
  309.    * <p>
  310.    * If the controller is showing, calling this method will take effect only the
  311.    * next time the controller is shown.
  312.    * </p>
  313.    *
  314.    * @param animationStyle animation style to use when the controller appears
  315.    *                       and disappears. Set to -1 for the default animation, 0 for no animation, or
  316.    *                       a resource identifier for an explicit animation.
  317.    */
  318.   public void setAnimationStyle(int animationStyle) {
  319.     mAnimStyle = animationStyle;
  320.   }
  321.  
  322.   /**
  323.    * Show the controller on screen. It will go away automatically after
  324.    * 'timeout' milliseconds of inactivity.
  325.    *
  326.    * @param timeout The timeout in milliseconds. Use 0 to show the controller
  327.    *                until hide() is called.
  328.    */
  329.   public void show(int timeout) {
  330.     if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) {
  331.       if (mPauseButton != null)
  332.         mPauseButton.requestFocus();
  333.  
  334.       if (mFromXml) {
  335.         setVisibility(View.VISIBLE);
  336.       } else {
  337.         int[] location = new int[2];
  338.  
  339.         mAnchor.getLocationOnScreen(location);
  340.         Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
  341.  
  342.         mWindow.setAnimationStyle(mAnimStyle);
  343.         setWindowLayoutType();
  344.         mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom);
  345.       }
  346.       mShowing = true;
  347.       if (mShownListener != null)
  348.         mShownListener.onShown();
  349.     }
  350.     updatePausePlay();
  351.     mHandler.sendEmptyMessage(SHOW_PROGRESS);
  352.  
  353.     if (timeout != 0) {
  354.       mHandler.removeMessages(FADE_OUT);
  355.       mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout);
  356.     }
  357.   }
  358.  
  359.   public boolean isShowing() {
  360.     return mShowing;
  361.   }
  362.  
  363.   public void hide() {
  364.     if (mAnchor == null)
  365.       return;
  366.  
  367.     if (mShowing) {
  368.       try {
  369.         mHandler.removeMessages(SHOW_PROGRESS);
  370.         if (mFromXml)
  371.           setVisibility(View.GONE);
  372.         else
  373.           mWindow.dismiss();
  374.       } catch (IllegalArgumentException ex) {
  375.         Log.d("MediaController already removed");
  376.       }
  377.       mShowing = false;
  378.       if (mHiddenListener != null)
  379.         mHiddenListener.onHidden();
  380.     }
  381.   }
  382.  
  383.   public void setOnShownListener(OnShownListener l) {
  384.     mShownListener = l;
  385.   }
  386.  
  387.   public void setOnHiddenListener(OnHiddenListener l) {
  388.     mHiddenListener = l;
  389.   }
  390.  
  391.   private long setProgress() {
  392.     if (mPlayer == null || mDragging)
  393.       return 0;
  394.  
  395.     long position = mPlayer.getCurrentPosition();
  396.     long duration = mPlayer.getDuration();
  397.     if (mProgress != null) {
  398.       if (duration > 0) {
  399.         long pos = 1000L * position / duration;
  400.         mProgress.setProgress((int) pos);
  401.       }
  402.       int percent = mPlayer.getBufferPercentage();
  403.       mProgress.setSecondaryProgress(percent * 10);
  404.     }
  405.  
  406.     mDuration = duration;
  407.  
  408.     if (mEndTime != null)
  409.       mEndTime.setText(StringUtils.generateTime(mDuration));
  410.     if (mCurrentTime != null)
  411.       mCurrentTime.setText(StringUtils.generateTime(position));
  412.  
  413.     return position;
  414.   }
  415.  
  416.   @Override
  417.   public boolean onTouchEvent(MotionEvent event) {
  418.     show(sDefaultTimeout);
  419.     return true;
  420.   }
  421.  
  422.   @Override
  423.   public boolean onTrackballEvent(MotionEvent ev) {
  424.     show(sDefaultTimeout);
  425.     return false;
  426.   }
  427.  
  428.   @Override
  429.   public boolean dispatchKeyEvent(KeyEvent event) {
  430.     int keyCode = event.getKeyCode();
  431.     if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
  432.       doPauseResume();
  433.       show(sDefaultTimeout);
  434.       if (mPauseButton != null)
  435.         mPauseButton.requestFocus();
  436.       return true;
  437.     } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
  438.       if (mPlayer.isPlaying()) {
  439.         mPlayer.pause();
  440.         updatePausePlay();
  441.       }
  442.       return true;
  443.     } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
  444.       hide();
  445.       return true;
  446.     } else {
  447.       show(sDefaultTimeout);
  448.     }
  449.     return super.dispatchKeyEvent(event);
  450.   }
  451.  
  452.   private void updatePausePlay() {
  453.     if (mRoot == null || mPauseButton == null)
  454.       return;
  455.  
  456.     if (mPlayer.isPlaying())
  457.       mPauseButton.setImageResource(getResources().getIdentifier("mediacontroller_pause", "drawable", mContext.getPackageName()));
  458.     else
  459.       mPauseButton.setImageResource(getResources().getIdentifier("mediacontroller_play", "drawable", mContext.getPackageName()));
  460.   }
  461.  
  462.   private void doPauseResume() {
  463.     if (mPlayer.isPlaying())
  464.       mPlayer.pause();
  465.     else
  466.       mPlayer.start();
  467.     updatePausePlay();
  468.   }
  469.  
  470.   @Override
  471.   public void setEnabled(boolean enabled) {
  472.     if (mPauseButton != null)
  473.       mPauseButton.setEnabled(enabled);
  474.     if (mProgress != null)
  475.       mProgress.setEnabled(enabled);
  476.     super.setEnabled(enabled);
  477.   }
  478.  
  479.   public interface OnShownListener {
  480.     public void onShown();
  481.   }
  482.  
  483.   public interface OnHiddenListener {
  484.     public void onHidden();
  485.   }
  486.  
  487.   public interface MediaPlayerControl {
  488.     void start();
  489.  
  490.     void pause();
  491.  
  492.     long getDuration();
  493.  
  494.     long getCurrentPosition();
  495.  
  496.     void seekTo(long pos);
  497.  
  498.     boolean isPlaying();
  499.  
  500.     int getBufferPercentage();
  501.   }
  502.  
  503. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement