com.doctoror.fuckoffmusicplayer.presentation.playback.PlaybackAndroidService.java Source code

Java tutorial

Introduction

Here is the source code for com.doctoror.fuckoffmusicplayer.presentation.playback.PlaybackAndroidService.java

Source

/*
 * Copyright (C) 2016 Yaroslav Mytkalyk
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.doctoror.fuckoffmusicplayer.presentation.playback;

import android.Manifest;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v4.content.ContextCompat;
import android.view.KeyEvent;

import com.doctoror.fuckoffmusicplayer.domain.media.CurrentMediaProvider;
import com.doctoror.fuckoffmusicplayer.domain.playback.PlaybackData;
import com.doctoror.fuckoffmusicplayer.domain.playback.PlaybackService;
import com.doctoror.fuckoffmusicplayer.domain.queue.Media;

import java.util.List;

import javax.inject.Inject;

import dagger.android.AndroidInjection;

/**
 * Media playback Service
 */
public final class PlaybackAndroidService extends Service {

    static final String ACTION_RESEND_STATE = "ACTION_RESEND_STATE";

    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
    public static final String ACTION_PLAY_PAUSE = "ACTION_PLAY_PAUSE";

    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
    public static final String ACTION_PLAY_ANYTHING = "ACTION_PLAY_ANYTHING";

    static final String ACTION_PLAY = "ACTION_PLAY";
    static final String ACTION_PAUSE = "ACTION_PAUSE";
    static final String ACTION_STOP = "ACTION_STOP";
    static final String ACTION_STOP_WITH_ERROR = "ACTION_STOP_WITH_ERROR";

    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
    public static final String ACTION_PREV = "ACTION_PREV";

    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
    public static final String ACTION_NEXT = "ACTION_NEXT";

    static final String ACTION_SEEK = "ACTION_SEEK";
    static final String EXTRA_ERROR_MESSAGE = "EXTRA_ERROR_MESSAGE";
    static final String EXTRA_POSITION_PERCENT = "EXTRA_POSITION_PERCENT";

    static final String EXTRA_QUEUE = "EXTRA_QUEUE";
    static final String EXTRA_POSITION = "EXTRA_POSITION";

    private final ResendStateReceiver resendStateReceiver = new ResendStateReceiver();

    @Inject
    CurrentMediaProvider currentMediaProvider;

    @Inject
    PlaybackData playbackData;

    @Inject
    PlaybackService service;

    @Override
    public void onCreate() {
        super.onCreate();
        AndroidInjection.inject(this);
        registerReceiver(resendStateReceiver, new IntentFilter(ACTION_RESEND_STATE));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
        unregisterReceiver(resendStateReceiver);
        service.destroy();
    }

    public void restart() {
        service.restart();
    }

    @Nullable
    @Override
    public IBinder onBind(final Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            stopSelf();
            return START_NOT_STICKY;
        }

        if (intent == null) {
            stopSelf(startId);
            return START_NOT_STICKY;
        }

        final String action = intent.getAction();
        if (action == null) {
            stopSelf(startId);
            return START_NOT_STICKY;
        }

        switch (intent.getAction()) {
        case ACTION_PLAY_PAUSE:
            onActionPlayPause();
            break;

        case ACTION_PLAY:
            onActionPlay(intent);
            break;

        case ACTION_PLAY_ANYTHING:
            onActionPlayAnything();
            break;

        case ACTION_PAUSE:
            onActionPause();
            break;

        case ACTION_STOP:
            onActionStop();
            break;

        case ACTION_STOP_WITH_ERROR:
            onActionStopWithError(intent.getCharSequenceExtra(EXTRA_ERROR_MESSAGE));
            break;

        case ACTION_PREV:
            onActionPrev();
            break;

        case ACTION_NEXT:
            onActionNext();
            break;

        case ACTION_SEEK:
            onActionSeek(intent);
            break;

        case Intent.ACTION_MEDIA_BUTTON:
            onActionMediaButton(intent);
            break;

        default:
            stopSelf(startId);
            return START_NOT_STICKY;
        }
        return START_STICKY;
    }

    private void onActionMediaButton(@NonNull final Intent intent) {
        final KeyEvent keyEvent = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
        if (keyEvent != null && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
            switch (keyEvent.getKeyCode()) {
            case KeyEvent.KEYCODE_MEDIA_PLAY:
                onActionPlayPause();
                break;

            case KeyEvent.KEYCODE_MEDIA_PAUSE:
                onActionPause();
                break;

            case KeyEvent.KEYCODE_MEDIA_NEXT:
                onActionNext();
                break;

            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
                onActionPrev();
                break;

            case KeyEvent.KEYCODE_MEDIA_STOP:
                onActionStop();
                break;

            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                onActionPlayPause();
                break;
            }
        }
    }

    private void onActionPlay(@NonNull final Intent intent) {
        final List<Media> queue = intent.getParcelableArrayListExtra(EXTRA_QUEUE);
        final int position = intent.getIntExtra(EXTRA_POSITION, 0);
        service.play(queue, position);
    }

    private void onActionPlayAnything() {
        service.playAnything();
    }

    private void onActionPause() {
        service.pause();
    }

    private void onActionStop() {
        service.stop();
    }

    private void onActionStopWithError(@Nullable final CharSequence errorMessage) {
        service.stopWithError(errorMessage);
    }

    private void onActionPrev() {
        service.playPrev();
    }

    private void onActionNext() {
        service.playNext();
    }

    private void onActionPlayPause() {
        service.playPause();
    }

    private void onActionSeek(final Intent intent) {
        if (intent.hasExtra(EXTRA_POSITION_PERCENT)) {
            onActionSeek(intent.getFloatExtra(EXTRA_POSITION_PERCENT, 0f));
        }
    }

    private void onActionSeek(final float positionPercent) {
        final Media media = currentMediaProvider.getCurrentMedia();
        if (media != null) {
            final long duration = media.getDuration();
            if (duration > 0) {
                final int position = (int) ((float) duration * positionPercent);
                playbackData.setMediaPosition(position);
                service.seek(position);
            }
        }
    }

    private final class ResendStateReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            service.notifyState();
        }
    }
}