X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/d68b32465328dafb0cd30d8104ef8a3a05ef7bde..7656cff3bbb92aefbbe01d59f746d5e7f3bd9445:/src/com/owncloud/android/media/MediaControlView.java diff --git a/src/com/owncloud/android/media/MediaControlView.java b/src/com/owncloud/android/media/MediaControlView.java deleted file mode 100644 index cb9ea19e..00000000 --- a/src/com/owncloud/android/media/MediaControlView.java +++ /dev/null @@ -1,688 +0,0 @@ -/* ownCloud Android client application - * - * Copyright (C) 2012-2013 ownCloud Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -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.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.MediaController.MediaPlayerControl; -import android.widget.ProgressBar; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; - -import java.util.Formatter; -import java.util.Locale; - -import com.owncloud.android.R; - -/** - * View containing controls for a {@link MediaPlayer}. - * - * Holds buttons "play / pause", "rewind", "fast forward" - * and a progress slider. - * - * It synchronizes itself with the state of the - * {@link MediaPlayer}. - * - * @author David A. Velasco - */ - -public class MediaControlView extends FrameLayout implements /* OnLayoutChangeListener, */ OnTouchListener { - - 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; - 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); - addView(mRoot, frameParams); - - setFocusable(true); - setFocusableInTouchMode(true); - setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); - requestFocus(); - } - - @Override - public void onFinishInflate() { - if (mRoot != null) - initControllerView(mRoot); - } - - /* TODO REMOVE - public MediaControlView(Context context, boolean useFastForward) { - super(context); - mContext = context; - mUseFastForward = useFastForward; - initFloatingWindowLayout(); - //initFloatingWindow(); - } - */ - - /* TODO REMOVE - public MediaControlView(Context context) { - this(context, true); - } - */ - - /* T - private void initFloatingWindow() { - mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); - mWindow = PolicyManager.makeNewWindow(mContext); - mWindow.setWindowManager(mWindowManager, null, null); - mWindow.requestFeature(Window.FEATURE_NO_TITLE); - mDecor = mWindow.getDecorView(); - mDecor.setOnTouchListener(mTouchListener); - mWindow.setContentView(this); - mWindow.setBackgroundDrawableResource(android.R.color.transparent); - - // While the media controller is up, the volume control keys should - // affect the media stream type - mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC); - - setFocusable(true); - setFocusableInTouchMode(true); - setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); - requestFocus(); - } - */ - - /* - // Allocate and initialize the static parts of mDecorLayoutParams. Must - // also call updateFloatingWindowLayout() to fill in the dynamic parts - // (y and width) before mDecorLayoutParams can be used. - private void initFloatingWindowLayout() { - mDecorLayoutParams = new WindowManager.LayoutParams(); - WindowManager.LayoutParams p = mDecorLayoutParams; - p.gravity = Gravity.TOP; - p.height = LayoutParams.WRAP_CONTENT; - p.x = 0; - p.format = PixelFormat.TRANSLUCENT; - p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; - p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; - p.token = null; - p.windowAnimations = 0; // android.R.style.DropDownAnimationDown; - } - */ - - // Update the dynamic parts of mDecorLayoutParams - // Must be called with mAnchor != NULL. - private void updateFloatingWindowLayout() { - int [] anchorPos = new int[2]; - mAnchor.getLocationOnScreen(anchorPos); - - WindowManager.LayoutParams p = mDecorLayoutParams; - p.width = mAnchor.getWidth(); - p.y = anchorPos[1] + mAnchor.getHeight(); - } - - /* - // This is called whenever mAnchor's layout bound changes - public void onLayoutChange(View v, int left, int top, int right, - int bottom, int oldLeft, int oldTop, int oldRight, - int oldBottom) { - //updateFloatingWindowLayout(); - if (mShowing) { - mWindowManager.updateViewLayout(mDecor, mDecorLayoutParams); - } - } - */ - - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (mShowing) { - hide(); - } - } - return false; - } - - - public void setMediaPlayer(MediaPlayerControl player) { - mPlayer = player; - 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); - } - - mFfwdButton = (ImageButton) v.findViewById(R.id.forwardBtn); - if (mFfwdButton != null) { - mFfwdButton.setOnClickListener(mFfwdListener); - if (!mFromXml) { - mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE); - } - } - - 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); - } - - mProgress = (ProgressBar) v.findViewById(R.id.progressBar); - if (mProgress != null) { - if (mProgress instanceof SeekBar) { - SeekBar seeker = (SeekBar) mProgress; - seeker.setOnSeekBarChangeListener(mSeekListener); - } - mProgress.setMax(1000); - } - - mEndTime = (TextView) v.findViewById(R.id.totalTimeText); - mCurrentTime = (TextView) v.findViewById(R.id.currentTimeText); - 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 - */ - private void disableUnsupportedButtons() { - try { - if (mPauseButton != null && !mPlayer.canPause()) { - mPauseButton.setEnabled(false); - } - if (mRewButton != null && !mPlayer.canSeekBackward()) { - mRewButton.setEnabled(false); - } - if (mFfwdButton != null && !mPlayer.canSeekForward()) { - mFfwdButton.setEnabled(false); - } - } catch (IncompatibleClassChangeError ex) { - // We were given an old version of the interface, that doesn't have - // the canPause/canSeekXYZ methods. This is OK, it just means we - // assume the media can be paused and seeked, and so we don't disable - // the buttons. - } - } - - /** - * 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()) { - msg = obtainMessage(SHOW_PROGRESS); - sendMessageDelayed(msg, 1000 - (pos % 1000)); - } - break; - } - } - }; - - private String stringForTime(int timeMs) { - int totalSeconds = timeMs / 1000; - - int seconds = totalSeconds % 60; - int minutes = (totalSeconds / 60) % 60; - int hours = totalSeconds / 3600; - - mFormatBuilder.setLength(0); - if (hours > 0) { - return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString(); - } else { - return mFormatter.format("%02d:%02d", minutes, seconds).toString(); - } - } - - private int setProgress() { - if (mPlayer == null || mDragging) { - return 0; - } - int position = mPlayer.getCurrentPosition(); - int duration = mPlayer.getDuration(); - if (mProgress != null) { - if (duration > 0) { - // use long to avoid overflow - long pos = 1000L * position / duration; - mProgress.setProgress( (int) pos); - } - int percent = mPlayer.getBufferPercentage(); - mProgress.setSecondaryProgress(percent * 10); - } - - if (mEndTime != null) - mEndTime.setText(stringForTime(duration)); - if (mCurrentTime != null) - mCurrentTime.setText(stringForTime(position)); - - 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) { - int keyCode = event.getKeyCode(); - final boolean uniqueDown = event.getRepeatCount() == 0 - && event.getAction() == KeyEvent.ACTION_DOWN; - if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK - || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE - || keyCode == KeyEvent.KEYCODE_SPACE) { - if (uniqueDown) { - doPauseResume(); - show(sDefaultTimeout); - if (mPauseButton != null) { - mPauseButton.requestFocus(); - } - } - return true; - } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { - if (uniqueDown && !mPlayer.isPlaying()) { - mPlayer.start(); - updatePausePlay(); - show(sDefaultTimeout); - } - return true; - } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP - || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { - 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(); - } - return true; - } - - show(sDefaultTimeout); - return super.dispatchKeyEvent(event); - } - - private View.OnClickListener mPauseListener = new View.OnClickListener() { - public void onClick(View v) { - doPauseResume(); - show(sDefaultTimeout); - } - }; - - private void updatePausePlay() { - if (mRoot == null || mPauseButton == null) - return; - - if (mPlayer.isPlaying()) { - mPauseButton.setImageResource(android.R.drawable.ic_media_pause); - } else { - mPauseButton.setImageResource(android.R.drawable.ic_media_play); - } - } - - private void doPauseResume() { - if (mPlayer.isPlaying()) { - mPlayer.pause(); - } else { - mPlayer.start(); - } - 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) { - mPauseButton.setEnabled(enabled); - } - if (mFfwdButton != null) { - mFfwdButton.setEnabled(enabled); - } - 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); - } - disableUnsupportedButtons(); - super.setEnabled(enabled); - } - - @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()); - } - - private View.OnClickListener mRewListener = new View.OnClickListener() { - public void onClick(View v) { - int pos = mPlayer.getCurrentPosition(); - pos -= 5000; // milliseconds - mPlayer.seekTo(pos); - setProgress(); - - show(sDefaultTimeout); - } - }; - - private View.OnClickListener mFfwdListener = new View.OnClickListener() { - public void onClick(View v) { - int pos = mPlayer.getCurrentPosition(); - pos += 15000; // milliseconds - mPlayer.seekTo(pos); - setProgress(); - - show(sDefaultTimeout); - } - }; - - private void installPrevNextListeners() { - if (mNextButton != null) { - mNextButton.setOnClickListener(mNextListener); - mNextButton.setEnabled(mNextListener != null); - } - - if (mPrevButton != null) { - mPrevButton.setOnClickListener(mPrevListener); - mPrevButton.setEnabled(mPrevListener != null); - } - } - - public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) { - mNextListener = next; - mPrevListener = prev; - mListenersSet = true; - - if (mRoot != null) { - installPrevNextListeners(); - - if (mNextButton != null && !mFromXml) { - mNextButton.setVisibility(View.VISIBLE); - } - if (mPrevButton != null && !mFromXml) { - mPrevButton.setVisibility(View.VISIBLE); - } - } - } - -}