<commit_before>package com.radiostream.player;

import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v7.app.NotificationCompat;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;

import com.radiostream.MainActivity;
import com.radiostream.R;
import com.radiostream.di.components.DaggerPlayerServiceComponent;
import com.radiostream.di.components.PlayerServiceComponent;
import com.radiostream.di.modules.ContextModule;
import com.radiostream.javascript.bridge.PlayerBridge;
import com.radiostream.javascript.bridge.PlaylistPlayerBridge;
import com.radiostream.javascript.bridge.PlaylistPlayerEventsEmitter;
import com.radiostream.javascript.bridge.SongBridge;
import com.radiostream.javascript.proxy.PlayerJsProxy;
import com.radiostream.util.SetTimeout;

import org.jdeferred.DoneCallback;
import org.jdeferred.Promise;

import java.util.Date;
import java.util.Objects;

import javax.inject.Inject;

import hugo.weaving.DebugLog;
import timber.log.Timber;


@DebugLog
public class PlayerService extends Service implements PlaylistControls {

    private final int mStopPausedServiceAfterMs = 10 * 60 * 1000;
    private final int mStopPausedServiceRetryAfterMs = 30 * 1000;
    private final int mNotificationId = 1;
    private final String mParamExit = "mParamExit";
    private final PlayerServiceBinder mBinder = new PlayerServiceBinder();

    private boolean mServiceAlive = true;
    private Date mPausedDate = null;
    private boolean mPausedDuePhoneState = false;

    MediaSession mMediaSession = null;

    @Inject
    Player mPlayer;
    @Inject
    PlaylistPlayerEventsEmitter mPlaylistPlayerEventsEmitter;
    @Inject
    SetTimeout mSetTimeout;


    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Timber.i("function start");
            if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                Timber.i("bluetooth disconnected");
                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (btDevice.getBluetoothClass().getMajorDeviceClass() == BluetoothClass.Device.Major.AUDIO_VIDEO) {
                    Timber.i("pausing music due to bluetooth disconnection");
                    mPlayer.pause();
                }
            }
        }
    };

    private PhoneStateListener phoneStateListener = new PhoneStateListener() {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            Timber.i("function start");
            if (state == TelephonyManager.CALL_STATE_RINGING || state == TelephonyManager.CALL_STATE_OFFHOOK) {
                Timber.i("telephone busy state: %d", state);
                if(mPlayer.getIsPlaying()) {
                    Timber.i("pausing due to telephone state");
                    mPlayer.pause();
                    mPausedDuePhoneState = true;
                }
            } else if(state == TelephonyManager.CALL_STATE_IDLE) {
                Timber.i("telehpone idle state");
                if(mPausedDuePhoneState) {
                    Timber.i("resuming pause music");
                    mPlayer.play();
                    mPausedDuePhoneState = false;
                }
            }

            super.onCallStateChanged(state, incomingNumber);
        }
    };

    private PlaylistPlayerEventsEmitter.EventCallback onPlaylistPlayerEvent = new PlaylistPlayerEventsEmitter.EventCallback() {
        @Override
        public void onEvent(PlaylistPlayerBridge playlistPlayerBridge) {
            Timber.i("onPlaylistPlayerEvent - function start");

            if (playlistPlayerBridge != null) {
                if (playlistPlayerBridge.isLoading) {
                    Timber.i("showing loading notification");
                    showLoadingNotification();
                } else if (playlistPlayerBridge.isPlaying) {
                    Timber.i("showing song notification");
                    showSongNotification(playlistPlayerBridge.songBridge);
                }
            }
        }
    };

    private void showSongNotification(SongBridge currentSong) {
        Timber.i("function start - show song notification for: %s - %s", currentSong.title, currentSong.artist);
        startWithNotificaiton(currentSong.title, currentSong.artist, true);
    }

    private void showLoadingNotification() {
        Timber.i("function start - show loading notification");
        startWithNotificaiton("Radio Stream", "Loading...", false);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Timber.i("function start");

        PlayerServiceComponent component = DaggerPlayerServiceComponent.builder()
            .jsProxyComponent(PlayerJsProxy.JsProxyComponent())
            .contextModule(new ContextModule(this))
            .build();

        component.inject(this);

        Timber.i("registering to bluetooth events");
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        registerReceiver(mReceiver, intentFilter);

        Timber.i("registering to telephony events");
        TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        if(mgr != null) {
            mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
        }

        mMediaSession = new MediaSession(this, "PlayerService");
        mMediaSession.setCallback(new MediaSession.Callback() {
            @Override
            public void onPlay() {
                Timber.i("bluetooth onPlay");
            }

            @Override
            public void onPause() {
                Timber.i("bluetooth onPause");
            }
        });

        mMediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
            MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);

        mMediaSession.setActive(true);

        PlaybackState state = new PlaybackState.Builder()
            .setActions(
                PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PLAY_PAUSE |
                    PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | PlaybackState.ACTION_PAUSE |
                    PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS)
            .build();
        mMediaSession.setPlaybackState(state);

        Timber.i("registering to player events");
        mPlaylistPlayerEventsEmitter.subscribe(onPlaylistPlayerEvent);
        scheduleStopSelfOnPause();
    }

    private void scheduleStopSelfOnPause() {
        Timber.i("function start");

        // We're retrying even after stopping a service because a stopped service might still be bound to activity
        if (mServiceAlive) {
            if (mPausedDate != null) {<commit_msg>bluetooth controls work<commit_after>package com.radiostream.player;

import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.NotificationCompat;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;

import com.radiostream.MainActivity;
import com.radiostream.R;
import com.radiostream.di.components.DaggerPlayerServiceComponent;
import com.radiostream.di.components.PlayerServiceComponent;
import com.radiostream.di.modules.ContextModule;
import com.radiostream.javascript.bridge.PlayerBridge;
import com.radiostream.javascript.bridge.PlaylistPlayerBridge;
import com.radiostream.javascript.bridge.PlaylistPlayerEventsEmitter;
import com.radiostream.javascript.bridge.SongBridge;
import com.radiostream.javascript.proxy.PlayerJsProxy;
import com.radiostream.util.SetTimeout;

import org.jdeferred.DoneCallback;
import org.jdeferred.Promise;

import java.util.Date;
import java.util.Objects;

import javax.inject.Inject;

import hugo.weaving.DebugLog;
import timber.log.Timber;


@DebugLog
public class PlayerService extends Service implements PlaylistControls {

    private final int mStopPausedServiceAfterMs = 10 * 60 * 1000;
    private final int mStopPausedServiceRetryAfterMs = 30 * 1000;
    private final int mNotificationId = 1;
    private final String mParamExit = "mParamExit";
    private final PlayerServiceBinder mBinder = new PlayerServiceBinder();

    private boolean mServiceAlive = true;
    private Date mPausedDate = null;
    private boolean mPausedDuePhoneState = false;

    MediaSession mMediaSession = null;

    @Inject
    Player mPlayer;
    @Inject
    PlaylistPlayerEventsEmitter mPlaylistPlayerEventsEmitter;
    @Inject
    SetTimeout mSetTimeout;


    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Timber.i("function start");
            if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                Timber.i("bluetooth disconnected");
                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (btDevice.getBluetoothClass().getMajorDeviceClass() == BluetoothClass.Device.Major.AUDIO_VIDEO) {
                    Timber.i("pausing music due to bluetooth disconnection");
                    mPlayer.pause();
                }
            }
        }
    };

    private PhoneStateListener phoneStateListener = new PhoneStateListener() {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            Timber.i("function start");
            if (state == TelephonyManager.CALL_STATE_RINGING || state == TelephonyManager.CALL_STATE_OFFHOOK) {
                Timber.i("telephone busy state: %d", state);
                if(mPlayer.getIsPlaying()) {
                    Timber.i("pausing due to telephone state");
                    mPlayer.pause();
                    mPausedDuePhoneState = true;
                }
            } else if(state == TelephonyManager.CALL_STATE_IDLE) {
                Timber.i("telehpone idle state");
                if(mPausedDuePhoneState) {
                    Timber.i("resuming pause music");
                    mPlayer.play();
                    mPausedDuePhoneState = false;
                }
            }

            super.onCallStateChanged(state, incomingNumber);
        }
    };

    private PlaylistPlayerEventsEmitter.EventCallback onPlaylistPlayerEvent = new PlaylistPlayerEventsEmitter.EventCallback() {
        @Override
        public void onEvent(PlaylistPlayerBridge playlistPlayerBridge) {
            Timber.i("onPlaylistPlayerEvent - function start");

            if (playlistPlayerBridge != null) {
                if (playlistPlayerBridge.isLoading) {
                    Timber.i("showing loading notification");
                    showLoadingNotification();
                } else if (playlistPlayerBridge.isPlaying) {
                    Timber.i("showing song notification");
                    showSongNotification(playlistPlayerBridge.songBridge);
                }
            }
        }
    };
    
    private MediaSession.Callback mMediaSessionCallback = new MediaSession.Callback() {

        @Override
        public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
            Timber.i("function start");

            KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
            if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
                switch (ke.getKeyCode()) {
                    case KeyEvent.KEYCODE_MEDIA_PLAY:
                        Timber.i("play media button");
                        PlayerService.this.play();
                        return true;
                    case KeyEvent.KEYCODE_MEDIA_PAUSE:
                        Timber.i("pause media button");
                        PlayerService.this.pause();
                        return true;
                    case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                        Timber.i("play/pause media button");
                        PlayerService.this.playPause();
                        return true;
                }
            }

            return false;
        }
    };

    private void showSongNotification(SongBridge currentSong) {
        Timber.i("function start - show song notification for: %s - %s", currentSong.title, currentSong.artist);
        startWithNotificaiton(currentSong.title, currentSong.artist, true);
    }

    private void showLoadingNotification() {
        Timber.i("function start - show loading notification");
        startWithNotificaiton("Radio Stream", "Loading...", false);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Timber.i("function start");

        PlayerServiceComponent component = DaggerPlayerServiceComponent.builder()
            .jsProxyComponent(PlayerJsProxy.JsProxyComponent())
            .contextModule(new ContextModule(this))
            .build();

        component.inject(this);

        Timber.i("registering to bluetooth events");
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        registerReceiver(mReceiver, intentFilter);

        Timber.i("registering to telephony events");
        TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        if(mgr != null) {
            mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
        }

        mMediaSession = new MediaSession(this, "PlayerService");
        mMediaSession.setCallback(mMediaSessionCallback);
        mMediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mMediaSession.setActive(true);
        PlaybackState state = new PlaybackState.Builder().setActions(PlaybackState.ACTION_PLAY_PAUSE).build();
        mMediaSession.setPlaybackState(state);

        Timber.i("registering to player events");
        mPlaylistPlayerEventsEmitter.subscribe(onPlaylistPlayerEvent);
        scheduleStopSelfOnPause();
    }

    private void playPause() {
        if(this.mPlayer.getIsPlaying()) {
            this.mPlayer.pause();
        } else {
            this.mPlayer.play();
        }
    }

    private void scheduleStopSelfOnPause() {
        Timber.i("function start");

        // We're retrying even after stopping a service because a stopped service might still be bound to activity
        if (mServiceAlive) {
            if (mPausedDate != null) {
{'fraction_non_alphanumeric': 0.08494879886649064, 'fraction_numerical': 0.002060926128679075, 'mean_word_length': 2.7050823192555478, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4335015', 'n_tokens_mistral': 4183, 'n_tokens_neox': 3976, 'n_words': 789}