/** 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);
      }
    }
  }
        @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 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);
    }
  }
 /** 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"));
 }
 /** @deprecated Applies the correct transformer effect to the ViewPager. */
 @SuppressWarnings("unused")
 private void setPlaylistPagerAnimation() {
   if (mApp.getSharedPreferences().getInt("TRACK_CHANGE_ANIMATION", 0) == 0) {
     // Don't set a transformer.
   } 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 DepthPageTransformer());
   }
 }
 /** Sets the play/pause button states. */
 private void setPlayPauseButton() {
   if (mApp.isServiceRunning()) {
     if (mApp.getService().isPlayingMusic()) {
       animatePlayToPause();
       stopSeekbarStrobeEffect();
     } else {
       animatePauseToPlay();
       initSeekbarStrobeEffect();
     }
   }
 }
 /** 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"));
 }
        @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 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();
        }
        @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();

        }
  /** 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);
  }
 /** 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);
   }
 }
        @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"));
        }
        @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);
        }
  /** 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();
    }
  }
        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();
          }
        }
  @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 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);
          }
        }
 /** 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);
 }
 @Override
 public void onPause() {
   super.onPause();
   if (isFinishing()) mApp.setNowPlayingActivity(null);
 }
  @SuppressLint("NewApi")
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    mContext = getApplicationContext();
    mApp = (Common) getApplicationContext();
    mApp.setNowPlayingActivity(this);
    setNowPlayingActivityListener(mApp.getPlaybackKickstarter());

    // 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);
  }