de.gruenewald.udacity.spotifystreamer.controller.AppController.java Source code

Java tutorial

Introduction

Here is the source code for de.gruenewald.udacity.spotifystreamer.controller.AppController.java

Source

/**
 * ****************************************************************************
 * Copyright (c) 2015 by Jan Grnewald.
 * jan.gruenewald84@googlemail.com
 * <p>
 * This file is part of 'Spotify Streamer'. 'Spotify Streamer' was developed as
 * part of the Android Developer Nanodegree by Udacity.
 * <p>
 * 'Spotify Streamer' 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.
 * <p>
 * 'Spotify Streamer' 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.
 * <p>
 * You should have received a copy of the GNU General Public License
 * along with 'Spotify Streamer'.  If not, see <http://www.gnu.org/licenses/>.
 * ****************************************************************************
 */

package de.gruenewald.udacity.spotifystreamer.controller;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import de.gruenewald.udacity.spotifystreamer.ArtistFragment;
import de.gruenewald.udacity.spotifystreamer.MainActivity;
import de.gruenewald.udacity.spotifystreamer.PlaybackFragment;
import de.gruenewald.udacity.spotifystreamer.R;
import de.gruenewald.udacity.spotifystreamer.TrackActivity;
import de.gruenewald.udacity.spotifystreamer.TrackFragment;
import de.gruenewald.udacity.spotifystreamer.exception.MissingDependencyException;
import de.gruenewald.udacity.spotifystreamer.exception.ParameterException;
import de.gruenewald.udacity.spotifystreamer.model.ArtistListEntry;
import de.gruenewald.udacity.spotifystreamer.model.PlaybackEntry;
import de.gruenewald.udacity.spotifystreamer.model.TrackListEntry;
import kaaes.spotify.webapi.android.SpotifyApi;
import kaaes.spotify.webapi.android.models.Track;
import kaaes.spotify.webapi.android.models.Tracks;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;

/**
 * Created by Jan on 27.06.2015.
 */
public class AppController {
    private static final String LOG_TAG = AppController.class.getSimpleName();
    private static final Handler MAIN_THREAD = new Handler(Looper.getMainLooper());

    public static final SpotifyApi SPOTIFY_API = new SpotifyApi();
    public static final String TRACK_PLAYBACK_TAG = "tag_fragment_playback";

    private static AppController instance = new AppController();

    private MainActivity mMainActivity;
    private TrackActivity mTrackActivity;

    private ArtistFragment mArtistFragment;
    private TrackFragment mTrackFragment;
    private PlaybackFragment mPlaybackFragment;

    private int mArtistListPosition;

    private AppController() {
        Log.v(LOG_TAG, "Creating new instance of AppController.");

        unregisterMainActivity();
        unregisterTrackActivity();

        unregisterArtistFragment();
        unregisterTrackFragment();
        unregisterPlaybackFragment();
    }

    public static AppController getInstance() {
        if (instance == null) {
            instance = new AppController();
        }

        return instance;
    }

    public void handleOnArtistSelected(final int pArtistPosition, final boolean pIsTabletMode)
            throws MissingDependencyException, ParameterException {
        registerArtistListPosition(pArtistPosition);

        if (mArtistListPosition <= -1) {
            throw new ParameterException("Can't execute 'handleOnArtistSelected'. Invalid artist's position.");
        }

        if (mMainActivity == null) {
            throw new MissingDependencyException(
                    "Can't execute 'handleOnArtistSelected'. Missing dependency: 'MainActivity'.");
        }

        if (pIsTabletMode && mTrackFragment == null) {
            throw new MissingDependencyException(
                    "Can't execute 'handleOnArtistSelected'. Missing dependency: 'TrackFragment'.");
        }

        if (mArtistFragment == null) {
            throw new MissingDependencyException(
                    "Can't execute: 'handleOnArtistSelected'. Missing dependency: 'ArtistFragment'.");
        }

        final ArtistListEntry myArtistEntry = mArtistFragment.getArtistListEntries().get(mArtistListPosition);

        //setup the request object for the top-track query
        Map<String, Object> myParameterMap = new HashMap<String, Object>();
        // TODO: Read the country from the settings
        myParameterMap.put("country", "US");

        SPOTIFY_API.getService().getArtistTopTrack(myArtistEntry.getArtistId(), myParameterMap,
                new Callback<Tracks>() {
                    @Override
                    public void success(Tracks t, Response response) {
                        if (t != null && t.tracks != null && t.tracks.size() > 0) {
                            final ArrayList<TrackListEntry> myTrackListEntries = new ArrayList<TrackListEntry>();
                            for (Track myTrack : t.tracks) {
                                TrackListEntry myCurrentEntry = new TrackListEntry(myTrack.id);
                                myCurrentEntry.setTrackName(myTrack.name);
                                if (myTrack.album != null) {
                                    myCurrentEntry.setAlbumName(myTrack.album.name);
                                    if (myTrack.album.images != null && myTrack.album.images.size() > 0) {
                                        myCurrentEntry.setAlbumCover(
                                                myTrack.album.images.get(myTrack.album.images.size() - 1).url);
                                        myCurrentEntry.setAlbumCoverLarge(myTrack.album.images.get(0).url);
                                    }

                                    myCurrentEntry.setPreviewUrl(myTrack.preview_url);
                                }
                                myTrackListEntries.add(myCurrentEntry);
                            }

                            MAIN_THREAD.post(new Runnable() {
                                @Override
                                public void run() {
                                    //Check if mTrackFragment is set. If not we're on a smartphone
                                    //and start a new TrackActivity as an intent. Else we re-use
                                    //the fragment's instance and update the view.
                                    if (mTrackFragment == null) {
                                        Intent trackIntent = new Intent(mMainActivity, TrackActivity.class);
                                        trackIntent.putExtra(TrackActivity.EXTRA_ARTISTENTRY, myArtistEntry);
                                        trackIntent.putParcelableArrayListExtra(TrackActivity.EXTRA_TRACKLIST,
                                                myTrackListEntries);
                                        mMainActivity.startActivity(trackIntent);
                                    } else {
                                        mTrackFragment.setTitle(myArtistEntry.getArtistName());
                                        mTrackFragment.setNofResults(myTrackListEntries.size());
                                        mTrackFragment.populateListView(myTrackListEntries);
                                    }
                                }
                            });
                        } else {
                            MAIN_THREAD.post(new Runnable() {
                                @Override
                                public void run() {
                                    Toast.makeText(mMainActivity, R.string.track_search_error_noresults,
                                            Toast.LENGTH_SHORT).show();
                                }
                            });
                        }
                    }

                    @Override
                    public void failure(RetrofitError error) {
                        MAIN_THREAD.post(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(mMainActivity, R.string.track_search_error_default,
                                        Toast.LENGTH_SHORT).show();
                            }
                        });
                    }
                });
    }

    /**
     * This function will be called when a track from the track list is separated.
     * It will then launch a {@link PlaybackFragment} either as fragment or as dialog
     * depending on the device specification (tablet / phone).
     *
     * @param pTrackPosition The position of the Item which was selected.
     * @param pIsTabletMode  A boolean indicating whether the device is a tablet or not.
     * @throws MissingDependencyException Will be thrown if a required dependency is missing.
     * @throws ParameterException         Will be thrown if a provided parameter is invalid.
     */
    public void handleOnTrackSelected(final int pTrackPosition, final boolean pIsTabletMode)
            throws MissingDependencyException, ParameterException {
        if (pTrackPosition <= -1) {
            throw new ParameterException("Can't execute 'handleOnTrackSelected'. Invalid track's position.");
        }

        if (mArtistListPosition <= -1) {
            throw new MissingDependencyException(
                    "Can't execute 'handleOnTrackSelected'. Missing dependency: 'ArtistListPosition'.");
        }

        //we'll use this dependency to fetch the currently displayed tracklist which will then be
        //passed to the PlaybackFragment
        if (mTrackFragment == null) {
            throw new MissingDependencyException(
                    "Can't execute: 'handleOnTrackSelected'. Missing dependency: 'TrackFragment'.");
        }

        //we'll use this dependency to fetch the currently selected artist (which links to the
        //tracklist) and which will be passed to the PlaybackFragment
        if (mArtistFragment == null) {
            throw new MissingDependencyException(
                    "Can't execute: 'handleOnTrackSelected'. Missing dependency: 'ArtistFragment'.");
        }

        //if we are in table-mode we need the MainActivity to register the PlaybackFragment on.
        if (pIsTabletMode && mMainActivity == null) {
            throw new MissingDependencyException(
                    "Can't execute: 'handleOnTrackSelected'. Missing dependency: 'MainActivity'.");
        }

        //if we are in phone-mode we need the TrackActivity to register the PlaybackFragment on.
        if (!pIsTabletMode && mTrackActivity == null) {
            throw new MissingDependencyException(
                    "Can't execute 'handleOnTrackSelected.'. Missing dependency: 'TrackActivity'.");
        }

        ArrayList<PlaybackEntry> myPlaybackEntries = new ArrayList<PlaybackEntry>();

        //fetch the playback-entries from the currently displayed track-list
        for (TrackListEntry myEntry : mTrackFragment.getTrackListEntries()) {
            PlaybackEntry myNewPlaybackEntry = new PlaybackEntry();
            myNewPlaybackEntry.setArtistListEntry(mArtistFragment.getArtistListEntries().get(mArtistListPosition));
            myNewPlaybackEntry.setTrackListEntry(myEntry);
            myPlaybackEntries.add(myNewPlaybackEntry);
        }

        //prepare the data bundle for the playback fragment
        Bundle myDataBundle = new Bundle();
        myDataBundle.putInt(PlaybackFragment.ARG_PLAYBACK_TRACKINDEX, pTrackPosition);
        myDataBundle.putParcelableArrayList(PlaybackFragment.ARG_PLAYBACK_DATALIST, myPlaybackEntries);

        //register the PlaybackFragment
        registerPlaybackFragment(PlaybackFragment.newInstance(myDataBundle));

        //launch the PlaybackFragment depending on whether we are running on tablet or phone
        //remove any existing PlaybackFragment's which might have been registered previously
        //(that should not happen)
        if (!pIsTabletMode) {
            FragmentManager myFM = mTrackActivity.getSupportFragmentManager();
            FragmentTransaction myFT = myFM.beginTransaction();

            Fragment myExisting = myFM.findFragmentByTag(TRACK_PLAYBACK_TAG);
            if (myExisting != null) {
                Log.w(LOG_TAG, "Had to remove a previously existing PlaybackFragment.");
                myFT.remove(myExisting);
            }

            myFT.replace(R.id.fragment_playback_container, mPlaybackFragment, TRACK_PLAYBACK_TAG)
                    .addToBackStack(null).commit();
        } else {
            FragmentManager myFM = mMainActivity.getSupportFragmentManager();
            FragmentTransaction myFT = myFM.beginTransaction();

            Fragment myExisting = myFM.findFragmentByTag(TRACK_PLAYBACK_TAG);
            if (myExisting != null) {
                Log.w(LOG_TAG, "Had to remove a previously existing PlaybackFragment.");
                myFT.remove(myExisting);
            }

            myFT.addToBackStack(null);
            mPlaybackFragment.show(myFT, TRACK_PLAYBACK_TAG);
        }
    }

    public void registerMainActivity(MainActivity pMainActivity) {
        mMainActivity = pMainActivity;
    }

    public void unregisterMainActivity() {
        mMainActivity = null;
        unregisterArtistFragment();
        unregisterTrackFragment();
    }

    public void registerTrackActivity(TrackActivity pTrackActivity) {
        mTrackActivity = pTrackActivity;
    }

    public void unregisterTrackActivity() {
        mTrackActivity = null;
        unregisterTrackFragment();
    }

    public void registerArtistFragment(ArtistFragment pArtistFragment) {
        mArtistFragment = pArtistFragment;

        if (mArtistFragment != null) {
            registerArtistListPosition(mArtistFragment.getArtlistPosition());
        }
    }

    public void unregisterArtistFragment() {
        mArtistFragment = null;
        unregisterArtistListPosition();
    }

    public void registerTrackFragment(TrackFragment pTrackFragment) {
        mTrackFragment = pTrackFragment;
    }

    public void unregisterTrackFragment() {
        mTrackFragment = null;
    }

    public void registerPlaybackFragment(PlaybackFragment pPlaybackFragment) {
        mPlaybackFragment = pPlaybackFragment;
    }

    public void unregisterPlaybackFragment() {
        mPlaybackFragment = null;
    }

    public void registerArtistListPosition(int pArtistListPosition) {
        int myResult = -1;

        if (mArtistFragment != null && mArtistFragment.getArtistListEntries() != null && pArtistListPosition >= 0
                && mArtistFragment.getArtistListEntries().size() > pArtistListPosition) {
            myResult = pArtistListPosition;
        }

        mArtistListPosition = myResult;
    }

    public void unregisterArtistListPosition() {
        mArtistListPosition = -1;
    }
}