package com.sound.ampache.service; /* Copyright (c) 2010 Jacob Alexander < haata@users.sf.net > * Copyright (c) 2014 David Hrdina Nemecek <dejvino@gmail.com> * * +------------------------------------------------------------------------+ * | 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 2 | * | 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, write to the Free Software | * | Foundation, Inc., 59 Temple Place - Suite 330, | * | Boston, MA 02111-1307, USA. | * +------------------------------------------------------------------------+ */ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import com.sound.ampache.MainActivity; import com.sound.ampache.objects.Media; import com.sound.ampache.utility.Player; import com.sound.ampache.utility.Playlist; import java.util.ArrayList; import java.util.Arrays; public class PlayerService extends Service { private static final String LOG_TAG = "Ampache_Amdroid_PlayerService"; // Basic service components private Player mediaPlayer; private Playlist playlist; private PlayerInterfaceListener listener; // Clients to send messages to private ArrayList<Messenger> clients = new ArrayList<Messenger>(); // ********************************************************************** // Client to Service Requests ******************************************* // ********************************************************************** @Override public IBinder onBind(Intent intent) { Log.d(LOG_TAG, "onBind"); // Make sure it's a valid request TODO if (IPlayerService.class.getName().equals(intent.getAction())) return mBinder; return mBinder; } @Override public void onRebind(Intent intent) { // All clients disconnected, and another connection is made Log.d(LOG_TAG, "onRebind"); } @Override public boolean onUnbind(Intent intent) { Log.d(LOG_TAG, "onUnbind"); return true; } @Override public void onCreate() { Log.d(LOG_TAG, "onCreate"); playlist = new Playlist(); mediaPlayer = new Player(this, playlist); // Setup Listner listener = new PlayerInterfaceListener(); mediaPlayer.setPlayerListener(listener); } @Override public void onDestroy() { Log.d(LOG_TAG, "onDestroy"); mediaPlayer.quit(); // Cleanup the telephony handler } @Override protected void finalize() { Log.d(LOG_TAG, "Android hath slain me :(killed):"); // TODO Warn the user (text) that the VM is killing the service } // Interface ********************************************************** private final IPlayerService.Stub mBinder = new IPlayerService.Stub() { // Player Status public boolean isPlaying() { return mediaPlayer.isPlaying(); } public boolean isSeekable() { return mediaPlayer.isSeekable(); } public int getBuffer() { return mediaPlayer.getBuffer(); } public int getCurrentPosition() { return mediaPlayer.getCurrentPosition(); } public int getDuration() { return mediaPlayer.getDuration(); } // Player Controls public void playMedia(Media media) { // TODO REMOVEME sendMessage(MSG_PLAY); mediaPlayer.playMedia(media); statusNotify(); } public void playPause() { mediaPlayer.doPauseResume(); stopNotify(); } public void stop() { mediaPlayer.stop(); stopNotify(); } public void next() { mediaPlayer.playMedia(playlist.next()); statusNotify(); } public void prev() { mediaPlayer.playMedia(playlist.prev()); statusNotify(); } public void seek(int msec) { mediaPlayer.seekTo(msec); } // Playlist Controls public Media nextItem() { return playlist.next(); } public Media prevItem() { return playlist.prev(); } // Playlist List Modifiers public Media[] currentPlaylist() { Media[] tmp = new Media[playlist.size()]; for (int c = 0; c < playlist.size(); c++) { tmp[c] = playlist.get(c); } return tmp; } public boolean add(Media media) { return playlist.add(media); } public boolean enqueue(Media[] media) { // Adds the given list of media items to the playlist return playlist.addAll(Arrays.asList(media)); } public boolean replace(Media[] media) { // Clears the playlist and replaces it with the given one playlist.clearPlaylist(); playlist.clearShuffleHistory(); return playlist.addAll(Arrays.asList(media)); } public void clearPlaylist() { playlist.clearPlaylist(); } // Playlist Item public int getCurrentIndex() { return playlist.getCurrentIndex(); } public int getPlaylistSize() { return playlist.size(); } public Media getCurrentMedia() { return playlist.getCurrentMedia(); } public Media setCurrentIndex(int index) { return playlist.setCurrentIndex(index); } // Shuffle/Repeat public boolean getShufflePlay() { return playlist.getShufflePlay(); } public boolean getRepeatPlay() { return playlist.getRepeatPlay(); } public void setShufflePlay(boolean randomize) { playlist.setShufflePlay(randomize); // Callback sendMessage(MSG_SHUFFLE_CHANGED, randomize ? 0 : 1); } public void setRepeatPlay(boolean loop) { playlist.setRepeatPlay(loop); // Callback sendMessage(MSG_REPEAT_CHANGED, loop ? 0 : 1); } public void clearShuffleHistory() { playlist.clearShuffleHistory(); } // Misc public void closeService() { } public void registerMessenger(Messenger messenger) { clients.add(messenger); } public void unregisterMessenger(Messenger messenger) { int remove = clients.lastIndexOf(messenger); if (remove >= 0) clients.remove(remove); } public void setAuthToken(String authToken) { mediaPlayer.setAuthToken(authToken); } }; // ********************************************************************** // Service to Client Messages ******************************************* // ********************************************************************** // Basic message types static final int MSG_SEEK_POSITION = 1; // Sent every time a seek is completed static final int MSG_BUFFER_PERCENTAGE = 2; // Sent when buffer updates static final int MSG_NEW_MEDIA = 3; // Sent on new media playing static final int MSG_PLAYLIST_INDEX = 4; // Sent on new media playing static final int MSG_SHUFFLE_CHANGED = 5; // Sent if the shuffle setting is changed static final int MSG_REPEAT_CHANGED = 6; // Sent if the repeat setting is changed static final int MSG_PLAY = 7; // Sent if the media player starts playing static final int MSG_PAUSE = 8; // Sent if the media player pauses the media static final int MSG_STOP = 9; // Sent if the media player stops playing static final int MSG_VIDEO_SIZE_CHANGED = 10; // Sent if the video size changes static final int MSG_PLAYLIST_CHANGED = 11; static final int MSG_SERVICE_CONNECTED = 100; static final int MSG_SERVICE_DISCONNECTED = 101; static final int MSG_ERROR = 200; // 1 - arg1 | getCurrentPosition - arg2 | 0 // 2 - arg1 | buffer percentage - arg2 | 0 // 3 - no args // 4 - arg1 | playlist index - arg2 | 0 // 5 - arg1 | 0 = True / 1 = False - arg2 | 0 // 6 - arg1 | 0 = True / 1 = False - arg2 | 0 // 7 - no args // 8 - no args // 9 - no args // 10 - arg1 | new width - arg2 | new height // 11 - arg1 | new size public void sendMessage(int message, int arg1, int arg2) { for (int c = 0; c < clients.size(); c++) { try { clients.get(c).send(Message.obtain(null, message, arg1, arg2)); } catch (RemoteException exp) { // Client is dead, remove it clients.remove(c); } } } public void sendMessage(int message, int arg) { sendMessage(message, arg, 0); } public void sendMessage(int message) { for (int c = 0; c < clients.size(); c++) { try { clients.get(c).send(Message.obtain(null, message)); } catch (RemoteException exp) { // Client is dead, remove it clients.remove(c); } } } // Player Interface private class PlayerInterfaceListener implements Player.PlayerListener { public void onPlayerStopped() { sendMessage(MSG_STOP); } public void onTogglePlaying(boolean playing) { if (playing) sendMessage(MSG_PLAY); else sendMessage(MSG_PAUSE); } public void onNewMediaPlaying(Media media) { sendMessage(MSG_NEW_MEDIA); } public void onVideoSizeChanged(int width, int height) { sendMessage(MSG_VIDEO_SIZE_CHANGED, width, height); } public void onBuffering(int buffer) { sendMessage(MSG_BUFFER_PERCENTAGE, buffer); } public void onSeek(int position) { sendMessage(MSG_SEEK_POSITION, position); } @Override public void onError(int what, int extra) { sendMessage(MSG_ERROR, what, extra); } } // ********************************************************************** // Notifications ******************************************************** // ********************************************************************** // Start notifications public void statusNotify() { // Setup Notification Manager for Amdroid Context context = getApplicationContext(); NotificationManager amdroidNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); int icon = com.sound.ampache.R.drawable.amdroid_notification; String mediaName = "No media"; String extraString = ""; if (playlist != null && playlist.getCurrentMedia() != null) { mediaName = playlist.getCurrentMedia().name; extraString = playlist.getCurrentMedia().extraString(); } CharSequence tickerText = "Amdroid - " + mediaName; long when = System.currentTimeMillis(); Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent mediaIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); // TODO: upgrade Notification notification = new Notification(icon, tickerText, when); notification.setLatestEventInfo(context, mediaName, extraString, mediaIntent); notification.flags |= Notification.FLAG_ONGOING_EVENT; amdroidNotifyManager.notify(1, notification); } // Stop notifications public void stopNotify() { // Setup Notification Manager for Amdroid NotificationManager amdroidNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); amdroidNotifyManager.cancel(1); } }