bucci.dev.freestyle.TimerService.java Source code

Java tutorial

Introduction

Here is the source code for bucci.dev.freestyle.TimerService.java

Source

/*
 Copyright Michal Buczek, 2014
 All rights reserved.
    
 Copyright Michal Buczek, 2014
 All rights reserved.
    
This file is part of Freestyle Timer.
    
Freestyle Timer 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 2 of the License, or
(at your option) any later version.
    
Freestyle Timer 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 Freestyle Timer; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package bucci.dev.freestyle;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import static bucci.dev.freestyle.TimerActivity.DELAY_FOR_BEEP;
import static bucci.dev.freestyle.TimerActivity.MSG_PAUSE_TIMER;
import static bucci.dev.freestyle.TimerActivity.MSG_START_EXTRA_ROUND_TIMER;
import static bucci.dev.freestyle.TimerActivity.MSG_START_PREPARATION_TIMER;
import static bucci.dev.freestyle.TimerActivity.MSG_START_TIMER;
import static bucci.dev.freestyle.TimerActivity.MSG_STOP_TIMER;
import static bucci.dev.freestyle.TimerActivity.PREPARATION_DURATION;
import static bucci.dev.freestyle.TimerActivity.SAVED_SONG_PATH_PARAM;
import static bucci.dev.freestyle.TimerActivity.SHARED_PREFS_PARAM;
import static bucci.dev.freestyle.TimerActivity.TIMER_TYPE_ERROR_VALUE;

public class TimerService extends Service {
    private static final boolean DEBUG = false;
    private static final String TAG = "BCC|TimerService";

    //Duplicated values from TimerType enum(Because serializable objects cannot be put in SharedPreferences)
    private final static int BATTLE_TIME_VALUE = 0;
    private final static int QUALIFICATION_TIME_VALUE = 1;
    private final static int ROUTINE_TIME_VALUE = 2;
    public static final int COUNT_DOWN_INTERVAL = 500;

    public static boolean hasTimerFinished = false;

    private SharedPreferences sharedPrefs;

    private MusicPlayer musicPlayer;
    private MediaPlayer beepPlayer;

    private class IncomingHandler extends Handler {
        CountDownTimer countDownTimer = null;

        {
            musicPlayer = new MusicPlayer();
        }

        @Override
        public void handleMessage(final Message msg) {
            switch (msg.what) {
            case MSG_START_TIMER:
                startTimerFromBackground((Long) msg.obj);
                break;

            case MSG_PAUSE_TIMER:
                musicPlayer.pause();
                if (countDownTimer != null) {
                    countDownTimer.cancel();
                    if (DEBUG)
                        Log.d(TAG, "Timer paused");

                    hasTimerFinished = false;
                }

                break;

            case MSG_STOP_TIMER:
                musicPlayer.stop();
                if (countDownTimer != null) {
                    countDownTimer.cancel();
                    if (DEBUG)
                        Log.d(TAG, "Timer stopped");

                    hasTimerFinished = false;
                }
                sendBroadcastToTimerActivity(TimerIntentFilter.ACTION_TIMER_STOP, 0);

                break;

            case MSG_START_PREPARATION_TIMER:
                if (DEBUG)
                    Log.i(TAG, "Preparation timer started");
                startPreparationTimer(false);
                break;

            case MSG_START_EXTRA_ROUND_TIMER:
                if (DEBUG)
                    Log.i(TAG, "Extra round preparation timer started");
                startPreparationTimer(true);
                break;

            default:
                super.handleMessage(msg);
            }
            super.handleMessage(msg);
        }

        private void startPreparationTimer(final boolean isExtraRound) {
            hasTimerFinished = false;

            if (beepPlayer != null) {
                beepPlayer.release();
                beepPlayer = null;
            }

            countDownTimer = new CountDownTimer(PREPARATION_DURATION, COUNT_DOWN_INTERVAL) {
                @Override
                public void onTick(long millsUntilFinished) {
                    sendBroadcastToTimerActivity(TimerIntentFilter.ACTION_PREPARATION_TIMER_TICK,
                            millsUntilFinished);
                }

                @Override
                public void onFinish() {
                    if (DEBUG)
                        Log.d(TAG, "Preparation timer onFinish()");
                    if (isExtraRound)
                        startTimerFromBackground(TimerActivity.EXTRA_TIME_DURATION);
                    else
                        startTimerFromBackground(getStartTime());

                }
            }.start();
        }

        private void startTimerFromBackground(long time) {
            SharedPreferences settings = getSharedPreferences(SHARED_PREFS_PARAM, 0);
            musicPlayer.play(settings.getString(SAVED_SONG_PATH_PARAM, ""));

            if (DEBUG)
                Log.i(TAG, "Timer started, milliseconds to finish: " + time);
            countDownTimer = new CountDownTimer(time, COUNT_DOWN_INTERVAL) {
                @Override
                public void onTick(long millsUntilFinished) {
                    if (getTimerTypeValue() != ROUTINE_TIME_VALUE) {
                        if (isIntervalReached(millsUntilFinished)) {
                            playBeep();
                        } else if (isTimerFinishing(millsUntilFinished))
                            playFinishBeep();
                    }
                    sendBroadcastToTimerActivity(TimerIntentFilter.ACTION_TIMER_TICK, millsUntilFinished);

                }

                @Override
                public void onFinish() {
                    if (DEBUG)
                        Log.i(TAG, "Timer onFinish()");
                    musicPlayer.stop();

                    hasTimerFinished = true;

                    sendBroadcastToTimerActivity(TimerIntentFilter.ACTION_TIMER_FINISH, 0);
                }
            }.start();
        }

        //Playing finish horn sound a second before onFinish() for smoother experience
        private boolean isTimerFinishing(long millsUntilFinished) {
            return millsUntilFinished < 1000;
        }

        private boolean isIntervalReached(long millsUntilFinished) {
            return millsUntilFinished % (30 * 1000) < 500;
        }

        private void sendBroadcastToTimerActivity(String action, long timeLeft) {
            Intent intent = new Intent(action);
            if (action.equals(TimerIntentFilter.ACTION_TIMER_TICK)
                    || action.equals(TimerIntentFilter.ACTION_PREPARATION_TIMER_TICK))
                intent.putExtra(TimerActivity.TIME_LEFT_PARAM, timeLeft);
            LocalBroadcastManager.getInstance(TimerService.this).sendBroadcast(intent);

        }
    }

    private long getStartTime() {
        switch (getTimerTypeValue()) {
        case BATTLE_TIME_VALUE:
            return TimerActivity.BATTLE_DURATION + DELAY_FOR_BEEP;
        case QUALIFICATION_TIME_VALUE:
            return TimerActivity.QUALIFICATION_DURATION + DELAY_FOR_BEEP;
        case ROUTINE_TIME_VALUE:
            return TimerActivity.routine_duration + DELAY_FOR_BEEP;
        default:
            if (DEBUG)
                Log.e(TAG, "getStartTime(), Error in getting start time");
            return 0;
        }

    }

    private int getTimerTypeValue() {
        return sharedPrefs.getInt(StartActivity.TIMER_TYPE, TIMER_TYPE_ERROR_VALUE);
    }

    private void playBeep() {
        if (beepPlayer == null) {
            switch (getTimerTypeValue()) {
            case BATTLE_TIME_VALUE:
                beepPlayer = MediaPlayer.create(TimerService.this, R.raw.airhorn);
                break;
            case QUALIFICATION_TIME_VALUE:
                beepPlayer = MediaPlayer.create(TimerService.this, R.raw.beep2);
                break;
            }

        }

        beepPlayer.start();
    }

    private void playFinishBeep() {
        beepPlayer = MediaPlayer.create(TimerService.this, R.raw.airhorn_finish);
        beepPlayer.start();
    }

    final Messenger messenger = new Messenger(new IncomingHandler());

    @Override
    public IBinder onBind(Intent intent) {
        if (DEBUG)
            Log.d(TAG, "IBinder onBind()");
        sharedPrefs = getSharedPreferences(SHARED_PREFS_PARAM, MODE_PRIVATE);

        return messenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        if (DEBUG)
            Log.d(TAG, "IBinder onUnbind()");
        musicPlayer.stop();

        return super.onUnbind(intent);
    }

}