/* == This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2014, Enno Gottschalk <mrmaffen@googlemail.com>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
package org.tomahawk.tomahawk_android.services;
import org.electricwisdom.unifiedremotemetadataprovider.media.RemoteMetadataProvider;
import org.electricwisdom.unifiedremotemetadataprovider.media.enums.PlayState;
import org.electricwisdom.unifiedremotemetadataprovider.media.enums.RemoteControlFeature;
import org.electricwisdom.unifiedremotemetadataprovider.media.listeners.OnArtworkChangeListener;
import org.electricwisdom.unifiedremotemetadataprovider.media.listeners.OnMetadataChangeListener;
import org.electricwisdom.unifiedremotemetadataprovider.media.listeners.OnPlaybackStateChangeListener;
import org.electricwisdom.unifiedremotemetadataprovider.media.listeners.OnRemoteControlFeaturesChangeListener;
import org.tomahawk.libtomahawk.authentication.AuthenticatorManager;
import org.tomahawk.libtomahawk.authentication.AuthenticatorUtils;
import org.tomahawk.libtomahawk.collection.Album;
import org.tomahawk.libtomahawk.collection.Artist;
import org.tomahawk.libtomahawk.collection.Track;
import org.tomahawk.libtomahawk.infosystem.InfoSystem;
import org.tomahawk.libtomahawk.resolver.Query;
import org.tomahawk.tomahawk_android.TomahawkApp;
import org.tomahawk.tomahawk_android.utils.PreferenceUtils;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import java.util.List;
public class MicroService extends Service {
private static final String TAG = MicroService.class.getSimpleName();
public static final String ACTION_PLAYSTATECHANGED
= "org.tomahawk.tomahawk_android.playstatechanged";
public static final String EXTRA_TRACKKEY = "org.tomahawk.tomahawk_android.track_key";
public static final String EXTRA_STATE = "org.tomahawk.tomahawk_android.extra_state";
public static final String EXTRA_TIMESTAMP = "org.tomahawk.tomahawk_android.extra_timestamp";
public static final String EXTRA_SOURCE = "org.tomahawk.tomahawk_android.extra_source";
public static final String EXTRA_MBID = "org.tomahawk.tomahawk_android.extra_mbid";
public static final String EXTRA_IS_SAME_AS_CURRENT_TRACK
= "org.tomahawk.tomahawk_android.is_same_as_current_track";
public enum State {
START, RESUME, PAUSE, COMPLETE, PLAYLIST_FINISHED, UNKNOWN_NONPLAYING
}
private static Track sCurrentTrack = null;
private RemoteMetadataProvider mMetadataProvider;
private MicroServiceBroadcastReceiver mMicroServiceBroadcastReceiver;
/**
* Handles incoming broadcasts
*/
private class MicroServiceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_HEADSET_PLUG.equals(intent.getAction()) && intent
.hasExtra("state") && intent.getIntExtra("state", 0) == 1) {
Log.d(TAG, "Headset has been plugged in");
if (PreferenceUtils.getBoolean(PreferenceUtils.PLUG_IN_TO_PLAY)) {
//resume playback, if user has set the "resume on headset plugin" preference
context.startService(new Intent(PlaybackService.ACTION_PLAY, null, context,
PlaybackService.class));
}
}
}
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
//Acquiring instance of RemoteMetadataProvider
mMetadataProvider = RemoteMetadataProvider.getInstance(this);
//setting up metadata listener
mMetadataProvider.setOnMetadataChangeListener(new OnMetadataChangeListener() {
@Override
public void onMetadataChanged(String artistName, String trackName,
String albumName,
String albumArtistName, long duration) {
Log.d(TAG, "onMetadataChanged");
scrobbleTrack(trackName, artistName, albumName, albumArtistName);
}
});
//setting up artwork listener
mMetadataProvider.setOnArtworkChangeListener(new OnArtworkChangeListener() {
@Override
public void onArtworkChanged(Bitmap artwork) {
Log.d(TAG, "onArtworkChanged");
}
});
//setting up remote control flags listener
mMetadataProvider.setOnRemoteControlFeaturesChangeListener(
new OnRemoteControlFeaturesChangeListener() {
@Override
public void onFeaturesChanged(List<RemoteControlFeature> usesFeatures) {
Log.d(TAG, "onFeaturesChanged");
}
}
);
//setting up playback state change listener
mMetadataProvider
.setOnPlaybackStateChangeListener(new OnPlaybackStateChangeListener() {
@Override
public void onPlaybackStateChanged(PlayState playbackState) {
Log.d(TAG, "onPlaybackStateChanged");
}
});
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
mMetadataProvider.acquireRemoteControls();
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
mMetadataProvider.acquireRemoteControls(256, 256);
}
}
mMicroServiceBroadcastReceiver = new MicroServiceBroadcastReceiver();
registerReceiver(mMicroServiceBroadcastReceiver,
new IntentFilter(Intent.ACTION_HEADSET_PLUG));
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent i, int flags, int startId) {
if (i != null) {
String action = i.getAction();
Bundle extras = i.getExtras();
if (ACTION_PLAYSTATECHANGED.equals(action)) {
if (extras != null) {
MicroService.State state = MicroService.State
.valueOf(extras.getString(EXTRA_STATE));
Track track = Track.getByKey(extras.getString(EXTRA_TRACKKEY));
boolean isSameAsCurrentTrack = extras
.containsKey(EXTRA_IS_SAME_AS_CURRENT_TRACK);
String source = extras.getString(EXTRA_SOURCE);
if (track != null || isSameAsCurrentTrack) {
onPlayStateChanged(track, state, isSameAsCurrentTrack, source);
}
}
}
}
return Service.START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mMicroServiceBroadcastReceiver);
mMicroServiceBroadcastReceiver = null;
Log.d(TAG, "MicroService has been destroyed");
}
private synchronized void onPlayStateChanged(Track track, MicroService.State state,
boolean isSameAsCurrentTrack, String source) {
if (isSameAsCurrentTrack) {
// this only happens for apps implementing Scrobble Droid's API
Log.d(TAG, "Got a SAME_AS_CURRENT track");
if (sCurrentTrack != null) {
track = sCurrentTrack;
} else {
Log.e(TAG, "Got a SAME_AS_CURRENT track, but current was null!");
return;
}
}
if (State.RESUME.equals(state) || State.START.equals(state)) {
scrobbleTrack(track.getName(), track.getArtist().getName(), track.getAlbum().getName(),
null);
}
}
public static void scrobbleTrack(String trackName, String artistName, String albumName,
String albumArtistName) {
boolean scrobbleEverything = PreferenceUtils.getBoolean(PreferenceUtils.SCROBBLE_EVERYTHING)
|| Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
if (scrobbleEverything && !TextUtils.isEmpty(trackName) && (!TextUtils.isEmpty(artistName)
|| !TextUtils.isEmpty(albumArtistName) || !TextUtils.isEmpty(albumName))) {
Artist artist;
Album album;
if (!TextUtils.isEmpty(artistName)) {
artist = Artist.get(artistName);
album = Album.get(albumName, artist);
} else if (!TextUtils.isEmpty(albumArtistName)) {
artist = Artist.get(albumArtistName);
album = Album.get(albumName, artist);
} else {
// Since the artistName is empty and the albumName isn't, we just assume that
// something got switched up. So we use the albumName as the artistName instead.
artist = Artist.get(albumName);
album = Album.get(null, artist);
}
Track track = Track.get(trackName, album, artist);
if (sCurrentTrack != track) {
sCurrentTrack = track;
AuthenticatorUtils utils = AuthenticatorManager.get()
.getAuthenticatorUtils(TomahawkApp.PLUGINNAME_HATCHET);
InfoSystem.get().sendNowPlayingPostStruct(utils, Query.get(track, false));
Log.d(TAG, "Scrobbling " + track);
}
} else {
Log.d(TAG, "Didn't scrobble track: '" + trackName + "' - '"
+ artistName + "' - '" + albumName + "' - '" + albumArtistName);
}
}
}