com.andreadec.musicplayer.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.andreadec.musicplayer.MainActivity.java

Source

/*
 * Copyright 2012-2014 Andrea De Cesare
 *
 * 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.andreadec.musicplayer;

import java.io.*;
import java.net.*;
import java.util.*;

import com.andreadec.musicplayer.adapters.*;
import com.readystatesoftware.systembartint.*;

import android.media.AudioManager;
import android.os.*;
import android.preference.*;
import android.support.v4.util.LruCache;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.app.*;
import android.text.TextUtils;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.*;
import android.content.DialogInterface.OnCancelListener;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.view.*;
import android.view.WindowManager.LayoutParams;
import android.view.View.*;
import android.widget.*;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CompoundButton.*;
import android.widget.SeekBar.*;

public class MainActivity extends FragmentActivity implements OnClickListener, OnSeekBarChangeListener {
    public final static int PAGE_BROWSER = 0, PAGE_PLAYLISTS = 1, PAGE_RADIOS = 2, PAGE_PODCASTS = 3;

    private TextView textViewArtist, textViewTitle, textViewTime;
    private ImageButton imageButtonPrevious, imageButtonPlayPause, imageButtonNext, imageButtonShowSeekbar2;
    private SeekBar seekBar1, seekBar2;
    private ImageView imageViewSongImage;
    private ImageButton imageButtonShuffle, imageButtonRepeat, imageButtonRepeatAll;
    private Button buttonBassBoost, buttonEqualizer, buttonShake;
    private MusicService musicService; // The application service
    private Intent serviceIntent;
    private BroadcastReceiver broadcastReceiver;
    private SharedPreferences preferences;
    private View buttonQuit, layoutPlaybackControls;

    private DrawerLayout drawerLayout;
    private RelativeLayout drawerContainer;
    private ListView drawerList;
    private NavigationDrawerArrayAdapter navigationAdapter;
    private ActionBarDrawerToggle drawerToggle;

    private static final int POLLING_INTERVAL = 450; // Refresh time of the seekbar
    private boolean pollingThreadRunning; // true if thread is active, false otherwise
    private boolean startPollingThread = true;
    private boolean showRemainingTime = false;
    private boolean showSongImage;

    // Variables used to reduce computing on polling thread
    private boolean isLengthAvailable = false;
    private String songDurationString = "";

    private String[] pages;
    private int currentPage = 0;
    private MusicPlayerFragment currentFragment;
    private FragmentManager fragmentManager;

    private LruCache<String, Bitmap> imagesCache;

    private String intentFile;
    private BrowserSong searchSong;

    /* Initializes the activity. */
    @SuppressLint({ "InlinedApi", "NewApi" })
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setVolumeControlStream(AudioManager.STREAM_MUSIC);

        preferences = PreferenceManager.getDefaultSharedPreferences(this);
        if (preferences.getBoolean(Constants.PREFERENCE_DISABLELOCKSCREEN, Constants.DEFAULT_DISABLELOCKSCREEN)) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); // Disable lock screen for this activity
        }

        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

        if (preferences.getBoolean(Constants.PREFERENCE_SHOWHELPOVERLAYMAINACTIVITY, true)) {
            final FrameLayout frameLayout = new FrameLayout(this);
            LayoutInflater layoutInflater = getLayoutInflater();
            layoutInflater.inflate(R.layout.layout_main, frameLayout);
            layoutInflater.inflate(R.layout.layout_helpoverlay_main, frameLayout);
            final View overlayView = frameLayout.getChildAt(1);
            overlayView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    frameLayout.removeView(overlayView);
                    SharedPreferences.Editor editor = preferences.edit();
                    editor.putBoolean(Constants.PREFERENCE_SHOWHELPOVERLAYMAINACTIVITY, false);
                    editor.commit();
                }
            });
            setContentView(frameLayout);
        } else {
            setContentView(R.layout.layout_main);
        }

        pages = new String[4];
        pages[PAGE_BROWSER] = getResources().getString(R.string.browser);
        pages[PAGE_PLAYLISTS] = getResources().getString(R.string.playlist);
        pages[PAGE_RADIOS] = getResources().getString(R.string.radio);
        pages[PAGE_PODCASTS] = getResources().getString(R.string.podcasts);
        fragmentManager = getSupportFragmentManager();
        setTitle(pages[currentPage]);

        /* NAVIGATION DRAWER */
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_drawer, R.string.drawer_open,
                R.string.drawer_close) {
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                setTitle(pages[currentPage]);
            }

            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                setTitle(getResources().getString(R.string.app_name));
            }
        };
        drawerLayout.setDrawerListener(drawerToggle);
        if (Build.VERSION.SDK_INT >= 11)
            getActionBar().setDisplayHomeAsUpEnabled(true);
        drawerContainer = (RelativeLayout) findViewById(R.id.navigation_container);
        drawerList = (ListView) findViewById(R.id.navigation_list);
        navigationAdapter = new NavigationDrawerArrayAdapter(this, pages);
        drawerList.setAdapter(navigationAdapter);
        drawerList.setOnItemClickListener(new ListView.OnItemClickListener() {
            @Override
            public void onItemClick(@SuppressWarnings("rawtypes") AdapterView parent, View view, int position,
                    long id) {
                openPage(position);
                drawerLayout.closeDrawer(drawerContainer);
            }
        });
        buttonQuit = findViewById(R.id.navigation_buttonQuit);
        buttonQuit.setOnClickListener(this);

        if (Build.VERSION.SDK_INT >= 19) {
            // Android 4.4+ only
            boolean translucentStatus = preferences.getBoolean(Constants.PREFERENCE_TRANSLUCENTSTATUSBAR,
                    Constants.DEFAULT_TRANSLUCENTSTATUSBAR);
            boolean translucentNavigation = preferences.getBoolean(Constants.PREFERENCE_TRANSLUCENTNAVIGATIONBAR,
                    Constants.DEFAULT_TRANSLUCENTNAVIGATIONBAR);

            if (translucentStatus)
                getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
            if (translucentNavigation)
                getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

            SystemBarTintManager tintManager = new SystemBarTintManager(this);
            if (translucentStatus) {
                tintManager.setStatusBarTintEnabled(true);
                tintManager.setStatusBarTintResource(R.color.actionBarBackground);
            }
        }

        textViewArtist = (TextView) findViewById(R.id.textViewArtist);
        textViewTitle = (TextView) findViewById(R.id.textViewTitle);
        textViewTime = (TextView) findViewById(R.id.textViewTime);
        imageViewSongImage = (ImageView) findViewById(R.id.imageViewSongImage);
        imageButtonPrevious = (ImageButton) findViewById(R.id.imageButtonPrevious);
        imageButtonPlayPause = (ImageButton) findViewById(R.id.imageButtonPlayPause);
        imageButtonNext = (ImageButton) findViewById(R.id.imageButtonNext);
        seekBar1 = (SeekBar) findViewById(R.id.seekBar1);
        seekBar2 = (SeekBar) findViewById(R.id.seekBar2);
        imageButtonShowSeekbar2 = (ImageButton) findViewById(R.id.imageButtonShowSeekbar2);
        imageButtonShuffle = (ImageButton) findViewById(R.id.imageButtonShuffle);
        imageButtonRepeat = (ImageButton) findViewById(R.id.imageButtonRepeat);
        imageButtonRepeatAll = (ImageButton) findViewById(R.id.imageButtonRepeatAll);
        buttonBassBoost = (Button) findViewById(R.id.buttonBassBoost);
        buttonEqualizer = (Button) findViewById(R.id.buttonEqualizer);
        buttonShake = (Button) findViewById(R.id.buttonShake);

        imageButtonShuffle.setOnClickListener(this);
        imageButtonRepeat.setOnClickListener(this);
        imageButtonRepeatAll.setOnClickListener(this);
        buttonBassBoost.setOnClickListener(this);
        buttonEqualizer.setOnClickListener(this);
        buttonShake.setOnClickListener(this);

        imageButtonShowSeekbar2.setOnClickListener(this);
        imageButtonPrevious.setOnClickListener(this);
        imageButtonPlayPause.setOnClickListener(this);
        imageButtonNext.setOnClickListener(this);
        seekBar1.setOnSeekBarChangeListener(this);
        seekBar1.setClickable(false);
        seekBar2.setOnSeekBarChangeListener(this);
        textViewTime.setOnClickListener(this);

        showSongImage = preferences.getBoolean(Constants.PREFERENCE_SHOWSONGIMAGE, Constants.DEFAULT_SHOWSONGIMAGE);
        imagesCache = new LruCache<String, Bitmap>(Constants.IMAGES_CACHE_SIZE);

        serviceIntent = new Intent(this, MusicService.class);
        startService(serviceIntent); // Starts the service if it is not running

        if (preferences.getBoolean(Constants.PREFERENCE_OPENLASTPAGEONSTART,
                Constants.DEFAULT_OPENLASTPAGEONSTART)) {
            openPage(preferences.getInt(Constants.PREFERENCE_LASTPAGE, Constants.DEFAULT_LASTPAGE));
        } else {
            openPage(PAGE_BROWSER);
        }
        loadSongFromIntent();

        layoutPlaybackControls = findViewById(R.id.layoutPlaybackControls);
        if (preferences.getBoolean(Constants.PREFERENCE_ENABLEGESTURES, Constants.DEFAULT_ENABLEGESTURES)) {
            final GestureDetectorCompat gestureDetector = new GestureDetectorCompat(this,
                    new PlayerGestureListener());
            View layoutTop = findViewById(R.id.layoutTop);
            layoutTop.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return gestureDetector.onTouchEvent(event);
                }
            });
            if (preferences.getBoolean(Constants.PREFERENCE_SHOWPLAYBACKCONTROLS,
                    Constants.DEFAULT_SHOWPLAYBACKCONTROLS)) {
                layoutPlaybackControls.setVisibility(View.VISIBLE);
            }
        } else {
            layoutPlaybackControls.setVisibility(View.VISIBLE);
        }
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

    /* Activity comes foreground */
    @Override
    public void onStart() {
        super.onStart();
        // The service is bound to this activity
        if (musicService == null) {
            createMusicConnection();
            bindService(serviceIntent, musicConnection, Context.BIND_AUTO_CREATE);
        }
    }

    /* Called after onStart or when the screen is switched on. */
    @Override
    public void onResume() {
        super.onResume();
        if (musicService != null)
            startRoutine();

        // Enable the broadcast receiver
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.andreadec.musicplayer.newsong");
        intentFilter.addAction("com.andreadec.musicplayer.playpausechanged");
        intentFilter.addAction("com.andreadec.musicplayer.podcastdownloadcompleted");
        intentFilter.addAction("com.andreadec.musicplayer.quitactivity");
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals("com.andreadec.musicplayer.newsong")) {
                    updatePlayingItem();
                } else if (intent.getAction().equals("com.andreadec.musicplayer.playpausechanged")) {
                    updatePlayPauseButton();
                } else if (intent.getAction().equals("com.andreadec.musicplayer.podcastdownloadcompleted")) {
                    if (currentPage == PAGE_PODCASTS) {
                        PodcastsFragment podcastsFragment = (PodcastsFragment) currentFragment;
                        podcastsFragment.updateListView(true);
                    }
                } else if (intent.getAction().equals("com.andreadec.musicplayer.quitactivity")) {
                    finish(); // I don't call quitActivity() because the service closes himself after sending this broadcast
                }

            }
        };
        registerReceiver(broadcastReceiver, intentFilter);
        updatePlayPauseButton();
    }

    @SuppressLint("NewApi")
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        if (Build.VERSION.SDK_INT >= 11) {
            getActionBar().setTitle(title);
        }
    }

    private void openPage(int page) {
        MusicPlayerFragment fragment;
        switch (page) {
        case PAGE_BROWSER:
            fragment = new BrowserFragment();
            break;
        case PAGE_PLAYLISTS:
            fragment = new PlaylistFragment();
            break;
        case PAGE_RADIOS:
            fragment = new RadioFragment();
            break;
        case PAGE_PODCASTS:
            fragment = new PodcastsFragment();
            break;
        default:
            return;
        }
        currentPage = page;
        currentFragment = fragment;
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.remove(currentFragment);
        transaction.replace(R.id.page, fragment);
        transaction.addToBackStack(null);
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        transaction.commit();
        fragmentManager.executePendingTransactions();
        drawerList.setItemChecked(currentPage, true);
        setTitle(pages[currentPage]);
    }

    /* Called before onStop or when the screen is switched off. */
    @Override
    public void onPause() {
        super.onPause();
        stopPollingThread(); // Stop the polling thread
        unregisterReceiver(broadcastReceiver); // Disable broadcast receiver
    }

    @Override
    public void onStop() {
        super.onStop();
        musicService = null;
        unbindService(musicConnection); // Unbinds from the service
    }

    /* Updates information about the current song. */
    private void updatePlayingItem() {
        PlayableItem playingItem = musicService.getCurrentPlayingItem();

        String titleLines = preferences.getString(Constants.PREFERENCE_TITLELINES, Constants.DEFAULT_TITLELINES);
        if (titleLines.equals("Auto")) {
            textViewTitle.setMinLines(1);
            textViewTitle.setMaxLines(5);
        } else {
            int lines = Integer.parseInt(titleLines);
            textViewTitle.setLines(lines);
            if (lines == 1) {
                textViewTitle.setSingleLine();
                textViewTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE);
                textViewTitle.setHorizontallyScrolling(true);
                textViewTitle.setMarqueeRepeatLimit(-1);
                textViewTitle.setSelected(true);
            }
        }

        if (playingItem != null) {
            // Song loaded
            textViewTitle.setText(playingItem.getTitle());
            textViewArtist.setText(playingItem.getArtist());
            seekBar1.setMax(musicService.getDuration());
            seekBar1.setProgress(musicService.getCurrentPosition());
            seekBar1.setClickable(true);
            isLengthAvailable = playingItem.isLengthAvailable();
            seekBar2.setVisibility(View.GONE);
            if (isLengthAvailable) {
                int duration = musicService.getDuration();
                songDurationString = "/" + Utils.formatTime(duration);
                seekBar1.setVisibility(View.VISIBLE);
                if (duration > Constants.SECOND_SEEKBAR_DURATION) {
                    imageButtonShowSeekbar2.setVisibility(View.VISIBLE);
                    imageButtonShowSeekbar2.setImageResource(R.drawable.expand);
                } else {
                    imageButtonShowSeekbar2.setVisibility(View.GONE);
                }
            } else {
                songDurationString = "";
                seekBar1.setVisibility(View.GONE);
                imageButtonShowSeekbar2.setVisibility(View.GONE);
            }

            if (showSongImage) {
                /*Bitmap image = playingItem.getImage();
                if(image==null) {
                   imageViewSongImage.setImageResource(R.drawable.ic_launcher);
                   imageViewSongImage.setVisibility(View.GONE);
                } else {
                   imageViewSongImage.setImageBitmap(image);
                   imageViewSongImage.setVisibility(View.VISIBLE);
                }*/
                imageViewSongImage.setVisibility(View.GONE);
                int imageSize = (int) getResources().getDimension(R.dimen.songImageSize);
                ImageLoaderTask imageLoader = new ImageLoaderTask(playingItem, imageViewSongImage, imagesCache,
                        imageSize);
                imageLoader.execute();
            } else {
                imageViewSongImage.setImageResource(R.drawable.ic_launcher);
                imageViewSongImage.setVisibility(View.GONE);
            }
        } else {
            // No song loaded
            textViewTitle.setText(R.string.noSong);
            textViewArtist.setText("");
            seekBar1.setMax(10);
            seekBar1.setProgress(0);
            seekBar1.setClickable(false);
            seekBar2.setVisibility(View.GONE);
            imageButtonShowSeekbar2.setVisibility(View.GONE);
            isLengthAvailable = true;
            songDurationString = "";
            seekBar1.setVisibility(SeekBar.GONE);
            imageViewSongImage.setVisibility(View.GONE);
        }
        updatePlayPauseButton();
        updatePosition();

        currentFragment.updateListView();
    }

    /* Updates the play/pause button status according to the playing song. */
    private void updatePlayPauseButton() {
        if (musicService != null && musicService.isPlaying())
            imageButtonPlayPause.setImageResource(R.drawable.pause);
        else
            imageButtonPlayPause.setImageResource(R.drawable.play);
    }

    /* Updates the seekbar and the position information according to the playing song. */
    private void updatePosition() {
        int progress = musicService.getCurrentPosition();
        int duration = musicService.getDuration();
        seekBar1.setProgress(progress);
        if (duration > Constants.SECOND_SEEKBAR_DURATION) {
            int progress2 = progress % Constants.SECOND_SEEKBAR_DURATION;

            int parts = duration / Constants.SECOND_SEEKBAR_DURATION;
            if (progress > parts * Constants.SECOND_SEEKBAR_DURATION) {
                seekBar2.setMax(duration - parts * Constants.SECOND_SEEKBAR_DURATION);
            } else {
                seekBar2.setMax(Constants.SECOND_SEEKBAR_DURATION);
            }
            seekBar2.setProgress(progress2);
        }
        String time;
        if (showRemainingTime && isLengthAvailable) {
            time = "-" + Utils.formatTime(musicService.getDuration() - progress);
        } else {
            time = Utils.formatTime(progress);
        }
        time += songDurationString;
        textViewTime.setText(time);
    }

    /* Updates the shuffle/repeat/repeat_all icons according to the playing song */
    private void updateExtendedMenu() {
        final int on = R.drawable.navigation_button_on;
        final int off = R.drawable.navigation_button_off;
        if (musicService.getShuffle())
            imageButtonShuffle.setBackgroundResource(on);
        else
            imageButtonShuffle.setBackgroundResource(off);
        if (musicService.getRepeat())
            imageButtonRepeat.setBackgroundResource(on);
        else
            imageButtonRepeat.setBackgroundResource(off);
        if (musicService.getRepeatAll())
            imageButtonRepeatAll.setBackgroundResource(on);
        else
            imageButtonRepeatAll.setBackgroundResource(off);
        if (musicService.getBassBoostEnabled())
            buttonBassBoost.setBackgroundResource(on);
        else
            buttonBassBoost.setBackgroundResource(off);
        if (musicService.getEqualizerEnabled())
            buttonEqualizer.setBackgroundResource(on);
        else
            buttonEqualizer.setBackgroundResource(off);
        if (musicService.isShakeEnabled())
            buttonShake.setBackgroundResource(on);
        else
            buttonShake.setBackgroundResource(off);
    }

    /* Called after the service has been bounded. */
    private void startRoutine() {
        updatePlayingItem();
        updateExtendedMenu();

        // Opens the song from the search, if any
        if (searchSong != null) {
            playSongFromSearch(searchSong);
            searchSong = null;
        }

        // Opens the song from the intent, if necessary
        if (intentFile != null) {
            BrowserSong song = new BrowserSong(intentFile);
            playItem(song);
            intentFile = null;
        }

        // Starts the thread to update the seekbar and position information
        if (startPollingThread)
            startPollingThread();
    }

    /* Manages songs opened from an external application */
    @Override
    protected void onNewIntent(Intent newIntent) {
        setIntent(newIntent);
        loadSongFromIntent();
    }

    private void loadSongFromIntent() {
        Intent intent = getIntent();
        if (intent != null && intent.getAction() == Intent.ACTION_VIEW) {
            try {
                intentFile = URLDecoder.decode(intent.getDataString(), "UTF-8");
                intentFile = intentFile.replace("file://", "");
            } catch (Exception e) {
            }
        }
    }

    /* Thread which updates song position polling the information from the service */
    private void startPollingThread() {
        pollingThreadRunning = true;
        new Thread() {
            public void run() {
                while (pollingThreadRunning) {
                    runOnUiThread(new Runnable() {
                        public void run() {
                            updatePosition();
                        }
                    });
                    try {
                        Thread.sleep(POLLING_INTERVAL);
                    } catch (Exception e) {
                    }
                }
            }
        }.start();
    }

    private void stopPollingThread() {
        pollingThreadRunning = false;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (preferences.getBoolean(Constants.PREFERENCE_OPENLASTPAGEONSTART,
                Constants.DEFAULT_OPENLASTPAGEONSTART)) {
            SharedPreferences.Editor editor = preferences.edit();
            editor.putInt(Constants.PREFERENCE_LASTPAGE, currentPage);
            editor.commit();
        }
        //unbindService(musicConnection); // Unbinds from the service
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        boolean navigationDrawerOpen = drawerLayout.isDrawerOpen(drawerContainer);
        if (currentPage == PAGE_BROWSER && !navigationDrawerOpen) {
            menu.findItem(R.id.menu_setAsBaseFolder).setVisible(true);
            menu.findItem(R.id.menu_gotoBaseFolder).setVisible(true);
        } else {
            menu.findItem(R.id.menu_setAsBaseFolder).setVisible(false);
            menu.findItem(R.id.menu_gotoBaseFolder).setVisible(false);
        }
        if (currentPage == PAGE_PODCASTS && !navigationDrawerOpen) {
            menu.findItem(R.id.menu_removeAllEpisodes).setVisible(true);
            menu.findItem(R.id.menu_removeDownloadedEpisodes).setVisible(true);
        } else {
            menu.findItem(R.id.menu_removeAllEpisodes).setVisible(false);
            menu.findItem(R.id.menu_removeDownloadedEpisodes).setVisible(false);
        }
        if (navigationDrawerOpen || musicService == null || musicService.getCurrentPlayingItem() == null) {
            menu.findItem(R.id.menu_songInfo).setVisible(false);
        } else {
            menu.findItem(R.id.menu_songInfo).setVisible(true);
        }
        return true;
    }

    /* A menu item has been selected. */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (drawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        switch (item.getItemId()) {
        case R.id.menu_gotoPlayingSongDirectory:
            gotoPlayingItemPosition();
            return true;
        case R.id.menu_gotoBaseFolder:
            ((BrowserFragment) currentFragment).gotoBaseFolder();
            return true;
        case R.id.menu_search:
            if (preferences.getBoolean(Constants.PREFERENCE_ENABLECACHE, Constants.DEFAULT_ENABLECACHE)) {
                startActivityForResult(new Intent(this, SearchActivity.class), 1);
            } else {
                Utils.showMessageDialog(this, R.string.search, R.string.searchNotPossible);
            }
            return true;
        case R.id.menu_songInfo:
            showItemInfo(musicService.getCurrentPlayingItem());
            return true;
        case R.id.menu_setAsBaseFolder:
            setBaseFolder(((MusicPlayerApplication) getApplication()).getCurrentDirectory().getDirectory());
            return true;
        case R.id.menu_removeAllEpisodes:
            ((PodcastsFragment) currentFragment).removeAllEpisodes();
            return true;
        case R.id.menu_removeDownloadedEpisodes:
            ((PodcastsFragment) currentFragment).removeDownloadedEpisodes();
            return true;
        case R.id.menu_preferences:
            startActivity(new Intent(this, PreferencesActivity.class));
            return true;
        case R.id.menu_quit:
            quitApplication();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        return currentFragment.onContextItemSelected(item);
    }

    /* Button click handler. */
    @Override
    public void onClick(View view) {
        if (view.equals(imageButtonPlayPause)) {
            musicService.playPause();
            updatePlayPauseButton();
        } else if (view.equals(imageButtonNext)) {
            musicService.nextItem();
        } else if (view.equals(imageButtonPrevious)) {
            musicService.previousItem(false);
        } else if (view.equals(textViewTime)) {
            showRemainingTime = !showRemainingTime;
        } else if (view.equals(imageButtonShuffle)) {
            musicService.setShuffle(!musicService.getShuffle());
            updateExtendedMenu();
        } else if (view.equals(imageButtonRepeat)) {
            musicService.setRepeat(!musicService.getRepeat());
            updateExtendedMenu();
        } else if (view.equals(imageButtonRepeatAll)) {
            musicService.setRepeatAll(!musicService.getRepeatAll());
            updateExtendedMenu();
        } else if (view.equals(buttonBassBoost)) {
            if (musicService.getBassBoostAvailable()) {
                bassBoostSettings();
            } else {
                Utils.showMessageDialog(this, R.string.error, R.string.errorBassBoost);
            }
        } else if (view.equals(buttonEqualizer)) {
            if (musicService.getEqualizerAvailable()) {
                equalizerSettings();
            } else {
                Utils.showMessageDialog(this, R.string.error, R.string.errorEqualizer);
            }
        } else if (view.equals(buttonShake)) {
            musicService.toggleShake();
            updateExtendedMenu();
        } else if (view.equals(imageButtonShowSeekbar2)) {
            if (seekBar2.getVisibility() == View.VISIBLE) {
                imageButtonShowSeekbar2.setImageResource(R.drawable.expand);
                seekBar2.setVisibility(View.GONE);
            } else {
                imageButtonShowSeekbar2.setImageResource(R.drawable.collapse);
                seekBar2.setVisibility(View.VISIBLE);
            }
        } else if (view.equals(buttonQuit)) {
            quitApplication();
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        // Called when SearchActivity returns
        super.onActivityResult(requestCode, resultCode, intent);
        if (resultCode == 1) { // If result code is 0, the user canceled the operation
            BrowserSong song = (BrowserSong) intent.getSerializableExtra("song");
            File songDirectory = new File(song.getPlayableUri()).getParentFile();
            BrowserDirectory browserDirectory = new BrowserDirectory(songDirectory);
            song.setBrowser(browserDirectory);
            //playSongFromSearch(song);
            searchSong = song;
        }
    }

    /* ALWAYS CALL THIS FUNCTION TO COMPLETELY CLOSE THE APPLICATION */
    public void quitApplication() {
        stopService(serviceIntent); // Stop the service!
        finish();
    }

    public void playItem(PlayableItem item) {
        boolean ok = musicService.playItem(item);
        if (!ok) {
            Utils.showMessageDialog(this, R.string.errorSong, R.string.errorSongMessage);
        }
    }

    public void playSongFromSearch(BrowserSong song) {
        boolean ok = musicService.playItem(song);
        if (!ok) {
            Utils.showMessageDialog(this, R.string.errorSong, R.string.errorSongMessage);
        }
        gotoPlayingItemPosition();
    }

    public void playRadio(Radio radio) {
        new PlayRadioTask(radio).execute();
    }

    public void playPodcastEpisodeStreaming(PodcastEpisode episode) {
        new PlayPodcastEpisodeStreamingTask(episode).execute();
    }

    public PlayableItem getCurrentPlayingItem() {
        if (musicService == null)
            return null;
        return musicService.getCurrentPlayingItem();
    }

    public void gotoPlayingItemPosition() {
        final PlayableItem playingItem = musicService.getCurrentPlayingItem();
        if (playingItem == null)
            return;
        if (playingItem instanceof BrowserSong) {
            openPage(PAGE_BROWSER);
        } else if (playingItem instanceof PlaylistSong) {
            openPage(PAGE_PLAYLISTS);
        } else if (playingItem instanceof Radio) {
            openPage(PAGE_RADIOS);
        } else if (playingItem instanceof PodcastEpisode) {
            openPage(PAGE_PODCASTS);
        }
        currentFragment.gotoPlayingItemPosition(playingItem);
    }

    public void setBaseFolder(final File folder) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.setAsBaseFolder);
        builder.setMessage(R.string.setBaseFolderConfirm);
        builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                saveBaseFolder(folder);
            }
        });
        builder.setNegativeButton(R.string.no, null);
        builder.show();
    }

    private void saveBaseFolder(final File folder) {
        SharedPreferences.Editor editor = preferences.edit();
        editor.putString(Constants.PREFERENCE_BASEFOLDER, folder.getAbsolutePath());
        editor.commit();

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.setAsBaseFolder);
        builder.setMessage(R.string.indexBaseFolderConfirm);
        builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                Intent indexIntent = new Intent(MainActivity.this, IndexFolderService.class);
                indexIntent.putExtra("folder", folder.getAbsolutePath());
                startService(indexIntent);
            }
        });
        builder.setNegativeButton(R.string.no, null);
        builder.show();
    }

    /* Back button click handler. Overwrites default behaviour. */
    boolean backPressedOnce = false; // Necessary to implement double-tap-to-quit-app

    @Override
    public void onBackPressed() {
        if (backPressedOnce) {
            quitApplication();
            return;
        }
        boolean executed = currentFragment.onBackPressed();
        if (!executed && preferences.getBoolean(Constants.PREFERENCE_ENABLEBACKDOUBLEPRESSTOQUITAPP,
                Constants.DEFAULT_ENABLEBACKDOUBLEPRESSTOQUITAPP)) {
            backPressedOnce = true;
            Toast.makeText(this, R.string.pressAgainToQuitApp, Toast.LENGTH_SHORT).show();
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    backPressedOnce = false;
                }
            }, 2000);
        }
    }

    /* Seekbar click handler. */
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) { // Event is triggered only if the seekbar position was modified by the user
            if (seekBar.equals(seekBar1)) {
                musicService.seekTo(progress);
            } else if (seekBar.equals(seekBar2)) {
                int progress2 = (seekBar1.getProgress() / Constants.SECOND_SEEKBAR_DURATION)
                        * Constants.SECOND_SEEKBAR_DURATION;
                musicService.seekTo(progress2 + progress);
            }
            updatePosition();
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }

    private ServiceConnection musicConnection;

    private void createMusicConnection() {
        musicConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName className, IBinder service) {
                musicService = ((MusicService.MusicBinder) service).getService();
                startRoutine();
            }

            @Override
            public void onServiceDisconnected(ComponentName className) {
                musicService = null;
            }
        };
    }

    private class PlayRadioTask extends AsyncTask<Void, Void, Boolean> {
        private ProgressDialog progressDialog;
        private Radio radio;

        public PlayRadioTask(Radio radio) {
            this.radio = radio;
            progressDialog = new ProgressDialog(MainActivity.this);
        }

        @Override
        protected void onPreExecute() {
            progressDialog.setIndeterminate(true);
            progressDialog.setCancelable(true);
            progressDialog.setOnCancelListener(new OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    cancel(true);
                }
            });
            progressDialog.setCanceledOnTouchOutside(false);
            progressDialog.setMessage(MainActivity.this.getString(R.string.loadingRadio, radio.getTitle()));
            progressDialog.show();
            startPollingThread = false;
            stopPollingThread(); // To prevent polling thread activation
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            return musicService.playItem(radio);
        }

        @Override
        protected void onCancelled() {
            musicService.playItem(null);
        }

        @Override
        protected void onPostExecute(final Boolean success) {
            updatePlayingItem();
            if (progressDialog.isShowing()) {
                progressDialog.dismiss();
            }
            startPollingThread = true;
            if (!pollingThreadRunning)
                startPollingThread();

            if (!success) {
                Utils.showMessageDialog(MainActivity.this, R.string.errorWebRadio, R.string.errorWebRadioMessage);
            }
        }
    }

    private class PlayPodcastEpisodeStreamingTask extends AsyncTask<Void, Void, Boolean> {
        private ProgressDialog progressDialog;
        private PodcastEpisode episode;

        public PlayPodcastEpisodeStreamingTask(PodcastEpisode episode) {
            this.episode = episode;
            progressDialog = new ProgressDialog(MainActivity.this);
        }

        @Override
        protected void onPreExecute() {
            progressDialog.setIndeterminate(true);
            progressDialog.setCancelable(true);
            progressDialog.setOnCancelListener(new OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    cancel(true);
                }
            });
            progressDialog.setCanceledOnTouchOutside(false);
            progressDialog
                    .setMessage(MainActivity.this.getString(R.string.loadingPodcastEpisode, episode.getTitle()));
            progressDialog.show();
            startPollingThread = false;
            stopPollingThread(); // To prevent polling thread activation
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            return musicService.playItem(episode);
        }

        @Override
        protected void onCancelled() {
            musicService.playItem(null);
        }

        @Override
        protected void onPostExecute(final Boolean success) {
            updatePlayingItem();
            if (progressDialog.isShowing()) {
                progressDialog.dismiss();
            }
            startPollingThread = true;
            if (!pollingThreadRunning)
                startPollingThread();

            if (!success) {
                Utils.showMessageDialog(MainActivity.this, R.string.error, R.string.errorSong);
            }
        }
    }

    private void bassBoostSettings() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.bassBoost);
        View view = getLayoutInflater().inflate(R.layout.layout_bassboost, null);
        builder.setView(view);

        builder.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                updateExtendedMenu();
            }
        });
        builder.setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                updateExtendedMenu();
            }
        });

        CheckBox checkBoxBassBoostEnable = (CheckBox) view.findViewById(R.id.checkBoxBassBoostEnabled);
        checkBoxBassBoostEnable.setChecked(musicService.getBassBoostEnabled());
        checkBoxBassBoostEnable.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                musicService.toggleBassBoost();
                updateExtendedMenu();
            }
        });

        SeekBar seekbar = (SeekBar) view.findViewById(R.id.seekBarBassBoostStrength);
        seekbar.setMax(1000);
        seekbar.setProgress(musicService.getBassBoostStrength());
        seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {
                    musicService.setBassBoostStrength(seekBar.getProgress());
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar arg0) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar arg0) {
            }
        });

        builder.show();
    }

    private void equalizerSettings() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.equalizer);
        View view = getLayoutInflater().inflate(R.layout.layout_equalizer, null);
        builder.setView(view);

        builder.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                updateExtendedMenu();
            }
        });
        builder.setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                updateExtendedMenu();
            }
        });

        CheckBox checkBoxEqualizerEnabled = (CheckBox) view.findViewById(R.id.checkBoxEqualizerEnabled);
        checkBoxEqualizerEnabled.setChecked(musicService.getEqualizerEnabled());
        checkBoxEqualizerEnabled.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                musicService.toggleEqualizer();
                updateExtendedMenu();
            }
        });

        String[] availablePresets = musicService.getEqualizerAvailablePresets();
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
                availablePresets);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        Spinner spinnerEqualizerPreset = (Spinner) view.findViewById(R.id.spinnerEqualizerPreset);
        spinnerEqualizerPreset.setAdapter(adapter);
        spinnerEqualizerPreset.setSelection(musicService.getEqualizerPreset());

        spinnerEqualizerPreset.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                musicService.setEqualizerPreset(position);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
        builder.show();
    }

    public boolean getShowSongImage() {
        return showSongImage;
    }

    public LruCache<String, Bitmap> getImagesCache() {
        return imagesCache;
    }

    private void showItemInfo(PlayableItem item) {
        if (item == null || item.getInformation() == null)
            return;
        ArrayList<Information> information = item.getInformation();

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.songInfo);
        View view = getLayoutInflater().inflate(R.layout.layout_songinfo, null, false);
        LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.linearLayoutInformation);

        Bitmap image = item.getImage();
        if (image != null) {
            ImageView imageView = new ImageView(this);
            imageView.setImageBitmap(image);
            linearLayout.addView(imageView);
        }

        for (Information info : information) {
            TextView info1 = new TextView(this);
            info1.setTextAppearance(this, android.R.style.TextAppearance_Medium);
            info1.setText(getResources().getString(info.key));
            TextView info2 = new TextView(this);
            info2.setText(info.value);
            info2.setPadding(0, 0, 0, 10);
            linearLayout.addView(info1);
            linearLayout.addView(info2);
        }

        builder.setView(view);
        builder.setPositiveButton(R.string.ok, null);
        builder.show();
    }

    private class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent event) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
            if (event1.getX() < event2.getX())
                musicService.previousItem(false);
            else if (event1.getX() > event2.getX())
                musicService.nextItem();
            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {
            musicService.playPause();
            return true;
        }
    }
}