org.tunesremote.util.NotificationService.java Source code

Java tutorial

Introduction

Here is the source code for org.tunesremote.util.NotificationService.java

Source

/*
TunesRemote+ - http://code.google.com/p/tunesremote-plus/
    
Copyright (C) 2008 Jeffrey Sharkey, http://jsharkey.org/
Copyright (C) 2010 TunesRemote+, http://code.google.com/p/tunesremote-plus/
    
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 3 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, see <http://www.gnu.org/licenses/>.
    
The Initial Developer of the Original Code is Jeffrey Sharkey.
Portions created by Jeffrey Sharkey are
Copyright (C) 2008. Jeffrey Sharkey, http://jsharkey.org/
All Rights Reserved.
 */
package org.tunesremote.util;

import org.tunesremote.BackendService;
import org.tunesremote.ControlActivity;
import org.tunesremote.R;
import org.tunesremote.daap.Session;
import org.tunesremote.daap.Status;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;

/**
 * Author: Alex Curran Date: 12/07/2012 Time: 20:14
 */
public class NotificationService extends Service implements AudioManager.OnAudioFocusChangeListener {

    public static final String TAG = NotificationService.class.toString();
    public static final String ACTION_END_SERVICE = "end";
    public static final String ACTION_NEXT_TRACK = "next";
    public static final String ACTION_PAUSE = "pause";

    private BackendService backend;
    private Session session;
    private Status status;
    private NotificationHelper nHelper;
    private boolean bound = false;

    private Intent endServiceIntent;
    private Intent pauseIntent;
    private Intent nextTrackIntent;
    private Intent launchIntent;

    protected PendingIntent endServicePending;
    protected PendingIntent pausePending;
    protected PendingIntent nextTrackPending;
    protected PendingIntent launchPending;

    public ServiceConnection connection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, final IBinder service) {

            try {
                backend = ((BackendService.BackendBinder) service).getService();

                Log.w(TAG, "onServiceConnected for NotificationService");

                session = backend.getSession();
                if (session == null) {
                    if (nHelper != null)
                        nHelper.killNotification();
                    return;
                }
                // for some reason we are not correctly disposing of the
                // session threads we create so we purge any existing ones
                // before creating a new one
                status = session.notificationStatus(statusUpdate);
                status.updateHandler(statusUpdate);

                // push update through to make sure we get updated
                statusUpdate.sendEmptyMessage(Status.UPDATE_TRACK);
                bound = true;

            } catch (Throwable e) {
                Log.e(TAG, "onServiceConnected:" + e);
            }

        }

        public void onServiceDisconnected(ComponentName className) {
            // make sure we clean up our handler-specific status
            Log.w(TAG, "onServiceDisconnected");
            status.updateHandler(null);
            backend = null;
            status = null;
            bound = false;
        }
    };

    protected Handler statusUpdate = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // update gui based on severity
            switch (msg.what) {
            case Status.UPDATE_TRACK:

            case Status.UPDATE_COVER:
                // For now, do nothing

            case Status.UPDATE_STATE:
                nHelper.updateNotification(status.getTrackName(), status.getTrackArtist(), status.getPlayStatus());
                // if (Build.VERSION.SDK_INT >=
                // Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                // rcc.editMetadata(true)
                // .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,
                // status.getTrackArtist())
                // .putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
                // status.getTrackName())
                // .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
                // status.getTrackAlbum()).apply();
                // }
            }

        }
    };

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String action = intent.getAction();
        if (action != null) {

            if (action.equals(ACTION_END_SERVICE)) {
                Log.d(TAG, "Call to end NotificationService");
                stopSelf();
            } else if (action.equals(ACTION_NEXT_TRACK)) {
                Log.d(TAG, "NotificationService alerted to change track");
                if (session != null)
                    session.controlNext();
            } else if (action.equals(ACTION_PAUSE)) {
                Log.d(TAG, "NotificationService alerted to pause");
                if (session != null)
                    if (status.getPlayStatus() == Status.STATE_PAUSED)
                        session.controlPlay();
                    else
                        session.controlPause();
            }

        } else { // standard initialisation

            Log.d(TAG, "Initialising NotificationService");

        }

        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        nHelper = new NotificationHelper(this);

        // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        //
        // // Sets up the lockscreen stuff
        // AudioManager am = (AudioManager)
        // getSystemService(Context.AUDIO_SERVICE);
        // am.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
        // AudioManager.AUDIOFOCUS_GAIN);
        // ComponentName lockscreenRec = new ComponentName(this,
        // LockscreenReceiver.class);
        // am.registerMediaButtonEventReceiver(lockscreenRec);
        //
        // Intent broadcast = new
        // Intent(Intent.ACTION_MEDIA_BUTTON).setComponent(lockscreenRec);
        // PendingIntent broadPender = PendingIntent.getBroadcast(this, 0,
        // broadcast, PendingIntent.FLAG_UPDATE_CURRENT);
        //
        // rcc = new RemoteControlClient(broadPender);
        // rcc.setTransportControlFlags(RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
        // RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE);
        // am.registerRemoteControlClient(rcc);
        //
        // }

        bindService(new Intent(this, BackendService.class), connection, BIND_AUTO_CREATE);

        endServiceIntent = new Intent(this, NotificationService.class).setAction(ACTION_END_SERVICE);
        pauseIntent = new Intent(this, NotificationService.class).setAction(ACTION_PAUSE);
        nextTrackIntent = new Intent(this, NotificationService.class).setAction(ACTION_NEXT_TRACK);
        launchIntent = new Intent(this, ControlActivity.class);

        endServicePending = PendingIntent.getService(this, 0, endServiceIntent, PendingIntent.FLAG_ONE_SHOT);
        pausePending = PendingIntent.getService(this, 0, pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        nextTrackPending = PendingIntent.getService(this, 0, nextTrackIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        launchPending = PendingIntent.getActivity(this, 0, launchIntent, PendingIntent.FLAG_CANCEL_CURRENT);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.d(TAG, "Destroying NotificationService");
        nHelper.killNotification();
        if (bound) {
            backend = null;
            if (session != null)
                session.purgeNotificationStatus();
            session = null;
        }

        // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        //
        // // Kill the lockscreen stuff
        // AudioManager am = (AudioManager)
        // getSystemService(Context.AUDIO_SERVICE);
        // ComponentName lockscreenRec = new ComponentName(this,
        // LockscreenReceiver.class);
        // am.unregisterMediaButtonEventReceiver(lockscreenRec);
        // am.unregisterRemoteControlClient(rcc);
        // am.abandonAudioFocus(this);
        //
        // }

        unbindService(connection);

    }

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

    @Override
    public void onAudioFocusChange(int i) {
        // We don't actually care about this, but its required for lockscreen
        // controls
    }

    public class NotificationHelper {

        private final Context mContext;
        private final NotificationManager nManager;

        public final static int NOTIFICATION = 1;

        public NotificationHelper(Context context) {
            mContext = context;
            nManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        }

        public void killNotification() {
            nManager.cancel(NOTIFICATION);
        }

        @TargetApi(16)
        public void updateNotification(String track, String artist, int playState) {

            if (Helper.canUseApi(Build.VERSION_CODES.JELLY_BEAN)) {

                int iconSize = getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
                Bitmap cover = null;
                if (status.coverCache != null)
                    cover = Bitmap.createScaledBitmap(status.coverCache, iconSize, iconSize, false);
                // Use the new-style notifications. Because we can only have 2
                // actions, the disconnect action is performed by swiping
                // the notification away.
                Notification.Builder newBuilder = new Notification.Builder(mContext);
                newBuilder.setSmallIcon(R.drawable.ic_notify).setContentTitle(track).setContentText(artist)
                        .setDeleteIntent(endServicePending).setContentIntent(launchPending)
                        .addAction(
                                playState == Status.STATE_PAUSED ? R.drawable.ic_notify_play
                                        : R.drawable.ic_notify_pause,
                                mContext.getString(playState == Status.STATE_PAUSED ? R.string.notify_play
                                        : R.string.notify_pause),
                                pausePending)
                        .addAction(R.drawable.ic_notify_next, mContext.getString(R.string.notify_next),
                                nextTrackPending);
                if (cover != null)
                    newBuilder.setLargeIcon(cover);
                nManager.notify(NOTIFICATION, newBuilder.build());

            } else {

                NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
                RemoteViews notification = new RemoteViews(getPackageName(), R.layout.notification);
                notification.setTextViewText(R.id.notification_title, track);
                notification.setTextViewText(R.id.notification_text, artist);
                notification.setImageViewResource(R.id.notify_play,
                        playState == Status.STATE_PAUSED ? R.drawable.ic_notify_play : R.drawable.ic_notify_pause);
                notification.setOnClickPendingIntent(R.id.notify_play, pausePending);
                notification.setOnClickPendingIntent(R.id.notify_next, nextTrackPending);
                notification.setOnClickPendingIntent(R.id.notify_end, endServicePending);
                builder.setContent(notification).setOngoing(true).setContentIntent(launchPending)
                        .setSmallIcon(R.drawable.ic_notify);
                nManager.notify(NOTIFICATION, builder.getNotification());

            }
        }

    }

}