org.opensilk.music.ui3.main.FooterScreenPresenter.java Source code

Java tutorial

Introduction

Here is the source code for org.opensilk.music.ui3.main.FooterScreenPresenter.java

Source

/*
 * Copyright (c) 2015 OpenSilk Productions 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 org.opensilk.music.ui3.main;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.PlaybackStateCompat;

import org.apache.commons.lang3.StringUtils;
import org.opensilk.common.core.dagger2.ForApplication;
import org.opensilk.common.core.dagger2.ScreenScope;
import org.opensilk.common.ui.mortar.PauseAndResumeRegistrar;
import org.opensilk.common.ui.mortar.PausesAndResumes;
import org.opensilk.music.AppPreferences;
import org.opensilk.music.R;
import org.opensilk.music.artwork.requestor.ArtworkRequestManager;
import org.opensilk.music.playback.control.PlaybackController;
import org.opensilk.music.ui3.NowPlayingActivity;

import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import hugo.weaving.DebugLog;
import mortar.MortarScope;
import mortar.ViewPresenter;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.subscriptions.CompositeSubscription;
import timber.log.Timber;

import static org.opensilk.common.core.rx.RxUtils.isSubscribed;
import static android.support.v4.media.MediaMetadataCompat.*;
import static android.support.v4.media.session.PlaybackStateCompat.*;

/**
 * Created by drew on 4/20/15.
 */
@ScreenScope
public class FooterScreenPresenter extends ViewPresenter<FooterScreenView> implements PausesAndResumes {

    final Context appContext;
    final PlaybackController playbackController;
    final ArtworkRequestManager artworkReqestor;
    final PauseAndResumeRegistrar pauseAndResumeRegistrar;
    final AppPreferences settings;

    String lastTrackName;
    String lastArtistName;
    Bitmap lastAlbumARt;
    long lastPosition;
    long lastDuration;
    boolean lastPosSynced;

    CompositeSubscription broadcastSubscriptions;
    Subscription progressSubscription;

    @Inject
    public FooterScreenPresenter(@ForApplication Context context, PlaybackController playbackController,
            ArtworkRequestManager artworkReqestor, PauseAndResumeRegistrar pauseAndResumeRegistrar,
            AppPreferences settings) {
        this.appContext = context;
        this.playbackController = playbackController;
        this.artworkReqestor = artworkReqestor;
        this.pauseAndResumeRegistrar = pauseAndResumeRegistrar;
        this.settings = settings;
    }

    @Override
    protected void onEnterScope(MortarScope scope) {
        Timber.v("onEnterScope()");
        super.onEnterScope(scope);
        pauseAndResumeRegistrar.register(scope, this);
    }

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

    @Override
    protected void onLoad(Bundle savedInstanceState) {
        Timber.v("onLoad()");
        super.onLoad(savedInstanceState);
        if (pauseAndResumeRegistrar.isRunning()) {
            Timber.v("missed onResume()");
            subscribeBroadcasts();
        }
    }

    @Override
    protected void onSave(Bundle outState) {
        Timber.v("onSave()");
        super.onSave(outState);
        if (!hasView() && pauseAndResumeRegistrar.isRunning()) {
            Timber.v("missed onPause()");
            unsubscribeBroadcasts();
            unsubscribeProgress();
        }
    }

    @Override
    public void onResume() {
        Timber.v("onResume()");
        if (hasView()) {
            subscribeBroadcasts();
        }
    }

    @Override
    public void onPause() {
        Timber.v("onPause");
        unsubscribeBroadcasts();
        unsubscribeProgress();
    }

    void setTrackName(String s) {
        if (!StringUtils.equals(lastTrackName, s)) {
            lastTrackName = s;
            if (hasView()) {
                getView().trackTitle.setText(s);
            }
        }
    }

    void setArtistName(String s) {
        if (!StringUtils.equals(lastArtistName, s)) {
            lastArtistName = s;
            if (hasView()) {
                getView().artistName.setText(s);
            }
        }
    }

    void setProgress(int progress) {
        if (hasView()) {
            getView().progressBar.setIndeterminate(progress == -1);
            getView().progressBar.setProgress(progress);
        }
    }

    void updateArtwork(Bitmap bitmap) {
        if (bitmap != null) {
            if (!bitmap.sameAs(lastAlbumARt)) {
                lastAlbumARt = bitmap;
                if (hasView()) {
                    getView().artworkThumbnail.setImageBitmap(bitmap, true);
                }
            }
        } else if (hasView()) {
            getView().artworkThumbnail.setDefaultImage(R.drawable.default_artwork);
        }
    }

    void onClick(Context context) {
        handleClick(settings.getString(AppPreferences.FOOTER_CLICK, AppPreferences.ACTION_OPEN_QUEUE), context);
    }

    boolean onLongClick(Context context) {
        return handleClick(settings.getString(AppPreferences.FOOTER_LONG_CLICK, AppPreferences.ACTION_NONE),
                context);
    }

    void onThumbClick(Context context) {
        handleClick(settings.getString(AppPreferences.FOOTER_THUMB_CLICK, AppPreferences.ACTION_OPEN_NOW_PLAYING),
                context);
    }

    boolean onThumbLongClick(Context context) {
        return handleClick(settings.getString(AppPreferences.FOOTER_THUMB_LONG_CLICK, AppPreferences.ACTION_NONE),
                context);
    }

    @DebugLog
    boolean handleClick(String action, Context context) {
        switch (action) {
        case AppPreferences.ACTION_OPEN_QUEUE:
        case AppPreferences.ACTION_OPEN_NOW_PLAYING:
            NowPlayingActivity.startSelf(context);
            return true;
        case AppPreferences.ACTION_NONE:
        default:
            return false;
        }
    }

    void subscribeBroadcasts() {
        if (isSubscribed(broadcastSubscriptions)) {
            return;
        }
        Subscription s = playbackController.subscribePlayStateChanges(new Action1<PlaybackStateCompat>() {
            @Override
            public void call(PlaybackStateCompat playbackState) {
                final int state = playbackState.getState();
                if (state == STATE_BUFFERING || state == STATE_CONNECTING) {
                    setProgress(-1);
                } else {
                    long position = playbackState.getPosition();
                    long duration = playbackState.getBufferedPosition();
                    if (position < 0 || duration <= 0) {
                        setProgress(1000);
                    } else {
                        setProgress((int) (1000 * position / duration));
                    }
                    Timber.v("Position discrepancy = %d", lastPosition - position);
                    lastPosition = position;
                    lastDuration = duration;
                    lastPosSynced = true;
                    subscribeProgress(MainPresenter.isPlaying(playbackState));
                }

            }
        });
        Subscription s2 = playbackController.subscribeMetaChanges(new Action1<MediaMetadataCompat>() {
            @Override
            public void call(MediaMetadataCompat mediaMetadata) {
                setTrackName(mediaMetadata.getString(METADATA_KEY_TITLE));
                setArtistName(mediaMetadata.getString(METADATA_KEY_ARTIST));
                updateArtwork(mediaMetadata.getBitmap(METADATA_KEY_ALBUM_ART));
            }
        });

        broadcastSubscriptions = new CompositeSubscription(s, s2);
    }

    void unsubscribeBroadcasts() {
        if (isSubscribed(broadcastSubscriptions)) {
            broadcastSubscriptions.unsubscribe();
            broadcastSubscriptions = null;
        }
    }

    void subscribeProgress(boolean playing) {
        if (isSubscribed(progressSubscription)) {
            if (!playing) {
                unsubscribeProgress();
            }
            return;
        }
        final long interval = 250;
        progressSubscription = Observable.interval(interval, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        long position = lastPosition;
                        if (lastPosSynced) {
                            lastPosSynced = false;
                        } else {
                            position += interval + 10;
                            lastPosition = position;
                        }
                        long duration = lastDuration;
                        if (position < 0 || duration <= 0) {
                            setProgress(1000);
                        } else {
                            setProgress((int) (1000 * position / duration));
                        }
                    }
                });
    }

    void unsubscribeProgress() {
        if (isSubscribed(progressSubscription)) {
            progressSubscription.unsubscribe();
            progressSubscription = null;
        }
    }

}