com.oceansky.yellow.app.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.oceansky.yellow.app.MainActivity.java

Source

/*
 * Copyright (C) 2015 Fastboot Mobile, LLC.
 *
 * This program 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.
 *
 * This program 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 this program;
 * if not, see <http://www.gnu.org/licenses>.
 */

package com.oceansky.yellow.app;

import android.*;
import android.Manifest;
import android.app.AlertDialog;
import android.app.SearchManager;
import android.app.TimePickerDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.drawable.ColorDrawable;
import android.net.http.HttpResponseCache;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.MediaRouteActionProvider;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TimePicker;
import android.widget.Toast;

import com.oceansky.yellow.app.fragments.AutomixFragment;
import com.oceansky.yellow.app.fragments.HistoryFragment;
import com.oceansky.yellow.app.fragments.ListenNowFragment;
import com.oceansky.yellow.app.fragments.LyricsFragment;
import com.oceansky.yellow.app.fragments.MySongsFragment;
import com.oceansky.yellow.app.fragments.NavigationDrawerFragment;
import com.oceansky.yellow.app.fragments.PlaybackQueueFragment;
import com.oceansky.yellow.app.fragments.PlaylistListFragment;
import com.oceansky.yellow.app.fragments.RecognitionFragment;
import com.oceansky.yellow.app.ui.PlayingBarView;
import com.oceansky.yellow.art.ImageCache;
import com.oceansky.yellow.cast.CastModule;
import com.oceansky.yellow.framework.PlaybackProxy;
import com.oceansky.yellow.framework.PluginsLookup;
import com.oceansky.yellow.providers.IMusicProvider;
import com.oceansky.yellow.providers.ProviderAggregator;
import com.oceansky.yellow.providers.ProviderConnection;
import com.oceansky.yellow.utils.Utils;
import com.williammora.snackbar.Snackbar;

import java.util.List;

public class MainActivity extends AppActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks, TimePickerDialog.OnTimeSetListener {

    private static final String TAG = "MainActivity";

    public static final int SECTION_LISTEN_NOW = 1;
    public static final int SECTION_MY_SONGS = 2;
    public static final int SECTION_PLAYLISTS = 3;
    public static final int SECTION_AUTOMIX = 4;
    public static final int SECTION_RECOGNITION = 5;
    public static final int SECTION_HISTORY = 6;
    public static final int SECTION_LYRICS = 7;
    public static final int SECTION_NOW_PLAYING = 8;

    public static final int SECTION_DRIVE_MODE = 9;
    public static final int SECTION_SETTINGS = 10;

    private static final int PERM_REQUEST_APP_CORE_PERMISSIONS = 129;

    /**
     * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
     */
    private NavigationDrawerFragment mNavigationDrawerFragment;

    /**
     * Used to store the last screen title. For use in {@link #restoreActionBar()}.
     */
    private CharSequence mTitle;

    private PlayingBarView mPlayingBarLayout;

    private CastModule mCastModule;

    private Handler mHandler;

    private int mCurrentFragmentIndex = -1;

    private MenuItem mOfflineMenuItem;

    private ProviderConnection mConfiguringProvider;

    private int mOrientation;

    private Toolbar mToolbar;

    private SearchView mSearchView;

    public MainActivity() {
        mHandler = new Handler();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (!WelcomeActivity.hasDoneWelcomeWizard(this)) {
            Intent intent = new Intent(this, WelcomeActivity.class);
            startActivity(intent);
            finish();
        } else {
            // Load UI
            setContentView(R.layout.activity_main);

            // Ensure we have READ_EXTERNAL_STORAGE for Music database in LocalProvider
            // Ensure we have WRITE_EXTERNAL_STORAGE for Album arts storage
            if (ContextCompat.checkSelfPermission(this,
                    android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
                        PERM_REQUEST_APP_CORE_PERMISSIONS);
            }

            mToolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(mToolbar);

            mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.navigation_drawer);
            if (mTitle == null) {
                onSectionAttached(mCurrentFragmentIndex);
            }

            // Set up the drawer.
            mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
                    (DrawerLayout) findViewById(R.id.drawer_layout));

            // Setup the playing bar click listener
            mPlayingBarLayout = (PlayingBarView) findViewById(R.id.playingBarLayout);
            mPlayingBarLayout.setWrapped(true, false);

            // Setup Cast button
            mCastModule = new CastModule(getApplicationContext());

            // Look for un-configured plugins in a second
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    lookForUnconfiguredProviders();
                }
            }, 1000);
        }

        getWindow().getDecorView()
                .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
        case PERM_REQUEST_APP_CORE_PERMISSIONS: {
            // If request is cancelled, the result arrays are empty.
            if (!(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                // permission denied, boo!
                Toast.makeText(this, R.string.toast_storage_permission_warning, Toast.LENGTH_LONG).show();
            }
            return;
        }
        }
    }

    public Toolbar getToolbar() {
        return mToolbar;
    }

    public CharSequence getFragmentTitle() {
        return mTitle;
    }

    private void lookForUnconfiguredProviders() {
        List<ProviderConnection> providers = PluginsLookup.getDefault().getAvailableProviders();
        for (final ProviderConnection conn : providers) {
            try {
                if (conn.getBinder() != null && !conn.getBinder().isSetup()
                        && conn.getConfigurationActivity() != null) {
                    notifyUnconfiguredProvider(conn);
                    break;
                }
            } catch (Exception e) {
                Log.e(TAG, "Cannot get " + conn + " status", e);
            }
        }
    }

    private void notifyUnconfiguredProvider(final ProviderConnection conn) {
        showSnackBar(getString(R.string.plugin_not_configured_snackbar, conn.getProviderName()),
                getString(R.string.configure), new Snackbar.ActionClickListener() {
                    @Override
                    public void onActionClicked() {
                        Intent i = new Intent();
                        i.setClassName(conn.getPackage(), conn.getConfigurationActivity());
                        try {
                            mConfiguringProvider = conn;
                            startActivity(i);
                        } catch (SecurityException e) {
                            Log.e(TAG, "Cannot start: Is your activity not exported?");
                            Toast.makeText(MainActivity.this,
                                    "Cannot start: Make sure you set 'exported=true' flag on your settings activity.",
                                    Toast.LENGTH_LONG).show();
                        } catch (ActivityNotFoundException e) {
                            Log.e(TAG, "Cannot start: Unknown activity");
                            Toast.makeText(MainActivity.this,
                                    "Cannot start: The settings activity hasn't been found in the package.",
                                    Toast.LENGTH_LONG).show();
                        }
                    }
                });
    }

    public void showSnackBar(String message, String button, Snackbar.ActionClickListener listener) {
        Snackbar.with(getApplicationContext()).type(Snackbar.SnackbarType.MULTI_LINE).text(message)
                .actionLabel(button).actionListener(listener).duration(Snackbar.SnackbarDuration.LENGTH_VERY_LONG)
                .show(this);
    }

    public boolean isPlayBarVisible() {
        return mPlayingBarLayout.isVisible();
    }

    @Override
    public void onBackPressed() {
        if (!mSearchView.isIconified()) {
            mSearchView.setIconified(true);
            //mNavigationDrawerFragment.setDrawerIndicatorEnabled(true);
            getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        } else if (!mPlayingBarLayout.isWrapped()) {
            mPlayingBarLayout.setWrapped(true);
        } else if (mNavigationDrawerFragment.isDrawerOpen()) {
            mNavigationDrawerFragment.closeDrawer();
        } else {
            super.onBackPressed();
            if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
                mNavigationDrawerFragment.selectItem(SECTION_LISTEN_NOW - 1);
                onSectionAttached(SECTION_LISTEN_NOW);
            }
            restoreActionBar();
        }
    }

    public void openSection(int section) {
        mNavigationDrawerFragment.selectItem(section - 1);
        onSectionAttached(section);
        restoreActionBar();
    }

    @Override
    protected void onResume() {
        super.onResume();
        PluginsLookup.getDefault().requestUpdatePlugins();

        mPlayingBarLayout.onResume();

        if (mConfiguringProvider != null) {
            IMusicProvider provider = mConfiguringProvider.getBinder();
            if (provider != null) {
                try {
                    if (provider.isSetup()) {
                        provider.login();
                    }
                } catch (RemoteException e) {
                    Log.e(TAG, "Remote exception while trying to login configured provider", e);
                }
            } else {
                Log.w(TAG, "Configured provider is null!");
            }
        }

        onSectionAttached(mCurrentFragmentIndex + 1);
        restoreActionBar();
    }

    @Override
    protected void onPause() {
        mPlayingBarLayout.onPause();
        super.onPause();
    }

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

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

    @Override
    protected void onDestroy() {
        HttpResponseCache cache = HttpResponseCache.getInstalled();
        if (cache != null) {
            cache.flush();
        }

        // Release services connections if playback isn't happening
        PluginsLookup.getDefault().releasePlaybackServiceIfPossible();
        ImageCache.getDefault().evictAll();
        System.gc();

        super.onDestroy();
    }

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

        if (mOrientation != newConfig.orientation) {
            mOrientation = newConfig.orientation;
        }

        onSectionAttached(mCurrentFragmentIndex + 1);
        restoreActionBar();
    }

    @Override
    public boolean onNavigationDrawerItemSelected(int position) {
        // update the main content by replacing fragments
        boolean result = true;
        if (mCurrentFragmentIndex == position) {
            return false;
        }

        try {
            if (position + 1 < SECTION_DRIVE_MODE) {
                mCurrentFragmentIndex = position;
            }

            final String fragmentTag = "" + position + "_" + mOrientation;

            if (mPlayingBarLayout != null) {
                mPlayingBarLayout.animate().alpha(1).setDuration(400).start();
            }

            Fragment newFrag = null;
            boolean needsBackground = true;
            switch (position + 1) {
            case SECTION_LISTEN_NOW:
                newFrag = ListenNowFragment.newInstance();
                break;
            case SECTION_PLAYLISTS:
                newFrag = PlaylistListFragment.newInstance(true);
                break;
            case SECTION_MY_SONGS:
                newFrag = MySongsFragment.newInstance();
                needsBackground = false;
                break;
            case SECTION_AUTOMIX:
                newFrag = AutomixFragment.newInstance();
                break;
            case SECTION_RECOGNITION:
                newFrag = RecognitionFragment.newInstance();
                break;
            case SECTION_HISTORY:
                newFrag = HistoryFragment.newInstance();
                break;
            case SECTION_LYRICS:
                newFrag = LyricsFragment.newInstance();
                break;
            case SECTION_NOW_PLAYING:
                newFrag = PlaybackQueueFragment.newInstance();
                mPlayingBarLayout.animate().alpha(0).setDuration(400).start();
                break;
            case SECTION_DRIVE_MODE + 1: // offset the divider
                startActivity(new Intent(this, DriveModeActivity.class));
                break;
            case SECTION_SETTINGS + 1: // offset the divider
                startActivity(new Intent(this, SettingsActivity.class));
                break;
            }

            if (needsBackground) {
                getWindow().setBackgroundDrawable(
                        new ColorDrawable(getResources().getColor(R.color.default_fragment_background)));
            } else {
                getWindow().setBackgroundDrawable(null);
            }

            if (newFrag != null) {
                showFragment(newFrag, position + 1 != SECTION_LISTEN_NOW, fragmentTag);
                result = true;
            } else {
                result = false;
            }
        } catch (IllegalStateException e) {
            // The app is pausing
        }

        return result;
    }

    public void showFragment(Fragment f, boolean addToStack, String tag) {
        // update the main content by replacing fragments
        FragmentManager fragmentManager = getSupportFragmentManager();
        if (fragmentManager.getBackStackEntryCount() > 0) {
            fragmentManager.popBackStack();
        }

        FragmentTransaction ft = fragmentManager.beginTransaction();
        if (addToStack) {
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
            ft.addToBackStack(f.toString());
        } else {
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        }
        ft.replace(R.id.container, f, tag);
        ft.commit();
    }

    public void onSectionAttached(final int number) {
        switch (number) {
        case SECTION_MY_SONGS:
            mTitle = getString(R.string.title_section_my_songs);
            break;
        case SECTION_PLAYLISTS:
            mTitle = getString(R.string.title_section_playlists);
            break;
        case SECTION_AUTOMIX:
            mTitle = getString(R.string.title_section_automix);
            break;
        case SECTION_RECOGNITION:
            mTitle = getString(R.string.title_section_recognition);
            break;
        case SECTION_HISTORY:
            mTitle = getString(R.string.section_history);
            break;
        case SECTION_LYRICS:
            mTitle = getString(R.string.section_lyrics);
            break;
        case SECTION_NOW_PLAYING:
            mTitle = getString(R.string.title_activity_playback_queue);
            break;

        case SECTION_LISTEN_NOW:
        default:
            mTitle = getString(R.string.title_section_listen_now);
            break;
        }

        if (mToolbar != null) {
            if (number != SECTION_LISTEN_NOW) {
                mToolbar.setBackgroundColor(getResources().getColor(R.color.primary));
            }
        }
    }

    public void restoreActionBar() {
        if (mToolbar != null && mCurrentFragmentIndex + 1 != SECTION_LISTEN_NOW) {
            mToolbar.setTitle(mTitle);
        }
    }

    public void openSearchView() {
        mSearchView.callOnClick();
    }

    public void toggleOfflineMode() {
        mOfflineMenuItem.setChecked(!mOfflineMenuItem.isChecked());
        ProviderAggregator.getDefault().notifyOfflineMode(mOfflineMenuItem.isChecked());
    }

    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        if (!mNavigationDrawerFragment.isDrawerOpen()) {
            if ((mCurrentFragmentIndex + 1) != SECTION_AUTOMIX) {
                // Only show items in the action bar relevant to this screen
                // if the drawer is not showing. Otherwise, let the drawer
                // decide what to show in the action bar.
                getMenuInflater().inflate(R.menu.main, menu);
                SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);

                mSearchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
                mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
                mSearchView.setIconifiedByDefault(true);
                mSearchView.setQueryRefinementEnabled(true);
                mSearchView.setSubmitButtonEnabled(true);

                if (mCurrentFragmentIndex + 1 == SECTION_LISTEN_NOW) {
                    menu.removeItem(R.id.action_search);
                }

                mSearchView.setOnSearchClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        menu.findItem(R.id.action_cast).setVisible(false);
                        mNavigationDrawerFragment.setDrawerIndicatorEnabled(false);
                        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                        mSearchView.requestFocus();
                        mToolbar.setBackgroundColor(getResources().getColor(R.color.primary));
                    }
                });
                mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
                    @Override
                    public boolean onClose() {
                        if (Utils.hasJellyBeanMR1()) {
                            MenuItem item = menu.findItem(R.id.action_cast);
                            if (item != null) {
                                item.setVisible(true);
                            }
                        }

                        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                        mNavigationDrawerFragment.setDrawerIndicatorEnabled(true);
                        return false;
                    }
                });

                // Setup cast button on 4.2+
                MenuItem castMenu = menu.findItem(R.id.action_cast);
                if (Utils.hasJellyBeanMR1()) {
                    MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat
                            .getActionProvider(castMenu);
                    mediaRouteActionProvider.setRouteSelector(mCastModule.getSelector());
                    castMenu.setVisible(true);
                } else {
                    Log.w(TAG, "Api too low to show cast action");
                    castMenu.setVisible(false);
                }

                // Offline mode
                mOfflineMenuItem = menu.findItem(R.id.action_offline_mode);
                ProviderAggregator aggregator = ProviderAggregator.getDefault();
                if (aggregator.hasNetworkConnectivity()) {
                    mOfflineMenuItem.setChecked(aggregator.isOfflineMode());
                } else {
                    mOfflineMenuItem.setEnabled(false);
                }
            }

            restoreActionBar();
            return true;
        }
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            break;
        case R.id.action_sleep_timer:
            showSleepTimerDialog();
            break;

        case R.id.action_offline_mode:
            toggleOfflineMode();
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    private void showSleepTimerDialog() {
        final long timerTimeout = PlaybackProxy.getSleepTimerEndTime();

        if (timerTimeout > 0) {
            long seconds = timerTimeout / 1000L;
            long hours = (long) Math.floor(((double) seconds) / 3600.0);
            long minutes = seconds / 60 - hours * 60;

            AlertDialog.Builder builder = new AlertDialog.Builder(this)
                    .setMessage(getString(R.string.sleep_timer_dialog_message, hours, minutes))
                    .setPositiveButton(R.string.dialog_buttton_continue, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    }).setNegativeButton(R.string.stop, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            PlaybackProxy.setSleepTimer(-1);
                            Toast.makeText(MainActivity.this, R.string.sleep_timer_disabled_toast,
                                    Toast.LENGTH_SHORT).show();
                            dialog.dismiss();
                        }
                    }).setNeutralButton(R.string.change, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();

                            long seconds = timerTimeout / 1000L;
                            long hours = (long) Math.floor(((double) seconds) / 3600.0);
                            long minutes = seconds / 60 - hours * 60;
                            showSleepTimerPicker((int) hours, (int) minutes);
                        }
                    });
            builder.show();
        } else {
            showSleepTimerPicker();
        }
    }

    private void showSleepTimerPicker() {
        TimePickerDialog dlg;
        if (Utils.hasLollipop()) {
            dlg = new TimePickerDialog(this, R.style.TimePickerAppDialog, this, 0, 0, true);
        } else {
            dlg = new TimePickerDialog(this, this, 0, 0, true);
        }
        dlg.show();
    }

    private void showSleepTimerPicker(int hour, int minute) {
        TimePickerDialog dlg;
        if (Utils.hasLollipop()) {
            dlg = new TimePickerDialog(this, R.style.TimePickerAppDialog, this, hour, minute, true);
        } else {
            dlg = new TimePickerDialog(this, this, hour, minute, true);
        }
        dlg.show();
    }

    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        long delay = (hourOfDay * 3600L + minute * 60L) * 1000L;
        PlaybackProxy.setSleepTimer(SystemClock.uptimeMillis() + delay);
        Toast.makeText(this, getString(R.string.sleep_timer_confirm_toast, hourOfDay, minute), Toast.LENGTH_LONG)
                .show();
    }
}