Java tutorial
/* * Copyright (C) 2014 Saravan Pantham * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.aniruddhc.acemusic.player.NowPlayingActivity; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.content.LocalBroadcastManager; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout.DrawerListener; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.ScaleAnimation; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import com.aniruddhc.acemusic.player.Animations.FadeAnimation; import com.aniruddhc.acemusic.player.Drawers.QueueDrawerFragment; import com.aniruddhc.acemusic.player.Helpers.TypefaceHelper; import com.aniruddhc.acemusic.player.Helpers.UIElementsHelper; import com.aniruddhc.acemusic.player.R; import com.aniruddhc.acemusic.player.Utils.Common; import com.aniruddhc.acemusic.player.Transformers.ZoomOutPageTransformer; import com.velocity.view.pager.library.VelocityViewPager; import java.util.HashMap; public class NowPlayingActivity extends FragmentActivity { //Common objects. private Context mContext; private Common mApp; //Layouts. private DrawerLayout mDrawerLayout; private FrameLayout mDrawerParentLayout; private QueueDrawerFragment mQueueDrawerFragment; private RelativeLayout mCurrentQueueLayout; //Song info/seekbar elements. private SeekBar mSeekbar; private ProgressBar mStreamingProgressBar; //Playback Controls. private RelativeLayout mControlsLayoutHeaderParent; private RelativeLayout mControlsLayoutHeader; private ImageButton mPlayPauseButton; private RelativeLayout mPlayPauseButtonBackground; private ImageButton mNextButton; private ImageButton mPreviousButton; private ImageButton mShuffleButton; private ImageButton mRepeatButton; //Seekbar indicator. private RelativeLayout mSeekbarIndicatorLayoutParent; private RelativeLayout mSeekbarIndicatorLayout; private TextView mSeekbarIndicatorText; //Seekbar strobe effect. private AlphaAnimation mSeekbarStrobeAnim; private static final int SEEKBAR_STROBE_ANIM_REPEAT = Animation.INFINITE; //Playlist pager. private VelocityViewPager mViewPager; private PlaylistPagerAdapter mViewPagerAdapter; //Handler object. private Handler mHandler = new Handler(); //Differentiates between a user's scroll input and a programmatic scroll. private boolean USER_SCROLL = true; //HashMap that passes on song information to the "Download from Cloud" dialog. private HashMap<String, String> metadata; //Interface instance and flags. private NowPlayingActivityListener mNowPlayingActivityListener; public static final String START_SERVICE = "StartService"; private boolean mIsCreating = true; private Animation mFadeInAnimation; @SuppressLint("NewApi") @Override protected void onCreate(Bundle savedInstanceState) { mContext = getApplicationContext(); mApp = (Common) getApplicationContext(); mApp.setNowPlayingActivity(this); setNowPlayingActivityListener(mApp.getPlaybackKickstarter()); mFadeInAnimation = AnimationUtils.loadAnimation(mContext, R.anim.slide_in_from_top); mFadeInAnimation.setDuration(700); //Set the UI theme. setTheme(); super.onCreate(savedInstanceState); setContentView(R.layout.activity_now_playing); //Set the volume stream for this activity. this.setVolumeControlStream(AudioManager.STREAM_MUSIC); //Drawer layout. if (!mApp.isTabletInLandscape()) { mDrawerLayout = (DrawerLayout) findViewById(R.id.main_activity_drawer_root); mDrawerParentLayout = (FrameLayout) findViewById(R.id.now_playing_drawer_frame_root); mCurrentQueueLayout = (RelativeLayout) findViewById(R.id.queue_drawer); mDrawerLayout.setDrawerListener(mDrawerListener); mDrawerLayout.setBackgroundColor(UIElementsHelper.getBackgroundColor(mContext)); } else { mCurrentQueueLayout = (RelativeLayout) findViewById(R.id.queue_drawer); } //ViewPager. mViewPager = (VelocityViewPager) findViewById(R.id.nowPlayingPlaylistPager); //Seekbar indicator. mSeekbarIndicatorLayoutParent = (RelativeLayout) findViewById(R.id.seekbarIndicatorParent); mSeekbarIndicatorLayout = (RelativeLayout) findViewById(R.id.seekbarIndicator); mSeekbarIndicatorText = (TextView) findViewById(R.id.seekbarIndicatorText); mSeekbarIndicatorLayoutParent.setVisibility(View.GONE); mSeekbarIndicatorLayout.setBackgroundResource(UIElementsHelper.getGridViewCardBackground(mContext)); mSeekbarIndicatorText.setTypeface(TypefaceHelper.getTypeface(mContext, "Roboto-Regular")); mSeekbarIndicatorText.setTextColor(UIElementsHelper.getThemeBasedTextColor(mContext)); //Playback Controls. mControlsLayoutHeaderParent = (RelativeLayout) findViewById(R.id.now_playing_controls_header_parent); mControlsLayoutHeader = (RelativeLayout) findViewById(R.id.now_playing_controls_header); mPlayPauseButtonBackground = (RelativeLayout) findViewById(R.id.playPauseButtonBackground); mPlayPauseButton = (ImageButton) findViewById(R.id.playPauseButton); mNextButton = (ImageButton) findViewById(R.id.nextButton); mPreviousButton = (ImageButton) findViewById(R.id.previousButton); mShuffleButton = (ImageButton) findViewById(R.id.shuffleButton); mRepeatButton = (ImageButton) findViewById(R.id.repeatButton); //Song info/seekbar elements. mSeekbar = (SeekBar) findViewById(R.id.nowPlayingSeekBar); mStreamingProgressBar = (ProgressBar) findViewById(R.id.startingStreamProgressBar); mStreamingProgressBar.setVisibility(View.GONE); try { mSeekbar.setThumb(getResources().getDrawable(R.drawable.transparent_drawable)); } catch (Exception e) { e.printStackTrace(); } mPlayPauseButtonBackground.setBackgroundResource(UIElementsHelper.getShadowedCircle(mContext)); mPlayPauseButton.setImageResource(R.drawable.pause_light); mPlayPauseButton.setId(R.drawable.pause_light); mNextButton.setImageResource(UIElementsHelper.getIcon(mContext, "btn_playback_next")); mPreviousButton.setImageResource(UIElementsHelper.getIcon(mContext, "btn_playback_previous")); if (mApp.getCurrentTheme() == Common.DARK_THEME) { mNextButton.setAlpha(1f); mPreviousButton.setAlpha(1f); } //KitKat specific layout code. setKitKatTranslucentBars(); //Set the control buttons and background. setControlButtonsBackground(); setPlayPauseButton(); setShuffleButtonIcon(); setRepeatButtonIcon(); //Set the click listeners. mSeekbar.setOnSeekBarChangeListener(seekBarChangeListener); mNextButton.setOnClickListener(mOnClickNextListener); mPreviousButton.setOnClickListener(mOnClickPreviousListener); mPlayPauseButton.setOnClickListener(playPauseClickListener); mPlayPauseButtonBackground.setOnClickListener(playPauseClickListener); mShuffleButton.setOnClickListener(shuffleButtonClickListener); mRepeatButton.setOnClickListener(repeatButtonClickListener); //Apply haptic feedback to the play/pause button. mPlayPauseButtonBackground.setHapticFeedbackEnabled(true); mPlayPauseButton.setHapticFeedbackEnabled(true); } /** * Updates this activity's UI elements based on the passed intent's * update flag(s). */ BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //Grab the bundle from the intent. Bundle bundle = intent.getExtras(); //Initializes the ViewPager. if (intent.hasExtra(Common.INIT_PAGER) || intent.hasExtra(Common.NEW_QUEUE_ORDER)) initViewPager(); //Updates the ViewPager's current page/position. if (intent.hasExtra(Common.UPDATE_PAGER_POSTIION)) { int currentPosition = mViewPager.getCurrentItem(); int newPosition = Integer.parseInt(bundle.getString(Common.UPDATE_PAGER_POSTIION)); if (currentPosition != newPosition) { if (newPosition > 0 && Math.abs(newPosition - currentPosition) <= 5) { //Smooth scroll to the new index. scrollViewPager(newPosition, true, 1, false); } else { //The new index is too far away, so avoid smooth scrolling to it. mViewPager.setCurrentItem(newPosition, false); } //Reinit the seekbar update handler. mHandler.post(seekbarUpdateRunnable); } } //Updates the playback control buttons. if (intent.hasExtra(Common.UPDATE_PLAYBACK_CONTROLS)) { setPlayPauseButton(); setRepeatButtonIcon(); setShuffleButtonIcon(); } //Displays the audibook toast. if (intent.hasExtra(Common.SHOW_AUDIOBOOK_TOAST)) displayAudiobookToast(Long.parseLong(bundle.getString(Common.SHOW_AUDIOBOOK_TOAST))); //Updates the duration of the SeekBar. if (intent.hasExtra(Common.UPDATE_SEEKBAR_DURATION)) setSeekbarDuration(Integer.parseInt(bundle.getString(Common.UPDATE_SEEKBAR_DURATION))); //Hides the seekbar and displays the streaming progress bar. if (intent.hasExtra(Common.SHOW_STREAMING_BAR)) { mSeekbar.setVisibility(View.INVISIBLE); mStreamingProgressBar.setVisibility(View.VISIBLE); mHandler.removeCallbacks(seekbarUpdateRunnable); } //Shows the seekbar and hides the streaming progress bar. if (intent.hasExtra(Common.HIDE_STREAMING_BAR)) { mSeekbar.setVisibility(View.VISIBLE); mStreamingProgressBar.setVisibility(View.INVISIBLE); mHandler.postDelayed(seekbarUpdateRunnable, 100); } //Updates the buffering progress on the seekbar. if (intent.hasExtra(Common.UPDATE_BUFFERING_PROGRESS)) mSeekbar.setSecondaryProgress(Integer.parseInt(bundle.getString(Common.UPDATE_BUFFERING_PROGRESS))); //Close this activity if the service is about to stop running. if (intent.hasExtra(Common.SERVICE_STOPPING)) { mHandler.removeCallbacks(seekbarUpdateRunnable); finish(); } } }; /** * Sets the activity's theme based on user preferences. */ private void setTheme() { if (mApp.getCurrentTheme() == Common.DARK_THEME) { this.setTheme(R.style.AppThemeNoActionBar); } else { this.setTheme(R.style.AppThemeLightNoActionBar); } } /** * Initializes the view pager. */ private void initViewPager() { try { mViewPager.setVisibility(View.INVISIBLE); mViewPagerAdapter = new PlaylistPagerAdapter(getSupportFragmentManager()); mViewPager.setAdapter(mViewPagerAdapter); mViewPager.setOffscreenPageLimit(0); mViewPager.setOnPageChangeListener(mPageChangeListener); mViewPager.setCurrentItem(mApp.getService().getCurrentSongIndex(), false); FadeAnimation fadeAnimation = new FadeAnimation(mViewPager, 600, 0.0f, 1.0f, new DecelerateInterpolator(2.0f)); fadeAnimation.animate(); } catch (IllegalStateException e) { /* * Catches any exceptions that may occur * as a result of the user rapidly changing * their device's orientation. */ } //Delay loading extra fragments by 1000ms. new Handler().postDelayed(new Runnable() { @Override public void run() { mViewPager.setOffscreenPageLimit(10); } }, 1000); } /** * Initializes the current queue drawer/layout. */ private void initDrawer() { //Load the current queue drawer. mQueueDrawerFragment = new QueueDrawerFragment(); try { getSupportFragmentManager().beginTransaction().replace(R.id.queue_drawer, mQueueDrawerFragment) .setCustomAnimations(R.anim.fade_in, R.anim.fade_out).commit(); } catch (IllegalStateException e) { /* * Catches any exceptions that may occur if the * user rapidly changes the device's orientation. */ e.printStackTrace(); } } /** * Slides in the controls bar from the bottom along with a * slight rotation. */ private void animateInControlsBar() { android.view.animation.TranslateAnimation slideUp = new android.view.animation.TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 2.0f, Animation.RELATIVE_TO_SELF, 0.0f); slideUp.setDuration(300); slideUp.setInterpolator(new DecelerateInterpolator(2.0f)); slideUp.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { mControlsLayoutHeaderParent.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } }); mControlsLayoutHeaderParent.startAnimation(slideUp); } /** * Scrolls the ViewPager programmatically. If dispatchToListener * is true, USER_SCROLL will be set to true. */ private void scrollViewPager(int newPosition, boolean smoothScroll, int velocity, boolean dispatchToListener) { USER_SCROLL = dispatchToListener; mViewPager.scrollToItem(newPosition, smoothScroll, velocity, dispatchToListener); } /** * Sets the background for the control buttons based on the selected theme. */ private void setControlButtonsBackground() { mControlsLayoutHeader.setBackgroundResource(UIElementsHelper.getGridViewCardBackground(mContext)); } /** * Sets the play/pause button states. */ private void setPlayPauseButton() { if (mApp.isServiceRunning()) { if (mApp.getService().isPlayingMusic()) { animatePlayToPause(); stopSeekbarStrobeEffect(); } else { animatePauseToPlay(); initSeekbarStrobeEffect(); } } } /** * Animates the play button to a pause button. */ private void animatePlayToPause() { //Check to make sure the current icon is the play icon. if (mPlayPauseButton.getId() != R.drawable.play_light) return; //Fade out the play button. final ScaleAnimation scaleOut = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f, mPlayPauseButton.getWidth() / 2, mPlayPauseButton.getHeight() / 2); scaleOut.setDuration(150); scaleOut.setInterpolator(new AccelerateInterpolator()); //Scale in the pause button. final ScaleAnimation scaleIn = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, mPlayPauseButton.getWidth() / 2, mPlayPauseButton.getHeight() / 2); scaleIn.setDuration(150); scaleIn.setInterpolator(new DecelerateInterpolator()); scaleOut.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { mPlayPauseButton.setImageResource(R.drawable.pause_light); mPlayPauseButton.setPadding(0, 0, 0, 0); mPlayPauseButton.startAnimation(scaleIn); } @Override public void onAnimationRepeat(Animation animation) { } }); scaleIn.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { mPlayPauseButton.setScaleX(1.0f); mPlayPauseButton.setScaleY(1.0f); mPlayPauseButton.setId(R.drawable.pause_light); } @Override public void onAnimationRepeat(Animation animation) { } }); mPlayPauseButton.startAnimation(scaleOut); } /** * Animates the pause button to a play button. */ private void animatePauseToPlay() { //Check to make sure the current icon is the pause icon. if (mPlayPauseButton.getId() != R.drawable.pause_light) return; //Scale out the pause button. final ScaleAnimation scaleOut = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f, mPlayPauseButton.getWidth() / 2, mPlayPauseButton.getHeight() / 2); scaleOut.setDuration(150); scaleOut.setInterpolator(new AccelerateInterpolator()); //Scale in the play button. final ScaleAnimation scaleIn = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, mPlayPauseButton.getWidth() / 2, mPlayPauseButton.getHeight() / 2); scaleIn.setDuration(150); scaleIn.setInterpolator(new DecelerateInterpolator()); scaleOut.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { mPlayPauseButton.setImageResource(R.drawable.play_light); mPlayPauseButton.setPadding(0, 0, -5, 0); mPlayPauseButton.startAnimation(scaleIn); } @Override public void onAnimationRepeat(Animation animation) { } }); scaleIn.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { mPlayPauseButton.setScaleX(1.0f); mPlayPauseButton.setScaleY(1.0f); mPlayPauseButton.setId(R.drawable.play_light); } @Override public void onAnimationRepeat(Animation animation) { } }); mPlayPauseButton.startAnimation(scaleOut); } /** * Sets the repeat button icon based on the current repeat mode. */ private void setRepeatButtonIcon() { if (mApp.isServiceRunning()) if (mApp.getService().getRepeatMode() == Common.REPEAT_OFF) { mRepeatButton.setImageResource(UIElementsHelper.getIcon(mContext, "repeat")); } else if (mApp.getService().getRepeatMode() == Common.REPEAT_PLAYLIST) { mRepeatButton.setImageResource(R.drawable.repeat_highlighted); } else if (mApp.getService().getRepeatMode() == Common.REPEAT_SONG) { mRepeatButton.setImageResource(R.drawable.repeat_song); } else if (mApp.getService().getRepeatMode() == Common.A_B_REPEAT) { mRepeatButton.setImageResource(R.drawable.repeat_song_range); } else mRepeatButton.setImageResource(UIElementsHelper.getIcon(mContext, "repeat")); } /** * Sets the shuffle button icon based on the current shuffle mode. */ private void setShuffleButtonIcon() { if (mApp.isServiceRunning()) if (mApp.getService().isShuffleOn() == true) { mShuffleButton.setImageResource(R.drawable.shuffle_highlighted); } else { mShuffleButton.setImageResource(UIElementsHelper.getIcon(mContext, "shuffle")); } else mShuffleButton.setImageResource(UIElementsHelper.getIcon(mContext, "shuffle")); } /** * Sets the seekbar's duration. Also updates the * elapsed/remaining duration text. */ private void setSeekbarDuration(int duration) { mSeekbar.setMax(duration); mSeekbar.setProgress(mApp.getService().getCurrentMediaPlayer().getCurrentPosition() / 1000); mHandler.postDelayed(seekbarUpdateRunnable, 100); } /** * Sets the KitKat translucent status/nav bar and adjusts * the views' boundaries. */ private void setKitKatTranslucentBars() { //KitKat translucent status bar. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { int statusBarHeight = Common.getStatusBarHeight(mContext); int navigationBarHeight = Common.getNavigationBarHeight(mContext); if (mDrawerParentLayout != null) { mDrawerParentLayout.setClipToPadding(false); mDrawerParentLayout.setPadding(0, 0, 0, 0); } if (mControlsLayoutHeaderParent != null) { int bottomPadding = mControlsLayoutHeaderParent.getPaddingBottom(); mControlsLayoutHeaderParent.setClipToPadding(false); RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mControlsLayoutHeaderParent .getLayoutParams(); if (navigationBarHeight > 0) { /* The nav bar already has padding, so remove the extra 15dp * margin that was applied in the layout file. */ params.bottomMargin = 0; } params.bottomMargin += navigationBarHeight; mControlsLayoutHeaderParent.setLayoutParams(params); } } } /** * Seekbar change listener. */ private OnSeekBarChangeListener seekBarChangeListener = new OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int seekBarPosition, boolean changedByUser) { try { long currentSongDuration = mApp.getService().getCurrentMediaPlayer().getDuration(); seekBar.setMax((int) currentSongDuration / 1000); if (changedByUser) mSeekbarIndicatorText.setText(mApp.convertMillisToMinsSecs(seekBar.getProgress() * 1000)); } catch (Exception e) { e.printStackTrace(); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { mHandler.removeCallbacks(seekbarUpdateRunnable); mHandler.removeCallbacks(fadeOutSeekbarIndicator); mSeekbarIndicatorLayoutParent.setVisibility(View.VISIBLE); mSeekbarIndicatorLayout.setAlpha(0.8f); } @Override public void onStopTrackingTouch(SeekBar seekBar) { int seekBarPosition = seekBar.getProgress(); mApp.getService().getCurrentMediaPlayer().seekTo(seekBarPosition * 1000); //Reinitiate the handler. mHandler.post(seekbarUpdateRunnable); //Fade out the indicator after 1000ms. mHandler.postDelayed(fadeOutSeekbarIndicator, 1000); } }; /** * Seekbar change indicator. */ private Runnable fadeOutSeekbarIndicator = new Runnable() { @Override public void run() { FadeAnimation fadeOut = new FadeAnimation(mSeekbarIndicatorLayoutParent, 300, 0.9f, 0.0f, null); fadeOut.animate(); } }; /** * Repeat button click listener. */ private OnClickListener repeatButtonClickListener = new OnClickListener() { @Override public void onClick(View arg0) { mApp.getService().clearABRepeatRange(); if (mApp.getService().getRepeatMode() == Common.REPEAT_OFF) { mRepeatButton.setImageResource(R.drawable.repeat_highlighted); mApp.getService().setRepeatMode(Common.REPEAT_PLAYLIST); } else if (mApp.getService().getRepeatMode() == Common.REPEAT_PLAYLIST) { mRepeatButton.setImageResource(R.drawable.repeat_song); mApp.getService().setRepeatMode(Common.REPEAT_SONG); } else { mRepeatButton.setImageResource(UIElementsHelper.getIcon(mContext, "repeat")); mApp.getService().setRepeatMode(Common.REPEAT_OFF); } } }; /** * Shuffle button click listener. */ private OnClickListener shuffleButtonClickListener = new OnClickListener() { @Override public void onClick(View arg0) { //Toggle shuffle on/off. boolean shuffleOn = mApp.getService().toggleShuffleMode(); if (shuffleOn) mShuffleButton.setImageResource(R.drawable.shuffle_highlighted); else mShuffleButton.setImageResource(UIElementsHelper.getIcon(mContext, "shuffle")); } }; /** * Click listener for the play/pause button. */ private OnClickListener playPauseClickListener = new OnClickListener() { @Override public void onClick(View view) { //BZZZT! Give the user a brief haptic feedback touch response. view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); //Update the playback UI elements. if (mApp.getService().isPlayingMusic()) { animatePauseToPlay(); mHandler.removeCallbacks(seekbarUpdateRunnable); } else { animatePlayToPause(); mHandler.post(seekbarUpdateRunnable); } /* * Toggle the playback state in a separate thread. This * will allow the play/pause button animation to remain * buttery smooth. */ new AsyncTask() { @Override protected Object doInBackground(Object[] params) { mApp.getService().togglePlaybackState(); return null; } }.execute(); } }; /** * Click listener for the previous button. */ private OnClickListener mOnClickPreviousListener = new OnClickListener() { @Override public void onClick(View arg0) { //Remove the seekbar update runnable. mHandler.removeCallbacks(seekbarUpdateRunnable); /* * Scrolling the pager will automatically call the skipToTrack() method. * Since we're passing true for the dispatchToListener parameter, the * onPageSelected() listener will receive a callback once the scrolling * animation completes. This has the side-benefit of letting the animation * finish before starting playback (keeps the animation buttery smooth). */ int newPosition = mViewPager.getCurrentItem() - 1; if (newPosition > -1) { scrollViewPager(newPosition, true, 1, true); } else { mViewPager.setCurrentItem(0, false); } } }; /** * Click listener for the next button. */ private OnClickListener mOnClickNextListener = new OnClickListener() { @Override public void onClick(View arg0) { //Remove the seekbar update runnable. mHandler.removeCallbacks(seekbarUpdateRunnable); /* * Scrolling the pager will automatically call the skipToTrack() method. * Since we're passing true for the dispatchToListener parameter, the * onPageSelected() listener will receive a callback once the scrolling * animation completes. This has the side-benefit of letting the animation * finish before starting playback (keeps the animation buttery smooth). */ int newPosition = mViewPager.getCurrentItem() + 1; if (newPosition < mViewPagerAdapter.getCount()) { scrollViewPager(newPosition, true, 1, true); } else { if (mApp.getService().getRepeatMode() == Common.REPEAT_PLAYLIST) mViewPager.setCurrentItem(0, false); else Toast.makeText(mContext, R.string.no_songs_to_skip_to, Toast.LENGTH_SHORT).show(); } //mApp.getService().skipToNextTrack(); } }; /** * Downloads a GMusic song for local playback. */ /*private void pinSong() { //Check if the app is getting pinned songs from the official GMusic app. if (mApp.isFetchingPinnedSongs()==false) { //Retrieve the name of the song. mApp.getService().getCursor().moveToPosition(mApp.getService().getPlaybackIndecesList().get(mApp.getService().getCurrentSongIndex())); //Get the song's ID/title. String songID = mApp.getService().getCursor().getString(mApp.getService().getCursor().getColumnIndex(DBAccessHelper.SONG_ID)); String songTitle = mApp.getService().getCursor().getString(mApp.getService().getCursor().getColumnIndex(DBAccessHelper.SONG_TITLE)); //Check if a local copy of the song exists. String localCopyPath = mApp.getDBAccessHelper().getLocalCopyPath(songID); if (localCopyPath!=null) { if (localCopyPath.isEmpty() || localCopyPath.equals("")) { if (mMenu!=null) { mMenu.findItem(R.id.action_pin).setIcon(R.drawable.pin_highlighted); } //Get a mCursor with the current song and initiate the download process. String selection = " AND " + DBAccessHelper.SONG_ID + "=" + "'" + songID + "'"; mApp.queueSongsToPin(false, false, selection); String toastMessage = getResources().getString(R.string.downloading_no_dot) + " " + songTitle + "."; Toast.makeText(mContext, toastMessage, Toast.LENGTH_SHORT).show(); } else { if (mMenu!=null) { mMenu.findItem(R.id.action_pin).setIcon(R.drawable.pin_light); } String selection = " AND " + DBAccessHelper.SONG_ID + "=" + "'" + songID + "'"; AsyncRemovePinnedSongsTask task = new AsyncRemovePinnedSongsTask(mContext, selection, null); task.execute(); } } else { if (mMenu!=null) { mMenu.findItem(R.id.action_pin).setIcon(R.drawable.pin_highlighted); } //Get a mCursor with the current song and initiate the download process. String selection = " AND " + DBAccessHelper.SONG_ID + "=" + "'" + songID + "'"; mApp.queueSongsToPin(false, false, selection); } } else { Toast.makeText(mContext, R.string.wait_until_pinning_complete, Toast.LENGTH_SHORT).show(); } }*/ /** * Drawer open/close listener. */ private DrawerListener mDrawerListener = new DrawerListener() { @Override public void onDrawerClosed(View drawer) { if (mQueueDrawerFragment != null && drawer == mCurrentQueueLayout) { mQueueDrawerFragment.setIsDrawerOpen(false); } } @Override public void onDrawerOpened(View drawer) { if (mQueueDrawerFragment != null && drawer == mCurrentQueueLayout) { mQueueDrawerFragment.setIsDrawerOpen(true); } } @Override public void onDrawerSlide(View drawer, float arg1) { // TODO Auto-generated method stub } @Override public void onDrawerStateChanged(int newState) { // TODO Auto-generated method stub } }; /** * Provides callback methods when the ViewPager's position/current page has changed. */ private VelocityViewPager.OnPageChangeListener mPageChangeListener = new VelocityViewPager.OnPageChangeListener() { @Override public void onPageScrollStateChanged(int scrollState) { if (scrollState == VelocityViewPager.SCROLL_STATE_DRAGGING) USER_SCROLL = true; } @Override public void onPageScrolled(final int pagerPosition, float swipeVelocity, int offsetFromCurrentPosition) { /* swipeVelocity determines whether the viewpager has finished scrolling or not. * Throw in an if statement that only allows the track to change when * swipeVelocity is 0 (which means the page is done scrolling). This ensures * that the tracks don't jump around or get truncated while the user is * swiping between different pages. */ if (mApp.isServiceRunning() && mApp.getService().getCursor().getCount() != 1) { /* Change tracks ONLY when the user has finished the swiping gesture (swipeVelocity will be zero). * Also, don't skip tracks if the new pager position is the same as the current mCursor position (indicates * that the starting and ending position of the pager is the same). */ if (swipeVelocity == 0.0f && pagerPosition != mApp.getService().getCurrentSongIndex()) { if (USER_SCROLL) { mHandler.removeCallbacks(seekbarUpdateRunnable); smoothScrollSeekbar(0); mHandler.postDelayed(new Runnable() { @Override public void run() { mApp.getService().skipToTrack(pagerPosition); } }, 200); } } } } @Override public void onPageSelected(int newPosition) { //TODO Auto-generated method stub. } }; /** * @deprecated * Applies the correct transformer effect to the ViewPager. */ @Deprecated private void setPlaylistPagerAnimation() { if (mApp.getSharedPreferences().getInt("TRACK_CHANGE_ANIMATION", 0) == 0) { mViewPager.setPageTransformer(true, new ZoomOutPageTransformer(0.85f)); } else if (mApp.getSharedPreferences().getInt("TRACK_CHANGE_ANIMATION", 0) == 1) { mViewPager.setPageTransformer(true, new ZoomOutPageTransformer(0.85f)); } else if (mApp.getSharedPreferences().getInt("TRACK_CHANGE_ANIMATION", 0) == 2) { mViewPager.setPageTransformer(true, new ZoomOutPageTransformer(0.85f)); } } /** * Create a new Runnable to update the seekbar and time every 100ms. */ public Runnable seekbarUpdateRunnable = new Runnable() { public void run() { try { long currentPosition = mApp.getService().getCurrentMediaPlayer().getCurrentPosition(); int currentPositionInSecs = (int) currentPosition / 1000; smoothScrollSeekbar(currentPositionInSecs); //mSeekbar.setProgress(currentPositionInSecs); mHandler.postDelayed(seekbarUpdateRunnable, 100); } catch (Exception e) { e.printStackTrace(); } } }; /** * Smoothly scrolls the seekbar to the indicated position. */ private void smoothScrollSeekbar(int progress) { ObjectAnimator animation = ObjectAnimator.ofInt(mSeekbar, "progress", progress); animation.setDuration(200); animation.setInterpolator(new DecelerateInterpolator()); animation.start(); } /** * Initiates the strobe effect on the seekbar. */ private void initSeekbarStrobeEffect() { mSeekbarStrobeAnim = new AlphaAnimation(1.0f, 0.0f); mSeekbarStrobeAnim.setRepeatCount(SEEKBAR_STROBE_ANIM_REPEAT); mSeekbarStrobeAnim.setDuration(700); mSeekbarStrobeAnim.setRepeatMode(Animation.REVERSE); mSeekbar.startAnimation(mSeekbarStrobeAnim); } /** * Stops the seekbar strobe effect. */ private void stopSeekbarStrobeEffect() { mSeekbarStrobeAnim = new AlphaAnimation(mSeekbar.getAlpha(), 1.0f); mSeekbarStrobeAnim.setDuration(700); mSeekbar.startAnimation(mSeekbarStrobeAnim); } public class PlaylistPagerAdapter extends FragmentStatePagerAdapter { public PlaylistPagerAdapter(FragmentManager fm) { super(fm); } @Override public void destroyItem(ViewGroup container, int position, Object object) { super.destroyItem(container, position, object); } //This method controls the layout that is shown on each screen. @Override public Fragment getItem(int position) { /* PlaylistPagerFragment.java will be shown on every pager screen. However, * the fragment will check which screen (position) is being shown, and will * update its TextViews and ImageViews to match the song that's being played. */ Fragment fragment = new PlaylistPagerFragment(); Bundle bundle = new Bundle(); bundle.putInt("POSITION", position); fragment.setArguments(bundle); return fragment; } @Override public int getCount() { try { if (mApp.getService().getPlaybackIndecesList() != null) { return mApp.getService().getPlaybackIndecesList().size(); } else { mApp.getService().stopSelf(); return 0; } } catch (Exception e) { e.printStackTrace(); return 0; } } } /** * Displays the "Resuming from xx:xx" toast. */ public void displayAudiobookToast(long resumePlaybackPosition) { try { String resumingFrom = mContext.getResources().getString(R.string.resuming_from) + " " + mApp.convertMillisToMinsSecs(resumePlaybackPosition) + "."; Toast.makeText(mContext, resumingFrom, Toast.LENGTH_LONG).show(); } catch (Exception e) { e.printStackTrace(); } } /** * Toggles the open/closed state of the current queue drawer. */ public void toggleCurrentQueueDrawer() { if (mDrawerLayout == null) return; if (mDrawerLayout.isDrawerOpen(Gravity.END)) mDrawerLayout.closeDrawer(Gravity.END); else mDrawerLayout.openDrawer(Gravity.END); } /* * Getter and setter methods. */ public SeekBar getSeekbar() { return mSeekbar; } public ProgressBar getStreamingProgressBar() { return mStreamingProgressBar; } public VelocityViewPager getPlaylistViewPager() { return mViewPager; } public NowPlayingActivityListener getNowPlayingActivityListener() { return mNowPlayingActivityListener; } public void setNowPlayingActivityListener(NowPlayingActivityListener listener) { mNowPlayingActivityListener = listener; } /** * Interface that provides callbacks once this activity is * up and running. */ public interface NowPlayingActivityListener { /** * Called once this activity's onResume() method finishes * executing. */ public void onNowPlayingActivityReady(); } @Override public void onResume() { super.onResume(); if (mIsCreating == false) { setKitKatTranslucentBars(); mHandler.postDelayed(seekbarUpdateRunnable, 100); mIsCreating = false; } //Animate the controls bar in. //animateInControlsBar(); //Update the seekbar. try { setSeekbarDuration(mApp.getService().getCurrentMediaPlayer().getDuration() / 1000); } catch (Exception e) { e.printStackTrace(); } //Load the drawer 1000ms after the activity is loaded. mHandler.postDelayed(new Runnable() { @Override public void run() { initDrawer(); } }, 1000); if (getIntent().hasExtra(START_SERVICE) && getNowPlayingActivityListener() != null) { getNowPlayingActivityListener().onNowPlayingActivityReady(); /** * To prevent the service from being restarted every time this * activity is resume, we're gonna have to remove the "START_SERVICE" * extra from the intent. */ getIntent().removeExtra(START_SERVICE); } } @Override public void onPause() { super.onPause(); if (isFinishing()) mApp.setNowPlayingActivity(null); } @Override public void onStart() { super.onStart(); //Initialize the broadcast manager that will listen for track changes. LocalBroadcastManager.getInstance(mContext).registerReceiver((mReceiver), new IntentFilter(Common.UPDATE_UI_BROADCAST)); /* Check if the service is up and running. If so, send out a broadcast message * that will initialize this activity fully. This code block is what will * initialize this activity fully if it is opened after the service is already * up and running (the onServiceRunning() callback isn't available at this point). */ if (mApp.isServiceRunning() && mApp.getService().getCursor() != null) { String[] updateFlags = new String[] { Common.UPDATE_PAGER_POSTIION, Common.UPDATE_SEEKBAR_DURATION, Common.HIDE_STREAMING_BAR, Common.INIT_PAGER, Common.UPDATE_PLAYBACK_CONTROLS, Common.UPDATE_EQ_FRAGMENT }; String[] flagValues = new String[] { "" + mApp.getService().getCurrentSongIndex(), "" + mApp.getService().getCurrentMediaPlayer().getDuration(), "", "", "", "" }; mApp.broadcastUpdateUICommand(updateFlags, flagValues); } } @Override public void onStop() { //Unregister the broadcast receivers. LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mReceiver); super.onStop(); } @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putBoolean("CALLED_FROM_FOOTER", true); savedInstanceState.putBoolean("CALLED_FROM_NOTIF", true); } }