com.smp.musicspeed.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.smp.musicspeed.MainActivity.java

Source

package com.smp.musicspeed;

import static com.smp.musicspeed.TextHelper.*;
import static com.smp.musicspeed.UtilityMethods.*;

import java.io.File;
import java.io.IOException;

import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.InterstitialAd;
import com.ipaulpro.afilechooser.utils.FileUtils;
import com.pheelicks.visualizer.VisualizerView;
import com.pheelicks.visualizer.renderer.BarGraphRenderer;
import com.smp.musicspeed.AdjustmentFragment.OnNumberEnteredListener;
import com.smp.musicspeed.ImportDialogFragment.ImportDialogFragmentListener;
import com.smp.musicspeed.PlayFileService.SoundStreamControlBinder;
import com.smp.soundtouchandroid.SoundStreamRuntimeException;
import static com.smp.musicspeed.Constants.*;
import android.media.audiofx.Visualizer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.Notification;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SwitchCompat;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Switch;
import android.widget.TextSwitcher;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;

public class MainActivity extends ActionBarActivity
        implements OnNumberEnteredListener, ImportDialogFragmentListener {
    private static final String MY_AD_UNIT_ID = "ca-app-pub-7592316401695950/1294338224";
    private static final String TEST_DEVICE = "54BEF252B42F93A4F19036ABE8E1CDDB";
    private static final int REQUEST_CODE = 6384;

    private static final int LINKED_VIEW = 1;
    private static final int UNLINKED_VIEW = 0;

    private static final float SLOW_SPEED_RANGE = 0.67f;
    private static final float SLOW_SPEED_MIN = 0.33f;

    private static final float FAST_SPEED_RANGE = 2.0f;
    private static final float FAST_SPEED_MIN = 1.0f;
    private static final float FAST_SPEED_MAX = FAST_SPEED_MIN + FAST_SPEED_RANGE;

    private static final float PITCH_MAX = 12.0f;
    private static final float PITCH_MIN = -12.0f;

    private static final float DECIMAL_PLACES_TEMPO = 100.0f;
    private static final float DECIMAL_PLACES_PITCH = 10.0f;

    private static final int BEGINNING_OF_FILE = 0;

    private static final String FILE = "";

    private static final long US_IN_MIN = 60000000;
    private static final long US_IN_SEC = 1000000;

    private static final String BLANK_TIME = "--:--";

    private int DEFAULT_PROGRESS_PITCH;
    private int DEFAULT_PROGRESS_TEMPO;
    private int DEFAULT_PROGRESS_RATE;

    private SeekBar playBar, pitchBar, tempoBar, rateBar;
    private VisualizerView visualizerView;
    private AdView adView;
    private TextView pitchText, tempoText, rateText, fileText;
    private TextView timeText, durationText;
    private View loopImage;
    private PlayFileService service;
    private SeekBarListener seekListen;
    private ImageButton playButton, loopStartButton, loopEndButton, loopClearButton;
    private ImageButton tempoKeysButton, pitchKeysButton, rateKeysButton;
    private SwitchCompat linkSwitch;
    private InterstitialAd interstitial;
    private Intent oldIntent;
    private View tempoCard, pitchCard, rateCard;

    // private TextSwitcher rateSwitcher;

    // private FrameLayout cardFrame;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DEFAULT_PROGRESS_PITCH = getResources().getInteger(R.integer.default_progress_pitch);
        DEFAULT_PROGRESS_TEMPO = getResources().getInteger(R.integer.default_progress_tempo);
        DEFAULT_PROGRESS_RATE = getResources().getInteger(R.integer.default_progress_rate);

        playBar = (SeekBar) findViewById(R.id.seek_play);
        tempoBar = (SeekBar) findViewById(R.id.seek_tempo);
        pitchBar = (SeekBar) findViewById(R.id.seek_pitch);
        rateBar = (SeekBar) findViewById(R.id.seek_rate);

        pitchText = (TextView) findViewById(R.id.pitch_text);
        tempoText = (TextView) findViewById(R.id.tempo_text);
        rateText = (TextView) findViewById(R.id.rate_text);
        fileText = (TextView) findViewById(android.R.id.title);
        timeText = (TextView) findViewById(R.id.text_time);
        durationText = (TextView) findViewById(R.id.text_duration);

        loopImage = findViewById(R.id.img_loop);

        playButton = (ImageButton) findViewById(R.id.button_play);
        loopStartButton = (ImageButton) findViewById(R.id.button_loop_start);
        loopEndButton = (ImageButton) findViewById(R.id.button_loop_end);
        loopClearButton = (ImageButton) findViewById(R.id.button_loop_clear);
        tempoKeysButton = (ImageButton) findViewById(R.id.button_keys_tempo);
        pitchKeysButton = (ImageButton) findViewById(R.id.button_keys_pitch);
        rateKeysButton = (ImageButton) findViewById(R.id.button_keys_rate);
        linkSwitch = (SwitchCompat) findViewById(R.id.link_toggle);

        // rateSwitcher = (TextSwitcher) findViewById(R.id.rate_switcher);

        tempoCard = findViewById(R.id.card_tempo);
        pitchCard = findViewById(R.id.card_pitch);
        rateCard = findViewById(R.id.card_rate);
        // pitchTempoCards = findViewById(R.id.pitch_tempo_cards);
        // cardFrame = (ViewFlipper) findViewById(R.id.card_frame);

        /*
         * Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
         * toolbar.setTitle(""); setSupportActionBar(toolbar);
         */
        getSupportActionBar().setTitle("");

        seekListen = new SeekBarListener();
        playBar.setOnSeekBarChangeListener(seekListen);
        tempoBar.setOnSeekBarChangeListener(seekListen);
        pitchBar.setOnSeekBarChangeListener(seekListen);
        rateBar.setOnSeekBarChangeListener(seekListen);

        if (Build.VERSION.SDK_INT >= 21) {
            getSupportActionBar().setElevation(0);
        }

        readPrefs();

        linkSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
                handleSwitch();
            }

        });

        visualizerView = (VisualizerView) findViewById(R.id.visualizer_view);
        addBarGraphRenderers();

        adView = (AdView) this.findViewById(R.id.adview);
        AdRequest adRequest = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                .addTestDevice(TEST_DEVICE).build();

        adView.setAdListener(new AdListener() {
            @Override
            public void onAdLoaded() {
                adView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAdFailedToLoad(int code) {
                adView.setVisibility(View.GONE);
            }
        });
        adView.loadAd(adRequest);

        initInterstitialAd();

        cleanUp();
    }

    private static final String PREF_NAME = "com.smp.musicspeed.prefs";
    private static final String PREF_LINKED = "com.smp.musicspeed.prefs.LINKED";

    private void readPrefs() {
        Context mContext = getApplicationContext();
        SharedPreferences prefs = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
        boolean linked = prefs.getBoolean(PREF_LINKED, false);

        if (linked) {
            linkSwitch.setChecked(linked);
            pitchCard.setVisibility(View.GONE);
            tempoCard.setVisibility(View.GONE);
            rateCard.setVisibility(View.VISIBLE);
        }
    }

    private void writePrefs() {
        Context mContext = getApplicationContext();
        SharedPreferences prefs = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean(PREF_LINKED, linkSwitch.isChecked());
        editor.commit();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("com.smp.linked", linkSwitch.isChecked());
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedState) {
        super.onRestoreInstanceState(savedState);

    }

    public void onClickOpen(View view) {
        showChooser();
    }

    public void onResetClicked(View view) {
        resetSeekbars();
        String st = getResources().getString(R.string.original_values);
        makeToastShort(st);
    }

    private void linkOn() {
        resetSeekbars();
        pitchCard.setVisibility(View.GONE);
        tempoCard.setVisibility(View.GONE);
        rateCard.setVisibility(View.VISIBLE);

    }

    private void linkOff() {
        resetSeekbars();
        pitchCard.setVisibility(View.VISIBLE);
        tempoCard.setVisibility(View.VISIBLE);
        rateCard.setVisibility(View.GONE);
    }

    private void resetSeekbars() {
        rateBar.setProgress(rateBar.getMax() / 2);
        pitchBar.setProgress(pitchBar.getMax() / 2);
        tempoBar.setProgress(tempoBar.getMax() / 2);
    }

    private static final int TRANS_ANIMATION_TIME = 700;
    private static final int TEXT_ANIMATION_TIME = 400;

    private void animateLinkOn() {

        TranslateAnimation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
                Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
                -1.0f);
        anim.setDuration(TRANS_ANIMATION_TIME);
        anim.setInterpolator(new AnticipateOvershootInterpolator());
        anim.setAnimationListener(new AnimationListenerAdaptor() {
            @Override
            public void onAnimationEnd(Animation animation) {
                rateText.setAlpha(0f);
                linkOn();

                rateText.animate().alpha(1f).setDuration(TRANS_ANIMATION_TIME)
                        .setListener(new AnimatorListenerAdapter() {
                        });
            }
        });
        tempoCard.startAnimation(anim);
        tempoText.animate().alpha(0f).setDuration(TEXT_ANIMATION_TIME).setListener(new AnimatorListenerAdapter() {
        });
    }

    private void animateLinkOff() {
        linkOff();
        tempoCard.setVisibility(View.INVISIBLE);

        TranslateAnimation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
                Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
                1.0f);
        anim.setDuration(TRANS_ANIMATION_TIME);
        anim.setInterpolator(new AnticipateOvershootInterpolator());
        anim.setAnimationListener(new AnimationListenerAdaptor() {
            @Override
            public void onAnimationEnd(Animation animation) {
                tempoText.setAlpha(0f);
                linkOff();

                tempoText.animate().alpha(1f).setDuration(TEXT_ANIMATION_TIME)
                        .setListener(new AnimatorListenerAdapter() {
                        });
            }
        });
        rateCard.startAnimation(anim);
        rateText.animate().alpha(0f).setDuration(TRANS_ANIMATION_TIME).setListener(new AnimatorListenerAdapter() {
        });
    }

    public void handleSwitch() {
        boolean on = linkSwitch.isChecked();
        if (on) {
            animateLinkOn();
        } else {
            animateLinkOff();
        }
    }

    public void onToggleClicked(final View view) {

    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_share:
            startShare();
            break;
        case R.id.action_save:
            startSave();
            break;
        case R.id.action_open:
            showChooser();
            break;
        case R.id.action_licenses:
            startActivity(new Intent(this, LicenseActivity.class));
            break;

        }
        return true;
    }

    private void startShare() {
        Intent intent = new Intent(android.content.Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);

        // Add data to the intent, the receiving app will decide what to do with
        // it.
        String fileName = null;
        if (service != null && service.getFileName() != null) {
            fileName = new File(service.getFileName()).getName();
        }
        String music = fileName == null ? "music" : fileName;
        intent.putExtra(Intent.EXTRA_SUBJECT, "Music Speed Changer");
        intent.putExtra(Intent.EXTRA_TEXT,
                "I'm listening to " + music
                        + " at a different tempo and pitch with Music Speed Changer, available at Google Play: "
                        + "https://play.google.com/store/apps/details?id=com.smp.musicspeed");

        startActivity(Intent.createChooser(intent, "How do you want to share?"));

    }

    private void startSave() {
        String fileName = service.getFileName();
        if (!(fileName == null)) {
            if (!isMyServiceRunning(this, FileWriterService.class)) {
                Intent intent = new Intent(this, FileWriterService.class);
                intent.putExtra(INTENT_FILE_NAME_IN, fileName);
                intent.putExtra(INTENT_TEMPO, service.getTempo());
                intent.putExtra(INTENT_PITCH, service.getPitchSemi());
                intent.putExtra(INTENT_RATE, service.getRate());
                intent.putExtra(INTENT_LINKED, linkSwitch.isChecked());
                startService(intent);
                if (interstitial.isLoaded())
                    interstitial.show();
            } else {
                makeToastShort(TOAST_SERVICE_RUNNING);
            }
        } else {
            makeToastShort(TOAST_SELECT_FILE);
        }

    }

    private void initInterstitialAd() {
        interstitial = new InterstitialAd(this);
        interstitial.setAdUnitId(MY_AD_UNIT_ID);
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder iBinder) {
            SoundStreamControlBinder binder = (SoundStreamControlBinder) iBinder;
            MainActivity.this.service = binder.getService();
            binder.setListener(new PlayFileBoundServiceListener() {
                @Override
                public void onProgressChanged(int track, final double currentPercentage, long position) {
                    if (!seekListen.getPlayTouched()) {
                        int maxProgress = playBar.getMax();
                        int currentProgress = (int) Math.floor(maxProgress * currentPercentage);
                        playBar.setProgress(currentProgress);
                        setPlayedTime(position);
                    }
                }

                @Override
                public void onTrackFinished(int track) {
                    playBar.post(new Runnable() {
                        @Override
                        public void run() {

                            setPlayImage();
                            // playBar.setProgress(0);
                            // setPlayedTime(service.getPlayedDuration());

                        }

                    });
                }

                @Override
                public void releaseServiceReference() {
                    service = null;
                }

                @Override
                public void shouldChangePlayImage() {
                    setPlayImage();
                }

                @Override
                public void onExceptionThrown() {
                    MainActivity.this.makeToastShort(TOAST_PROBLEM_PLAYING);
                    MainActivity.this.onInvalidFile();
                }
            });

            // pendingFile is not null if the service has been stopped via the
            // notification
            // and the user is in the file chooser.

            if (pendingFile != null) {
                try {
                    Log.d("FILE", "onNewFile() called on " + pendingFile);
                    onNewFile(pendingFile);
                } catch (IOException e) {
                    logException(Log.getStackTraceString(e));
                    e.printStackTrace();
                    onInvalidFile();
                } catch (SoundStreamRuntimeException e) {
                    logException(Log.getStackTraceString(e));
                    e.printStackTrace();
                    onInvalidFile();
                }
                pendingFile = null;
            }

            if (getIntent() != null && getIntent().getAction() == Intent.ACTION_VIEW
                    && !isMyServiceRunning(MainActivity.this, HardPathService.class)) {
                processNewFileIntent(getIntent());
            }

            // TODO Refactor this?
            setPitchText(service.getPitchSemi());
            setTempoText(service.getTempo());
            setRateText(service.getRate());
            setPitchBar(service.getPitchSemi());
            setTempoBar(service.getTempo());
            setRateBar(service.getRate());
            setPlayBar(service.getPlayedDuration());
            initVisualizerView();
            determineLooping();
            setDurationText(service.getDuration());
            setPlayedTime(service.getPlayedDuration());
            String file = service.getFileName();
            showFileName(file);
            uiEnabled(file != null);
            setPlayImage();

            //

            stopServiceForeground();
        }

        private void setPlayBar(long playedDuration) {
            int maxProgress = playBar.getMax();
            long pd = service.getPlayedDuration();
            long d = service.getDuration();
            double cp = pd == 0 ? 0 : (double) pd / d;
            int currentProgress = (int) Math.round(maxProgress * cp);
            if (pd == PlayFileService.NOT_SET)
                currentProgress = 0;
            playBar.setProgress(currentProgress);
        }

        private void setTempoBar(float tempo) {
            int progress = calculateProgressFromTempo(tempo);
            tempoBar.setProgress(progress);
        }

        private void setRateBar(float rate) {
            int progress = calculateProgressFromRate(rate);
            rateBar.setProgress(progress);
        }

        private void setPitchBar(float pitchSemi) {
            int progress = calculateProgressFromPitch(pitchSemi);
            pitchBar.setProgress(progress);
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {

        }
    };

    private String pendingFile;

    private void startServiceForeground() {
        Notification not = NotificationHelper.generatePlayFileNotification(this, false, service.getFileName(),
                service.getPitchSemi(), service.getTempo(), service.getRate());

        service.startForeground(ID_PLAYER_NOTIFICATION, not);
    }

    private void stopServiceForeground() {
        service.stopForeground(true);
    }

    private void determineLooping() {
        if (service.isLooping())
            loopImage.setVisibility(View.VISIBLE);
        else
            loopImage.setVisibility(View.INVISIBLE);
    }

    private void setTempoText(float tempo) {
        tempoText.setText(TEMPO + getFormattedTempo(tempo));
    }

    private void setRateText(float rateChange) {
        rateText.setText(RATE + getFormattedRate(rateChange));
    }

    private void setPitchText(float pitch) {
        pitchText.setText(PITCH + getFormattedPitch(pitch));
    }

    private void uiEnabled(boolean value) {
        playBar.setEnabled(value);
        pitchBar.setEnabled(value);
        tempoBar.setEnabled(value);
        rateBar.setEnabled(value);
        tempoKeysButton.setEnabled(value);
        pitchKeysButton.setEnabled(value);
        rateKeysButton.setEnabled(value);
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onPause() {
        if (adView != null) {
            adView.pause();
        }
        if (service != null) {
            if (!service.isPaused() && !(service.getFileName() == null))
                startServiceForeground();
            /*
             * if (service.hasVisualizer()) service.setVisualizerEnabled(false);
             */
        }
        unbindService(serviceConnection);
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (adView != null) {
            adView.resume();
        }
        if (service != null) {
            stopServiceForeground();
            setPlayImage();

            /*
             * if (service.hasVisualizer()) service.setVisualizerEnabled(true);
             */
        }
        if (!interstitial.isLoaded()) {
            AdRequest adRequest = new AdRequest.Builder().addTestDevice(TEST_DEVICE).build();
            interstitial.loadAd(adRequest);
        }
        Intent intent = new Intent(this, PlayFileService.class);
        startService(intent);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        if (service != null)
            service.releaseListener();
        service = null;
        if (adView != null)
            adView.destroy();
        writePrefs();
        System.gc();
        super.onDestroy();
    }

    private void cleanUp() {
        if (!isMyServiceRunning(this, PlayFileService.class) && !isMyServiceRunning(this, FileWriterService.class)
                && !isMyServiceRunning(this, HardPathService.class)) {
            try {
                FileMethods.deleteTempDir();
            } catch (Exception e) {
                logException(Log.getStackTraceString(e));
                e.printStackTrace();
            }

        }
    }

    private float calculatePitch(int progress) {
        return (progress - DEFAULT_PROGRESS_PITCH) / DECIMAL_PLACES_PITCH;
    }

    private float calculateRate(int progress) {
        return calculateTempo(progress);
    }

    private float calculateTempo(int progress) {
        float tempo;
        float percentage = (float) progress / DEFAULT_PROGRESS_TEMPO;
        if (progress >= DEFAULT_PROGRESS_TEMPO) {
            tempo = Math.round((percentage * FAST_SPEED_RANGE - FAST_SPEED_MIN) * DECIMAL_PLACES_TEMPO)
                    / DECIMAL_PLACES_TEMPO;
        } else {
            tempo = Math.round((percentage * SLOW_SPEED_RANGE + SLOW_SPEED_MIN) * DECIMAL_PLACES_TEMPO)
                    / DECIMAL_PLACES_TEMPO;
        }
        return tempo;
    }

    private int calculateProgressFromPitch(double pitch) {
        return (int) Math.round(pitch * DECIMAL_PLACES_PITCH + DEFAULT_PROGRESS_PITCH);
    }

    private int calculateProgressFromRate(double rate) {
        return calculateProgressFromTempo(rate);
    }

    private int calculateProgressFromTempo(double tempo) {
        int progress;
        double percentage;

        if (tempo >= FAST_SPEED_MIN) {
            percentage = (tempo + FAST_SPEED_MIN) / FAST_SPEED_RANGE;
        } else {
            percentage = (tempo - SLOW_SPEED_MIN) / SLOW_SPEED_RANGE;
        }
        progress = (int) Math.round(percentage * DEFAULT_PROGRESS_TEMPO);
        return progress;
    }

    private class SeekBarListener implements OnSeekBarChangeListener {
        private boolean playTouched;
        private int playSeek;

        boolean getPlayTouched() {
            return playTouched;
        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (seekBar == pitchBar) {
                float pitch = calculatePitch(progress);
                if (service != null) {
                    service.setPitch(pitch);
                    setPitchText(pitch);

                }
            } else if (seekBar == tempoBar) {
                float tempo = calculateTempo(progress);
                if (service != null) {
                    service.setTempo(tempo);
                    setTempoText(tempo);
                }
            } else if (seekBar == rateBar) {
                float rate = calculateRate(progress);
                if (service != null) {
                    service.setRate(rate);
                    setRateText(rate);
                }
            } else if (seekBar == playBar && fromUser) {
                playSeek = progress;
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            if (seekBar == playBar)
                playTouched = true;
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            if (seekBar == playBar) {
                playBar.post(new Runnable() {
                    @Override
                    public void run() {
                        playTouched = false;
                        float percentage = (float) playSeek / playBar.getMax();
                        if (service != null) {
                            service.seekTo(percentage);
                            setPlayedTime(service.getPlayedDuration());
                        }
                    }
                });
            }
        }
    }

    private void addBarGraphRenderers() {
        Paint paint = new Paint();
        paint.setStrokeWidth(10.5f);
        paint.setAntiAlias(true);
        paint.setColor(Color.argb(255, 144, 202, 249));
        BarGraphRenderer barGraphRendererBottom = new BarGraphRenderer(4, paint, false);
        visualizerView.addRenderer(barGraphRendererBottom);
    }

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

    public void onPlay(View view) {
        if (service.getFileName() == null) {
            makeToastShort(TOAST_SELECT_FILE);
        } else {
            service.onPlayCommand();
            setPlayImage();
            if (service.isPaused()) {
                visualizerView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (visualizerView != null && service != null && service.isPaused())
                            visualizerView.setVisibility(View.INVISIBLE);
                    }

                }, 2000);
            } else {
                visualizerView.setVisibility(View.VISIBLE);
            }
        }
    }

    private void setPlayImage() {
        if (service.isPaused()) {
            playButton.setImageResource(R.drawable.ic_play_circle_fill_grey600_36dp);
        } else {
            playButton.setImageResource(R.drawable.ic_pause_circle_fill_grey600_36dp);
        }
    }

    private void showFileName(String fullPath) {
        if (fullPath != null) {
            String nameOnly = new File(fullPath).getName();
            fileText.setText(FILE + nameOnly);
        } else {
            fileText.setText(getResources().getString(R.string.header_file));
        }
    }

    private void showChooser() {
        Intent target = createAudioContentIntent();

        Intent intent = Intent.createChooser(target, getString(R.string.chooser_title));

        startActivityForResult(intent, REQUEST_CODE);
    }

    private Intent createAudioContentIntent() {
        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("audio/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        // intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
        return intent;
    }

    private class Time implements Comparable {
        private int min;
        private int sec;

        Time(long us) {
            min = (int) (us / US_IN_MIN);
            sec = (int) Math.floor((us % US_IN_MIN / (double) US_IN_SEC));
        }

        @Override
        public String toString() {
            return "" + min + ":" + String.format("%02d", sec);
        }

        @Override
        public int compareTo(Object arg) {
            Time other = (Time) arg;
            if (min == other.min && sec == other.sec)
                return 0;
            if (min == other.min) {
                if (sec > other.sec)
                    return 1;
                return -1;
            }
            if (min > other.min)
                return 1;
            return -1;
        }
    }

    private void setDurationText(long time) {
        if (time < 0) {
            durationText.setText(BLANK_TIME);
        } else {
            Time duration = new Time(time);
            durationText.setText(duration.toString());
        }
    }

    private void setPlayedTime(long time) {
        if (time < 0) {
            timeText.setText(BLANK_TIME);
        } else {
            Time played = new Time(time);
            Time duration = new Time(service.getDuration());
            if (played.compareTo(duration) > 0)
                played = duration;
            timeText.setText(played.toString());
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        visualizerView.setVisibility(View.INVISIBLE);
        switch (requestCode) {
        case REQUEST_CODE:

            if (resultCode == RESULT_OK && data != null) {
                oldIntent = getIntent();
                data.setAction(Intent.ACTION_VIEW);
                setIntent(data);
                // processNewFileIntent(data);
            }
            break;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onFilePathReceived(String filePath) {
        if (filePath != null) {
            Uri fileUri = Uri.fromFile(new File(filePath));

            Intent uriIntent = new Intent();
            uriIntent.setAction(Intent.ACTION_VIEW);
            uriIntent.setData(fileUri);
            setIntent(uriIntent);
        }
        processNewFilePath(filePath);
    }

    @Override
    public void onImportCancelled() {
        setIntent(oldIntent);
    }

    private void processNewFileIntent(Intent data) {
        String filePath = FileUtils.getPath(this, data.getData());
        if (filePath != null) {
            processNewFilePath(filePath);
        } else {
            ImportDialogFragment dialog = ImportDialogFragment.newInstance(data.getData());
            dialog.show(getFragmentManager(), "ImportDialogFragment");
        }
    }

    private void processNewFilePath(String filePath) {
        try {
            if (filePath == null) {
                makeToastShort(TOAST_INVALID_FILE);
                // onInvalidFile();
            } else if (service == null) {
                // Log.d("FILE", "service == null");
                pendingFile = filePath;
            } else if (!filePath.equals(service.getFileName())) {
                onNewFile(filePath);
            }
        } catch (IOException e) {
            logException(Log.getStackTraceString(e));
            e.printStackTrace();
            makeToastShort(TOAST_INVALID_FILE);
            onInvalidFile();
        } catch (SoundStreamRuntimeException e) {
            logException(Log.getStackTraceString(e));
            e.printStackTrace();
            makeToastShort(TOAST_INVALID_FILE);
            onInvalidFile();
        } catch (IllegalArgumentException e) {
            logException(Log.getStackTraceString(e));
            e.printStackTrace();
            makeToastShort(TOAST_INVALID_FILE);
            onInvalidFile();
        }
    }

    private void onInvalidFile() {
        service.reset();
        prepareUIForNewFile();
    }

    private void onNewFile(String fileName) throws IOException {
        playBar.setOnSeekBarChangeListener(null);
        if (fileName != null) {
            service.initAudioFile(fileName);
        }
        prepareUIForNewFile();
    }

    private void prepareUIForNewFile() {
        String fileName = service.getFileName();
        resetUI();
        uiEnabled(service.isPlayable());
        showFileName(fileName);
        initVisualizerView();
    }

    private void makeToastShort(String text) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }

    private void initVisualizerView() {
        Visualizer v = service.getVisualizer();
        if (v != null)
            visualizerView.link(v);
    }

    private void resetUI() {
        playBar.post(new Runnable() {

            @Override
            public void run() {
                determineLooping();
                playBar.setProgress(BEGINNING_OF_FILE);
                pitchBar.setProgress(DEFAULT_PROGRESS_PITCH);
                tempoBar.setProgress(DEFAULT_PROGRESS_TEMPO);
                rateBar.setProgress(DEFAULT_PROGRESS_RATE);
                playButton.setImageResource(R.drawable.ic_play_circle_fill_grey600_36dp);
                setDurationText(service.getDuration());
                setPlayedTime(service.getPlayedDuration());
                playBar.setOnSeekBarChangeListener(seekListen);
            }
        });
    }

    private void showAdjustmentFragmentDialog(int adjustment) {
        AdjustmentFragment frag = new AdjustmentFragment();
        Bundle args = new Bundle();
        args.putInt(BUNDLE_ADJUSTMENT, adjustment);
        frag.setArguments(args);
        frag.show(getSupportFragmentManager(), "Adjustment Fragment");
    }

    public void onPitchKeys(View view) {
        showAdjustmentFragmentDialog(AdjustmentFragment.ADJUSTMENT_PITCH);
    }

    public void onTempoKeys(View view) {
        showAdjustmentFragmentDialog(AdjustmentFragment.ADJUSTMENT_TEMPO);
    }

    public void onRateKeys(View view) {
        showAdjustmentFragmentDialog(AdjustmentFragment.ADJUSTMENT_RATE);
    }

    public void onLoopStart(View view) {
        if (service.getFileName() == null) {
            makeToastShort(TOAST_SELECT_FILE);
        } else {
            if (service.setLoopStart()) {
                makeToastShort("Loop start point set.");
            } else {
                makeToastShort(TOAST_INVALID_LOOP_TIME);
            }
            determineLooping();
        }
    }

    public void onLoopEnd(View view) {
        if (service.getFileName() == null) {
            makeToastShort(TOAST_SELECT_FILE);
        } else {
            if (service.setLoopEnd()) {
                makeToastShort("Loop end point set.");
            } else {
                makeToastShort(TOAST_INVALID_LOOP_TIME);
            }
            determineLooping();
        }
    }

    public void onLoopClear(View view) {
        if (service.getFileName() == null) {
            makeToastShort(TOAST_SELECT_FILE);
        } else {
            service.clearLoopPoints();
            Toast.makeText(this, "Loop points cleared.", Toast.LENGTH_SHORT).show();
        }
        determineLooping();
    }

    @Override
    public void onNumberEntered(double num, int adjustment) {
        int progress;
        switch (adjustment) {
        case AdjustmentFragment.ADJUSTMENT_PITCH:
            if (num < PITCH_MIN)
                num = PITCH_MIN;
            else if (num > PITCH_MAX)
                num = PITCH_MAX;
            progress = calculateProgressFromPitch(num);
            pitchBar.setProgress(progress);
            float pitch = (float) num;
            service.setPitch(pitch);
            setPitchText(pitch);
            break;
        case AdjustmentFragment.ADJUSTMENT_TEMPO:
            num /= DECIMAL_PLACES_TEMPO;
            if (num < SLOW_SPEED_MIN)
                num = SLOW_SPEED_MIN;
            else if (num > FAST_SPEED_MAX)
                num = FAST_SPEED_MAX;
            progress = calculateProgressFromTempo(num);
            tempoBar.setProgress(progress);
            float tempo = (float) num;
            service.setTempo(tempo);
            setTempoText(tempo);
            break;
        case AdjustmentFragment.ADJUSTMENT_RATE:
            num /= DECIMAL_PLACES_TEMPO;
            if (num < SLOW_SPEED_MIN)
                num = SLOW_SPEED_MIN;
            else if (num > FAST_SPEED_MAX)
                num = FAST_SPEED_MAX;
            progress = calculateProgressFromRate(num);
            rateBar.setProgress(progress);
            float rate = (float) num;
            service.setRate(rate);
            setRateText(rate);
            break;
        default:
            throw new IllegalArgumentException("Not a valid adjustment");
        }
    }

    static class AnimationListenerAdaptor implements Animation.AnimationListener {

        @Override
        public void onAnimationEnd(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationStart(Animation animation) {
            // TODO Auto-generated method stub

        }

    }

}