package com.sound.ampache.fragments; /* Copyright (c) 2008 Kevin James Purdy <purdyk@onid.orst.edu> * Copyright (c) 2010 Kristopher Heijari < iix.ftw@gmail.com > * Copyright (c) 2010 Jacob Alexander < haata@users.sf.net > * Copyright (c) 2014 David Hrdina Nemecek <dejvino@gmail.com> * * +------------------------------------------------------------------------+ * | 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 2 | * | 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, write to the Free Software | * | Foundation, Inc., 59 Temple Place - Suite 330, | * | Boston, MA 02111-1307, USA. | * +------------------------------------------------------------------------+ */ import android.app.Fragment; import android.content.Context; import android.os.Bundle; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.ProgressBar; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import com.sound.ampache.R; import com.sound.ampache.amdroid; import com.sound.ampache.service.AbstractPlayerServiceStatusListener; import java.util.Formatter; import java.util.Locale; /** * Media player controls fragment. */ public final class MiniPlayer extends Fragment { private static final String LOG_TAG = "Ampache_Amdroid_MiniPlayer"; private static int bufferingPercent = 0; private ProgressBar mProgress; private TextView mEndTime, mCurrentTime; private boolean mDragging; private ImageButton mPauseButton; private ImageButton mNextButton; private ImageButton mPrevButton; private ImageButton mRepeatButton; private ImageButton mShuffleButton; private static final int FADE_OUT = 1; private static final int SHOW_PROGRESS = 2; StringBuilder mFormatBuilder; Formatter mFormatter; private PlaybackListener playbackListener = new PlaybackListener(); /* * Listener variables for our buttons defined in the layout. The listeners are bound to their * buttons in initControllerView */ private View.OnClickListener mPauseListener = new View.OnClickListener() { @Override public void onClick(View view) { amdroid.playbackControl.doPauseResume(); } }; private View.OnClickListener mNextListener = new View.OnClickListener() { @Override public void onClick(View view) { amdroid.playbackControl.nextInPlaylist(); amdroid.playbackControl.play(); } }; private View.OnClickListener mPrevListener = new View.OnClickListener() { @Override public void onClick(View view) { amdroid.playbackControl.prevInPlaylist(); amdroid.playbackControl.play(); } }; private View.OnClickListener mShuffleListener = new View.OnClickListener() { @Override public void onClick(View view) { if (amdroid.playbackControl.shuffleEnabled()) { ((ImageButton) view).setImageResource(R.drawable.ic_menu_shuffle_disabled); // Disable Shuffle amdroid.playbackControl.setShuffle(false); Toast.makeText(getContext(), "Shuffle Disabled", Toast.LENGTH_SHORT).show(); } else { ((ImageButton) view).setImageResource(R.drawable.ic_menu_shuffle); // Enable Shuffle amdroid.playbackControl.setShuffle(true); Toast.makeText(getContext(), "Shuffle Enabled", Toast.LENGTH_SHORT).show(); } } }; private View.OnClickListener mRepeatListener = new View.OnClickListener() { @Override public void onClick(View view) { if (amdroid.playbackControl.repeatEnabled()) { ((ImageButton) view).setImageResource(R.drawable.ic_menu_revert_disabled); // Disable Repeat amdroid.playbackControl.setRepeat(false); Toast.makeText(getContext(), "Repeat Disabled", Toast.LENGTH_SHORT).show(); } else { ((ImageButton) view).setImageResource(R.drawable.ic_menu_revert); // Enable Repeat amdroid.playbackControl.setRepeat(true); Toast.makeText(getContext(), "Repeat Enabled", Toast.LENGTH_SHORT).show(); } } }; /* * Listener to respond to changes made to the seekbar. */ private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { long duration; public void onStartTrackingTouch(SeekBar bar) { duration = amdroid.playbackControl.getDuration(); } public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) { if (fromtouch) { mDragging = true; long newposition = (duration * progress) / 1000L; amdroid.playbackControl.seekTo((int) newposition); if (mCurrentTime != null) mCurrentTime.setText(stringForTime((int) newposition)); } } public void onStopTrackingTouch(SeekBar bar) { mDragging = false; setProgress(); updatePausePlay(); } }; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.mini_player, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // Bind listeners to our components mPauseButton = (ImageButton) view.findViewById(R.id.pause); if (mPauseButton != null) { mPauseButton.setOnClickListener(mPauseListener); } mNextButton = (ImageButton) view.findViewById(R.id.next); if (mNextButton != null) { mNextButton.setOnClickListener(mNextListener); } mPrevButton = (ImageButton) view.findViewById(R.id.prev); if (mPrevButton != null) { mPrevButton.setOnClickListener(mPrevListener); } // TODO: move to playlist // mRepeatButton = (ImageButton) view.findViewById(R.id.repeat); // if (mRepeatButton != null) { // mRepeatButton.setOnClickListener( mRepeatListener ); // /* TODO!! // if ( amdroid.playbackControl.repeatEnabled() ) // mRepeatButton.setImageResource( R.drawable.ic_menu_revert ); // else // mRepeatButton.setImageResource( R.drawable.ic_menu_revert_disabled ); // */ // } // // mShuffleButton = (ImageButton) view.findViewById(R.id.shuffle); // if (mShuffleButton != null) { // mShuffleButton.setOnClickListener(mShuffleListener); // /* TODO!! // if ( amdroid.playbackControl.shuffleEnabled() ) // mShuffleButton.setImageResource( R.drawable.ic_menu_shuffle ); // else // mShuffleButton.setImageResource( R.drawable.ic_menu_shuffle_disabled ); // */ // } mProgress = (SeekBar) view.findViewById(R.id.mediacontroller_progress); if (mProgress != null) { if (mProgress instanceof SeekBar) { SeekBar seeker = (SeekBar) mProgress; seeker.setOnSeekBarChangeListener(mSeekListener); } mProgress.setMax(1000); } mEndTime = (TextView) view.findViewById(R.id.time); mCurrentTime = (TextView) view.findViewById(R.id.time_current); mFormatBuilder = new StringBuilder(); mFormatter = new Formatter(mFormatBuilder, Locale.getDefault()); amdroid.playbackControl.registerServiceStatusListener(playbackListener); } @Override public void onDestroy() { super.onDestroy(); amdroid.playbackControl.unregisterServiceStatusListener(playbackListener); } 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(); } } /** * Reads the progress information from the player service and updates the corresponding UI elements. * * @return position (progress), returned from {@link com.sound.ampache.GlobalMediaPlayerControl#getCurrentPosition()}. */ private int setProgress() { if (mDragging) { return 0; } int position = amdroid.playbackControl.getCurrentPosition(); int duration = amdroid.playbackControl.getDuration(); if (mProgress != null) { if (duration > 0) { // use long to avoid overflow long pos = 1000L * position / duration; mProgress.setProgress((int) pos); } mProgress.setSecondaryProgress(bufferingPercent * 10); } if (mEndTime != null) mEndTime.setText(stringForTime(duration)); if (mCurrentTime != null) mCurrentTime.setText(stringForTime(position)); return position; } private void updatePausePlay() { ImageButton button = mPauseButton; if (button == null) return; if (amdroid.playbackControl.isPlaying()) { button.setImageResource(android.R.drawable.ic_media_pause); } else { button.setImageResource(android.R.drawable.ic_media_play); } } private Context getContext() { return getActivity(); } /** * Handles messages from the player service. * <p/> * Contains periodic song progress updater. */ private class PlaybackListener extends AbstractPlayerServiceStatusListener { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == SHOW_PROGRESS) { updateProgress(); } } @Override public void onPlay() { updateProgress(); } @Override public void onPause() { updateProgress(); } @Override public void onStop() { updateProgress(); } @Override public void onSeek(int position) { setProgress(); } @Override public void onBuffering(int buffer) { bufferingPercent = buffer; updateProgress(); } @Override public void onError(int what, int extra) { Context ctx = getActivity(); if (ctx != null) { Toast.makeText(ctx, "Media player error (" + what + ", " + extra + ")", Toast.LENGTH_SHORT).show(); } } // TODO: add to interface public void onBufferingCompleted() { amdroid.playbackControl.nextInPlaylist(); amdroid.playbackControl.play(); } private void updateProgress() { setProgress(); cancelProgressUpdate(); if (amdroid.playbackControl.isPlaying()) { scheduleProgressUpdate(); } } private void scheduleProgressUpdate() { sendEmptyMessageDelayed(SHOW_PROGRESS, 500); } private void cancelProgressUpdate() { removeMessages(SHOW_PROGRESS); } } }