com.geecko.QuickLyric.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.geecko.QuickLyric.MainActivity.java

Source

/*
 * *
 *  * This file is part of QuickLyric
 *  * Copyright  2017 QuickLyric SPRL
 *  *
 *  * QuickLyric is free software: you can redistribute it and/or modify
 *  * it under the terms of the GNU General Public License as published by
 *  * the Free Software Foundation, either version 3 of the License, or
 *  * (at your option) any later version.
 *  *
 *  * QuickLyric is distributed in the hope that it will be useful,
 *  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  * GNU General Public License for more details.
 *  * You should have received a copy of the GNU General Public License
 *  * along with QuickLyric.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package com.geecko.QuickLyric;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.media.AudioManager;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;

import com.geecko.QuickLyric.adapter.DrawerAdapter;
import com.geecko.QuickLyric.adapter.IntroScreenSlidePagerAdapter;
import com.geecko.QuickLyric.broadcastReceiver.MusicBroadcastReceiver;
import com.geecko.QuickLyric.fragment.LocalLyricsFragment;
import com.geecko.QuickLyric.fragment.LyricsViewFragment;
import com.geecko.QuickLyric.lyrics.Lyrics;
import com.geecko.QuickLyric.tasks.DBContentLister;
import com.geecko.QuickLyric.tasks.Id3Writer;
import com.geecko.QuickLyric.tasks.IdDecoder;
import com.geecko.QuickLyric.utils.ChangelogStringBuilder;
import com.geecko.QuickLyric.utils.DatabaseHelper;
import com.geecko.QuickLyric.utils.IMMLeaks;
import com.geecko.QuickLyric.utils.LyricsSearchSuggestionsProvider;
import com.geecko.QuickLyric.utils.NightTimeVerifier;
import com.geecko.QuickLyric.utils.RefreshButtonBehavior;
import com.geecko.QuickLyric.utils.Spotify;
import com.geecko.QuickLyric.view.LrcView;
import com.geecko.QuickLyric.view.MaterialSuggestionsSearchView;
import com.geecko.QuickLyric.view.RefreshIcon;
import com.viewpagerindicator.CirclePageIndicator;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.geecko.QuickLyric.R.array;
import static com.geecko.QuickLyric.R.id;
import static com.geecko.QuickLyric.R.layout;
import static com.geecko.QuickLyric.R.string;

public class MainActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener {

    private static final String LYRICS_FRAGMENT_TAG = "LyricsViewFragment";
    private static final String SETTINGS_FRAGMENT = "SettingsFragment";
    private static final String LOCAL_LYRICS_FRAGMENT_TAG = "LocalLyricsFragment";
    public static final String SEARCH_FRAGMENT_TAG = "SearchFragment";
    public static boolean waitingForListener = false;
    public View drawer;
    public View drawerView;
    public DrawerItemClickListener drawerListener;
    public boolean focusOnFragment = true;
    public ActionMode mActionMode;
    public ActionBarDrawerToggle mDrawerToggle;
    public int themeNum;
    private Fragment displayedFragment;
    private MusicBroadcastReceiver receiver;
    private boolean receiverRegistered = false;
    private boolean destroyed = false;
    private int selectedRow = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        IMMLeaks.fixFocusedViewLeak(getApplication());
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        int[] themes = new int[] { R.style.Theme_QuickLyric, R.style.Theme_QuickLyric_Red,
                R.style.Theme_QuickLyric_Purple, R.style.Theme_QuickLyric_Indigo, R.style.Theme_QuickLyric_Green,
                R.style.Theme_QuickLyric_Lime, R.style.Theme_QuickLyric_Brown, R.style.Theme_QuickLyric_Dark };
        themeNum = Integer.valueOf(sharedPref.getString("pref_theme", "0"));
        boolean nightMode = sharedPref.getBoolean("pref_night_mode", false);
        if (nightMode && NightTimeVerifier.check(this))
            setTheme(R.style.Theme_QuickLyric_Night);
        else
            setTheme(themes[themeNum]);
        super.onCreate(savedInstanceState);
        setStatusBarColor(null);
        setNavBarColor(null);
        final FragmentManager fragmentManager = getFragmentManager();
        setContentView(layout.nav_drawer_activity);
        setSupportActionBar((android.support.v7.widget.Toolbar) findViewById(id.toolbar));
        getSupportActionBar().setDisplayShowTitleEnabled(true);
        getSupportActionBar().setTitle(string.app_name);

        AppBarLayout appBarLayout = (AppBarLayout) findViewById(id.appbar);
        appBarLayout.addOnOffsetChangedListener(this);

        /** Drawer setup */
        final ListView drawerList = (ListView) findViewById(id.drawer_list);
        DrawerAdapter drawerAdapter = new DrawerAdapter(this, this.getResources().getStringArray(array.nav_items));
        drawerList.setAdapter(drawerAdapter);
        drawerView = this.findViewById(id.left_drawer);
        drawer = this.findViewById(id.drawer_layout);
        if (drawer instanceof DrawerLayout) { // if phone
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            mDrawerToggle = new ActionBarDrawerToggle(this, (DrawerLayout) drawer, string.drawer_open_desc,
                    string.drawer_closed_desc) {

                /**
                 * Called when a drawer has settled in a completely open state.
                 */
                public void onDrawerOpened(View drawerView) {
                    focusOnFragment = false;
                    if (mActionMode != null)
                        mActionMode.finish();
                    MainActivity.this.invalidateOptionsMenu(); // onPrepareOptionsMenu()
                }

                /**
                 * Called when a drawer has settled in a completely closed state.
                 */
                public void onDrawerClosed(View view) {
                    focusOnFragment = true;
                    if (selectedRow != -1)
                        selectItem(selectedRow);
                    MainActivity.this.selectedRow = -1;
                    MainActivity.this.invalidateOptionsMenu(); // onPrepareOptionsMenu()
                }
            };
            Resources.Theme theme = getTheme();
            TypedValue darkColorValue = new TypedValue();
            TypedValue primaryColorValue = new TypedValue();
            theme.resolveAttribute(R.attr.colorPrimaryDark, darkColorValue, true);
            theme.resolveAttribute(R.attr.colorPrimary, primaryColorValue, true);
            ((DrawerLayout) drawer).addDrawerListener(mDrawerToggle);
            ((DrawerLayout) drawer).setStatusBarBackground(null);

            if (themeNum > 0 && themeNum != 7) { // Is not Amber or Dark
                final ImageView drawerHeader = (ImageView) findViewById(id.drawer_header);
                drawerHeader.setColorFilter(darkColorValue.data, PorterDuff.Mode.OVERLAY);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription(null, null,
                        primaryColorValue.data);
                this.setTaskDescription(taskDescription);
            }
        }

        drawerListener = new DrawerItemClickListener();
        drawerList.setOnItemClickListener(drawerListener);

        Intent intent = getIntent();
        String extra = intent.getStringExtra(Intent.EXTRA_TEXT);
        Lyrics receivedLyrics = getBeamedLyrics(intent);
        if (receivedLyrics != null) {
            updateLyricsFragment(0, 0, false, receivedLyrics);
        } else {
            String s = intent.getAction();
            if ("com.geecko.QuickLyric.getLyrics".equals(s) && intent.getStringArrayExtra("TAGS") != null) {
                String[] metadata = intent.getStringArrayExtra("TAGS");
                String artist = metadata[0];
                String track = metadata[1];
                updateLyricsFragment(0, artist, track);
            } else if ("android.intent.action.SEND".equals(s)) {
                new IdDecoder(this, init(fragmentManager, true)).execute(getIdUrl(extra));
            } else
                init(fragmentManager, false);
        }
        boolean seenIntro = getSharedPreferences("intro_slides", Context.MODE_PRIVATE).getBoolean("seen", false);
        if (!seenIntro) {
            registerTempReceiver();
            setupDemoScreen();
        }

        SharedPreferences updatePrefs = getSharedPreferences("update_tracker", Context.MODE_PRIVATE);
        int versionCode = updatePrefs.getInt("VERSION_CODE",
                seenIntro ? BuildConfig.VERSION_CODE - 1 : BuildConfig.VERSION_CODE);
        updatePrefs.edit().putInt("VERSION_CODE", BuildConfig.VERSION_CODE).apply();
        if (versionCode < BuildConfig.VERSION_CODE)
            onAppUpdated(versionCode);
    }

    private LyricsViewFragment init(FragmentManager fragmentManager, boolean startEmpty) {
        LyricsViewFragment lyricsViewFragment = (LyricsViewFragment) fragmentManager
                .findFragmentByTag(LYRICS_FRAGMENT_TAG);
        if (lyricsViewFragment == null || lyricsViewFragment.isDetached())
            lyricsViewFragment = new LyricsViewFragment();
        lyricsViewFragment.startEmpty(startEmpty);
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.setCustomAnimations(R.animator.slide_in_end, R.animator.slide_out_start,
                R.animator.slide_in_start, R.animator.slide_out_end);
        if (!lyricsViewFragment.isAdded()) {
            fragmentTransaction.add(id.main_fragment_container, lyricsViewFragment, LYRICS_FRAGMENT_TAG);
        }

        Fragment[] activeFragments = getActiveFragments();
        displayedFragment = getDisplayedFragment(activeFragments);

        for (Fragment fragment : activeFragments)
            if (fragment != null) {
                if (fragment != displayedFragment && !fragment.isHidden()) {
                    fragmentTransaction.hide(fragment);
                    fragment.onHiddenChanged(true);
                } else if (fragment == displayedFragment)
                    fragmentTransaction.show(fragment);
            }
        fragmentTransaction.commit();
        return lyricsViewFragment;
    }

    public Fragment getDisplayedFragment(Fragment[] fragments) {
        for (Fragment fragment : fragments) {
            if (fragment == null)
                continue;
            if ((fragment instanceof LyricsViewFragment && ((LyricsViewFragment) fragment).isActiveFragment)
                    || (fragment instanceof LocalLyricsFragment
                            && ((LocalLyricsFragment) fragment).isActiveFragment))
                return fragment;
        }
        return fragments[0];
    }

    public Fragment[] getActiveFragments() {
        FragmentManager fragmentManager = this.getFragmentManager();
        Fragment[] fragments = new Fragment[4];
        fragments[0] = fragmentManager.findFragmentByTag(LYRICS_FRAGMENT_TAG);
        fragments[1] = fragmentManager.findFragmentByTag(SEARCH_FRAGMENT_TAG);
        fragments[2] = fragmentManager.findFragmentByTag(SETTINGS_FRAGMENT);
        fragments[3] = fragmentManager.findFragmentByTag(LOCAL_LYRICS_FRAGMENT_TAG);
        return fragments;
    }

    @SuppressWarnings("ConstantConditions")
    @NonNull
    public ActionBar getSupportActionBar() {
        return super.getSupportActionBar();
    }

    @Override
    protected void onResume() {
        super.onResume();
        App.activityResumed();
        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter != null) {
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                    new Intent(this, ((Object) this).getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
            IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
            try {
                ndef.addDataType("application/lyrics");
            } catch (IntentFilter.MalformedMimeTypeException e) {
                return;
            }
            IntentFilter[] intentFiltersArray = new IntentFilter[] { ndef, };
            try {
                nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, null);
            } catch (Exception ignored) {
            }
        }
        LyricsViewFragment lyricsViewFragment = (LyricsViewFragment) getFragmentManager()
                .findFragmentByTag(LYRICS_FRAGMENT_TAG);
        if (lyricsViewFragment != null) {
            if (getIntent() == null || getIntent().getAction() == null || getIntent().getAction().equals("")) {
                // fixme executes twice?
                if (!"Storage".equals(lyricsViewFragment.getSource()) && !lyricsViewFragment.searchResultLock)
                    lyricsViewFragment.fetchCurrentLyrics(false);
                lyricsViewFragment.checkPreferencesChanges();
            }
        }
        AppBarLayout appBarLayout = (AppBarLayout) findViewById(id.appbar);
        appBarLayout.removeOnOffsetChangedListener(this);
        appBarLayout.addOnOffsetChangedListener(this);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String action = intent.getAction();
        String extra = intent.getStringExtra(Intent.EXTRA_TEXT);
        if (action != null) {
            switch (action) {
            case NfcAdapter.ACTION_NDEF_DISCOVERED:
                Lyrics receivedLyrics = getBeamedLyrics(intent);
                if (receivedLyrics != null)
                    updateLyricsFragment(0, 0, false, receivedLyrics);
                break;
            case "android.intent.action.SEARCH":
                search(intent.getStringExtra(SearchManager.QUERY));
                break;
            case "android.intent.action.SEND":
                LyricsViewFragment lyricsViewFragment = (LyricsViewFragment) getFragmentManager()
                        .findFragmentByTag(LYRICS_FRAGMENT_TAG);
                new IdDecoder(this, lyricsViewFragment).execute(getIdUrl(extra));
                selectItem(0);
                break;
            case "android.intent.action.VIEW":
                if (intent.getDataString().contains("spotify"))
                    Spotify.onCallback(intent, this);
                break;
            case "com.geecko.QuickLyric.getLyrics":
                String[] metadata = intent.getStringArrayExtra("TAGS");
                if (metadata != null) {
                    String artist = metadata[0];
                    String track = metadata[1];
                    LyricsViewFragment lyricsFragment = (LyricsViewFragment) getFragmentManager()
                            .findFragmentByTag(LYRICS_FRAGMENT_TAG);
                    lyricsFragment.fetchLyrics(artist, track);
                    selectItem(0);
                }
                break;
            case "com.geecko.QuickLyric.updateDBList":
                updateDBList();
                break;
            }
        }
    }

    @TargetApi(14)
    private Lyrics getBeamedLyrics(Intent intent) {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        // only one message sent during the beam
        if (rawMsgs != null && rawMsgs.length > 0) {
            NdefMessage msg = (NdefMessage) rawMsgs[0];
            // record 0 contains the MIME type, record 1 is the AAR, if present
            NdefRecord[] records = msg.getRecords();
            if (records.length > 0) {
                try {
                    return Lyrics.fromBytes(records[0].getPayload());
                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public void search(String searchQuery) {
        LyricsSearchSuggestionsProvider.getInstance(getApplicationContext()).saveQuery(searchQuery);
        Intent searchIntent = new Intent(this, SearchActivity.class);
        searchIntent.putExtra("query", searchQuery);
        startActivityForResult(searchIntent, 55);
        overridePendingTransition(R.anim.slide_in_end, android.R.anim.fade_out);
    }

    private void updateDBList() {
        LocalLyricsFragment localLyricsFragment = (LocalLyricsFragment) getFragmentManager()
                .findFragmentByTag(LOCAL_LYRICS_FRAGMENT_TAG);
        if (localLyricsFragment != null && localLyricsFragment.isActiveFragment)
            new DBContentLister(localLyricsFragment).execute();
        else
            selectItem(1);
    }

    private String getIdUrl(String extra) {
        final Pattern urlPattern = Pattern.compile(
                "(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)" + "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*"
                        + "[\\p{Alnum}.,%_=?&#\\-+()\\[\\]\\*$~@!:/{};']*)",
                Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);

        if (!(extra == null || extra.isEmpty())) {
            Matcher matcher = urlPattern.matcher(extra);
            if (matcher.find())
                return extra.substring(matcher.start(), matcher.end());
        }
        return null;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        invalidateOptionsMenu();
        LyricsViewFragment lyricsViewFragment = (LyricsViewFragment) getFragmentManager()
                .findFragmentByTag(LYRICS_FRAGMENT_TAG);
        if (lyricsViewFragment == null)
            return;
        if (requestCode == 77) {
            lyricsViewFragment.checkPreferencesChanges();
        } else if (resultCode == RESULT_OK && requestCode == 55) {
            Lyrics results = (Lyrics) data.getSerializableExtra("lyrics");
            updateLyricsFragment(R.animator.slide_out_end, results.getArtist(), results.getTitle(),
                    results.getURL());
            lyricsViewFragment.searchResultLock = true;
        }
        lyricsViewFragment.updateSearchView(true, null, false);
    }

    @Override
    protected void onPause() {
        super.onPause();
        App.activityPaused();
        if (receiver != null && receiverRegistered) {
            unregisterReceiver(receiver);
            LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
            receiverRegistered = false;
        }
        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter != null)
            nfcAdapter.disableForegroundDispatch(this);
        AppBarLayout appBarLayout = (AppBarLayout) findViewById(id.appbar);
        appBarLayout.removeOnOffsetChangedListener(this);
    }

    @Override
    protected void onDestroy() {
        this.destroyed = true;
        if (DatabaseHelper.getInstance(getApplicationContext()) != null)
            DatabaseHelper.getInstance(getApplicationContext()).close();
        try {
            ((Class.forName("android.view.inputmethod.InputMethodManager")).getMethod("windowDismissed",
                    IBinder.class)).invoke(null, drawer.getWindowToken());
        } catch (Exception ignored) {
        }
        super.onDestroy();
    }

    public boolean hasBeenDestroyed() {
        return this.destroyed;
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        if (displayedFragment instanceof LyricsViewFragment) {
            DrawerAdapter drawerAdapter = (DrawerAdapter) ((ListView) findViewById(id.drawer_list)).getAdapter();
            if (drawerAdapter.getSelectedItem() != 0) {
                drawerAdapter.setSelectedItem(0);
                drawerAdapter.notifyDataSetChanged();
            }
        }
        if (!RefreshButtonBehavior.visible)
            findViewById(id.refresh_fab).setVisibility(View.GONE);
    }

    @Override
    public void onBackPressed() {
        MaterialSuggestionsSearchView suggestionsSearchView = (MaterialSuggestionsSearchView) findViewById(
                R.id.material_search_view);
        if (suggestionsSearchView.isSearchOpen())
            suggestionsSearchView.closeSearch();
        else if (drawer instanceof DrawerLayout && ((DrawerLayout) drawer).isDrawerOpen(drawerView))
            ((DrawerLayout) drawer).closeDrawer(drawerView);
        else {
            displayedFragment = getDisplayedFragment(getActiveFragments());
            if (displayedFragment != null && displayedFragment instanceof LocalLyricsFragment)
                selectItem(0);
            else
                finish();
        }
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        if (mDrawerToggle != null)
            mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mDrawerToggle != null)
            mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        LyricsViewFragment lyricsViewFragment = ((LyricsViewFragment) getFragmentManager()
                .findFragmentByTag(LYRICS_FRAGMENT_TAG));
        if (lyricsViewFragment != null)
            lyricsViewFragment.enablePullToRefresh(i == 0);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
        case LocalLyricsFragment.REQUEST_CODE:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                LocalLyricsFragment localLyricsFragment = (LocalLyricsFragment) getFragmentManager()
                        .findFragmentByTag(LOCAL_LYRICS_FRAGMENT_TAG);
                localLyricsFragment.showScanDialog();
            } else {
                Toast.makeText(this, string.scan_error_permission_denied, Toast.LENGTH_LONG).show();
            }
            break;
        case Id3Writer.REQUEST_CODE:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, string.id3_write_permission_error, Toast.LENGTH_LONG).show();
            } else {
                String message = getString(string.id3_write_error) + " " + getString(string.permission_denied);
                Toast.makeText(this, message, Toast.LENGTH_LONG).show();
            }
        }
    }

    public void setDrawerListener(boolean bool) {
        ((ListView) findViewById(id.drawer_list)).setOnItemClickListener(bool ? drawerListener : null);
    }

    private void registerTempReceiver() {
        receiver = new MusicBroadcastReceiver();
        MusicBroadcastReceiver.forceAutoUpdate(true);
        IntentFilter intentfilter = new IntentFilter();
        intentfilter.addAction("com.android.music.metachanged");
        intentfilter.addAction("com.htc.music.metachanged");
        intentfilter.addAction("com.miui.player.metachanged");
        intentfilter.addAction("com.real.IMP.metachanged");
        intentfilter.addAction("com.sonyericsson.music.metachanged");
        intentfilter.addAction("com.rdio.android.playstatechanged");
        intentfilter.addAction("com.samsung.sec.android.MusicPlayer.metachanged");
        intentfilter.addAction("com.sec.android.app.music.metachanged");
        intentfilter.addAction("com.nullsoft.winamp.metachanged");
        intentfilter.addAction("com.amazon.mp3.metachanged");
        intentfilter.addAction("com.rhapsody.metachanged");
        intentfilter.addAction("com.maxmpz.audioplayer.metachanged");
        intentfilter.addAction("com.real.IMP.metachanged");
        intentfilter.addAction("com.andrew.apollo.metachanged");
        intentfilter.addAction("fm.last.android.metachanged");
        intentfilter.addAction("com.adam.aslfms.notify.playstatechanged");
        intentfilter.addAction("net.jjc1138.android.scrobbler.action.MUSIC_STATUS");
        intentfilter.addAction("com.spotify.music.metadatachanged");
        registerReceiver(receiver, intentfilter);
        this.receiverRegistered = true;
    }

    private void setupDemoScreen() {
        ViewGroup rootView = (ViewGroup) findViewById(id.root_view);
        getLayoutInflater().inflate(layout.tutorial_view, rootView);
        final ViewPager pager = (ViewPager) findViewById(id.pager);
        CirclePageIndicator indicator = (CirclePageIndicator) findViewById(id.indicator);
        final IntroScreenSlidePagerAdapter pagerAdapter = new IntroScreenSlidePagerAdapter(getFragmentManager(),
                this);
        pager.setAdapter(pagerAdapter);
        pager.addOnPageChangeListener(pagerAdapter);
        indicator.setViewPager(pager);
        pager.setCurrentItem(pagerAdapter.rightToLeft ? pagerAdapter.getCount() - 1 : 0);
        indicator.setOnPageChangeListener(pagerAdapter);
        Button skipButton = (Button) rootView.findViewById(id.pager_button);
        ImageButton arrowButton = (ImageButton) rootView.findViewById(id.pager_arrow);
        skipButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
                    pagerAdapter.exitAction();
                else
                    pager.setCurrentItem(pagerAdapter.getCount() - 1);
            }
        });
        arrowButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pagerAdapter.nextAction();
            }
        });
        if (mDrawerToggle != null)
            ((DrawerLayout) drawer).setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        focusOnFragment = false;
        invalidateOptionsMenu();
    }

    @TargetApi(21)
    public static void setStatusBarColor(Window window, Resources.Theme theme, Integer color) {
        if (Build.VERSION.SDK_INT >= 21) {
            if (color == null) {
                TypedValue typedValue = new TypedValue();
                theme.resolveAttribute(android.R.attr.statusBarColor, typedValue, true);
                color = typedValue.data;
            }
            window.setStatusBarColor(color);
        }
    }

    @TargetApi(21)
    public void setStatusBarColor(Integer color) {
        MainActivity.setStatusBarColor(getWindow(), getTheme(), color);
    }

    @TargetApi(21)
    public static void setNavBarColor(Window window, Resources.Theme theme, Integer color) {
        if (Build.VERSION.SDK_INT >= 21) {
            if (color == null) {
                TypedValue typedValue = new TypedValue();
                theme.resolveAttribute(android.R.attr.navigationBarColor, typedValue, true);
                color = typedValue.data;
            }
            window.setNavigationBarColor(color);
        }
    }

    @TargetApi(21)
    public void setNavBarColor(Integer color) {
        MainActivity.setNavBarColor(getWindow(), getTheme(), color);
    }

    private void prepareAnimations(Fragment nextFragment) {
        if (nextFragment != null) {
            if (nextFragment instanceof LocalLyricsFragment)
                ((LocalLyricsFragment) nextFragment).showTransitionAnim = true;
            else if (nextFragment instanceof LyricsViewFragment)
                ((LyricsViewFragment) nextFragment).showTransitionAnim = true;
        }
    }

    public void updateArtwork(String url) {
        LyricsViewFragment lyricsViewFragment = (LyricsViewFragment) getFragmentManager()
                .findFragmentByTag(LYRICS_FRAGMENT_TAG);
        if (lyricsViewFragment != null)
            lyricsViewFragment.setCoverArt(url, null);
    }

    public void updateLyricsFragment(int outAnim, String... params) { // Should only be called from SearchFragment or IdDecoder
        String artist = params[0];
        String song = params[1];
        String url = null;
        if (params.length > 2)
            url = params[2];
        LyricsViewFragment lyricsViewFragment = (LyricsViewFragment) getFragmentManager()
                .findFragmentByTag(LYRICS_FRAGMENT_TAG);
        if (lyricsViewFragment != null)
            lyricsViewFragment.fetchLyrics(artist, song, url);
        else {
            Lyrics lyrics = new Lyrics(Lyrics.SEARCH_ITEM);
            lyrics.setArtist(artist);
            lyrics.setTitle(song);
            lyrics.setURL(url);
            Bundle lyricsBundle = new Bundle();
            try {
                if (artist != null && song != null)
                    lyricsBundle.putByteArray("lyrics", lyrics.toBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
            lyricsViewFragment = new LyricsViewFragment();
            lyricsViewFragment.setArguments(lyricsBundle);

            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
            fragmentTransaction.setCustomAnimations(R.animator.slide_in_start, outAnim, R.animator.slide_in_start,
                    outAnim);
            Fragment activeFragment = getDisplayedFragment(getActiveFragments());
            if (activeFragment != null) {
                prepareAnimations(activeFragment);
                fragmentTransaction.hide(activeFragment);
            }
            fragmentTransaction.add(id.main_fragment_container, lyricsViewFragment, LYRICS_FRAGMENT_TAG);
            lyricsViewFragment.isActiveFragment = true;
            fragmentTransaction.commit();
        }
        if (drawer instanceof DrawerLayout && !mDrawerToggle.isDrawerIndicatorEnabled()) {
            mDrawerToggle.setDrawerIndicatorEnabled(true);
            ((DrawerLayout) drawer).setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        }
    }

    public void updateLyricsFragment(int outAnim, int inAnim, boolean transition, Lyrics lyrics) {
        LyricsViewFragment lyricsViewFragment = (LyricsViewFragment) getFragmentManager()
                .findFragmentByTag(LYRICS_FRAGMENT_TAG);
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.setCustomAnimations(inAnim, outAnim, inAnim, outAnim);
        Fragment activeFragment = getDisplayedFragment(getActiveFragments());
        if (lyricsViewFragment != null && lyricsViewFragment.getView() != null) {
            SharedPreferences preferences = getSharedPreferences("current_music", Context.MODE_PRIVATE);
            String artist = preferences.getString("artist", null);
            String track = preferences.getString("track", null);
            if (lyrics.isLRC()
                    && !(lyrics.getOriginalArtist().equals(artist) && lyrics.getOriginalTrack().equals(track))) {
                LrcView parser = new LrcView(this, null);
                parser.setOriginalLyrics(lyrics);
                parser.setSourceLrc(lyrics.getText());
                lyrics = parser.getStaticLyrics();
            }
            lyricsViewFragment.update(lyrics, lyricsViewFragment.getView(), true);
            if (transition) {
                fragmentTransaction.hide(activeFragment).show(lyricsViewFragment);
                prepareAnimations(activeFragment);
                prepareAnimations(lyricsViewFragment);
            }
            showRefreshFab(true);
            lyricsViewFragment.expandToolbar();
        } else {
            Bundle lyricsBundle = new Bundle();
            try {
                lyricsBundle.putByteArray("lyrics", lyrics.toBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
            lyricsViewFragment = new LyricsViewFragment();
            lyricsViewFragment.setArguments(lyricsBundle);
            if (!(activeFragment instanceof LyricsViewFragment) && activeFragment != null)
                fragmentTransaction.hide(activeFragment).add(id.main_fragment_container, lyricsViewFragment,
                        LYRICS_FRAGMENT_TAG);
            else
                fragmentTransaction.replace(id.main_fragment_container, lyricsViewFragment, LYRICS_FRAGMENT_TAG);
        }
        fragmentTransaction.commitAllowingStateLoss();
    }

    private void expandToolbar(boolean expanded) {
        AppBarLayout appBarLayout = (AppBarLayout) findViewById(id.appbar);
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
        AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
        if (behavior != null) {
            behavior.onNestedFling((CoordinatorLayout) (findViewById(id.coordinator_layout)), appBarLayout,
                    appBarLayout, 0, expanded ? -4000 : 4000, !expanded);
        }
    }

    private void showRefreshFab(boolean show) {
        RefreshIcon refreshFAB = (RefreshIcon) findViewById(id.refresh_fab);
        if (show)
            refreshFAB.show();
        else
            refreshFAB.hide();
    }

    private void onAppUpdated(int versionCode) {
        String changelog = ChangelogStringBuilder.getChangelog(getResources(), versionCode);
        if (changelog == null || changelog.isEmpty())
            return;
        CharSequence spannedChangelog = Html.fromHtml(changelog);
        AlertDialog dialog = new AlertDialog.Builder(this).setTitle(string.changelog).setCancelable(true)
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).setNeutralButton("Translate the app", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                })
                //                .setNeutralButton(string.rate_us, new DialogInterface.OnClickListener() {
                //                    @Override
                //                    public void onClick(DialogInterface dialog, int which) {
                //                        dialog.dismiss(); TODO: Add play store page here
                //                    }
                //                }) TODO: only show this button on PLAY variant
                .setMessage(spannedChangelog).create();
        dialog.show();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (mDrawerToggle != null)
            return (mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item));
        else
            return super.onOptionsItemSelected(item);
    }

    // Swaps fragments from the drawer
    private void selectItem(int position) {
        FragmentManager fragmentManager = getFragmentManager();
        Fragment newFragment;
        String tag;
        switch (position) {
        default:
            // Lyrics
            tag = LYRICS_FRAGMENT_TAG;
            newFragment = fragmentManager.findFragmentByTag(tag);
            if (newFragment == null || !(newFragment instanceof LyricsViewFragment))
                newFragment = new LyricsViewFragment();
            ((LyricsViewFragment) newFragment).showTransitionAnim = true;
            break;
        case 1:
            // Saved Lyrics
            tag = LOCAL_LYRICS_FRAGMENT_TAG;
            newFragment = fragmentManager.findFragmentByTag(tag);
            if (newFragment == null || !(newFragment instanceof LocalLyricsFragment))
                newFragment = new LocalLyricsFragment();
            ((LocalLyricsFragment) newFragment).showTransitionAnim = true;
            break;
        case 2:
            // Separator
            return;
        case 3:
            // Settings
            if (drawer instanceof DrawerLayout)
                ((DrawerLayout) drawer).closeDrawer(drawerView);
            drawer.postDelayed(new Runnable() {
                @Override
                public void run() {
                    Intent settingsIntent = new Intent(MainActivity.this, SettingsActivity.class);
                    startActivityForResult(settingsIntent, 77);
                }
            }, 250);
            return;
        case 4:
            // Feedback
            return;
        case 5:
            // About Dialog
            if (drawer instanceof DrawerLayout)
                ((DrawerLayout) drawer).closeDrawer(drawerView);
            drawer.postDelayed(new Runnable() {
                @Override
                public void run() {
                    Intent aboutIntent = new Intent(MainActivity.this, AboutActivity.class);
                    startActivityForResult(aboutIntent, 77);
                }
            }, 250);
            return;
        }

        final Fragment activeFragment = getDisplayedFragment(getActiveFragments());
        prepareAnimations(activeFragment);

        // Insert the fragment by replacing any existing fragment
        if (newFragment != activeFragment) {
            if (mActionMode != null)
                mActionMode.finish();
            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
            fragmentTransaction.setCustomAnimations(R.animator.slide_in_start, R.animator.slide_out_start,
                    R.animator.slide_in_start, R.animator.slide_out_start);
            fragmentTransaction.hide(activeFragment);
            if (newFragment.isAdded())
                fragmentTransaction.show(newFragment);
            else
                fragmentTransaction.add(id.main_fragment_container, newFragment, tag);
            ((CollapsingToolbarLayout) findViewById(R.id.toolbar_layout)).setCollapsedTitleTextColor(Color.WHITE);
            fragmentTransaction.commit();

            if (activeFragment instanceof LyricsViewFragment || newFragment instanceof LyricsViewFragment) {
                final Fragment newFragmentCopy = newFragment;
                activeFragment.getView().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (activeFragment instanceof LyricsViewFragment) {
                            expandToolbar(false);
                            showRefreshFab(false);
                        } else if (newFragmentCopy instanceof LyricsViewFragment) {
                            expandToolbar(true);
                            showRefreshFab(true);
                        }
                    }
                }, getResources().getInteger(android.R.integer.config_longAnimTime));
            }
        }
        if (drawer instanceof DrawerLayout && (newFragment == activeFragment))
            ((DrawerLayout) drawer).closeDrawer(drawerView);
    }

    public void whyPopUp(View view) {
        LyricsViewFragment lyricsViewFragment = ((LyricsViewFragment) getFragmentManager()
                .findFragmentByTag(LYRICS_FRAGMENT_TAG));
        if (lyricsViewFragment != null && !lyricsViewFragment.isDetached())
            lyricsViewFragment.showWhyPopup();
    }

    @SuppressWarnings("unused")
    public void id3PopUp(View view) {
        Toast.makeText(this, string.ignore_id3_toast, Toast.LENGTH_LONG).show();
    }

    @SuppressLint("InlinedApi")
    public void resync(MenuItem item) {
        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        am.requestAudioFocus(null,
                // Use the music stream.
                AudioManager.STREAM_SYSTEM,
                // Request permanent focus.
                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
        am.abandonAudioFocus(null);
    }

    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            MainActivity.this.selectedRow = position;
            ((DrawerLayout) drawer).closeDrawer(drawerView);
        }
    }
}