Android Open Source - Boxee-Thumb-Remote Server Remote Service






From Project

Back to project page Boxee-Thumb-Remote.

License

The source code is released under:

Apache License

If you think the Android project Boxee-Thumb-Remote listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.evendanan.android.thumbremote.service;
//  ww  w  .  ja v a2  s.c  om
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
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.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import com.jakewharton.notificationcompat2.NotificationCompat2;
import com.jakewharton.notificationcompat2.NotificationCompat2.Builder;

import net.evendanan.android.thumbremote.MediaStateListener;
import net.evendanan.android.thumbremote.R;
import net.evendanan.android.thumbremote.RemoteApplication;
import net.evendanan.android.thumbremote.ServerAddress;
import net.evendanan.android.thumbremote.ServerConnector;
import net.evendanan.android.thumbremote.ServerState;
import net.evendanan.android.thumbremote.ServerStatePoller;
import net.evendanan.android.thumbremote.UiView;
import net.evendanan.android.thumbremote.boxee.BoxeeConnector;
import net.evendanan.android.thumbremote.boxee.BoxeeDiscovererThread;
import net.evendanan.android.thumbremote.network.HttpRequest;
import net.evendanan.android.thumbremote.service.DoServerRemoteAction.DoServerRemoteActionListener;
import net.evendanan.android.thumbremote.ui.RemoteUiActivity;

import java.util.ArrayList;

public class ServerRemoteService extends Service implements BoxeeDiscovererThread.Receiver,
        DoServerRemoteActionListener {

    public class LocalBinder extends Binder {
        public ServerRemoteService getService() {
            return ServerRemoteService.this;
        }
    }

    private static final String TAG = "ServerRemoteService";

    // public static final String KEY_DATA_TITLE = "KEY_DATA_TITLE";

    private static final int NOTIFICATION_PLAYING_ID = 1;

    private NotificationManager mNotificationManager;

    private IBinder mBinder;

    private final BroadcastReceiver mCallReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null)
            {
                String newState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
                if (newState != null && newState.equals(TelephonyManager.EXTRA_STATE_RINGING))
                {
                    onPhone();
                }
            }
        }
    };

    private final BroadcastReceiver mNetworkChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            onNetworkChanged();
        }
    };

    private Handler mHandler;

    private UiView mUi;
    private ServerConnector mRemote;
    private BoxeeDiscovererThread mServerDiscoverer;
    private ServerAddress mServerAddress = null;
    private ServerStatePoller mStatePoller = null;

    private State mState;
    /*
     * private final ServiceConnection mKeepAliveConnection = new
     * ServiceConnection() {
     * @Override public void onServiceDisconnected(ComponentName name) { }
     * @Override public void onServiceConnected(ComponentName name, IBinder
     * service) { } };
     */
    private final Runnable mCheckServerStateASAP = new Runnable() {
        @Override
        public void run() {
            mStatePoller.checkStateNow();
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mHandler = new Handler();
        mState = State.DISCOVERYING;
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mBinder = new LocalBinder();
        mRemote = new BoxeeConnector();
        mRemote.setUiView(new MediaStateListener() {

            @Override
            public void onMediaPlayingStateChanged(ServerState serverState) {
                Log.d(TAG, "Media playing state has changed to "+(serverState.isMediaActive()? "active":"inactive"));
                if (serverState.isMediaActive())
                {
                    showPlayingNotification(serverState.getMediaTitle(),
                            serverState.getMediaPoster(),
                            serverState.isMediaPlaying());
                }
                else
                {
                    stopServiceIfMediaIsNotActive();
                    cancelPlayingNotification();
                }
                if (mUi != null)
                    mUi.onMediaPlayingStateChanged(serverState);
            }

            @Override
            public void onMediaPlayingProgressChanged(ServerState serverState) {
                if (mUi != null)
                    mUi.onMediaPlayingProgressChanged(serverState);
            }

            @Override
            public void onMediaMetadataChanged(ServerState serverState) {
                if (serverState.isMediaActive())
                {
                    showPlayingNotification(serverState.getMediaTitle(),
                            serverState.getMediaPoster(),
                            serverState.isMediaPlaying());
                }
                if (mUi != null)
                    mUi.onMediaMetadataChanged(serverState);
            }

            @Override
            public void onKeyboardStateChanged(ServerState serverState) {
                if (mUi != null)
                    mUi.onKeyboardStateChanged(serverState);
            }
        });

        createStatePoller();

        IntentFilter callFilter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
        registerReceiver(mCallReceiver, callFilter);
        IntentFilter networkFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(mNetworkChangedReceiver, networkFilter);

        setServer();
        /*
         * //and I want my own reference. bindService(new Intent(this,
         * ServerRemoteService.class), mKeepAliveConnection,
         * Context.BIND_AUTO_CREATE);
         */
    }

    private void createStatePoller() {
        if (mStatePoller != null)
            mStatePoller.stop();
        mStatePoller = new ServerStatePoller(mRemote, getApplicationContext());
        mStatePoller.poll();
    }

    /*
     * @Override public int onStartCommand(Intent intent, int flags, int
     * startId) { //We want this service to continue running until it is
     * explicitly // stopped, so return sticky. return START_STICKY; }
     */
    private void stopServiceIfMediaIsNotActive()
    {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (mUi == null && !mRemote.isMediaActive())
                {
                    Log.d(TAG,
                            "stopServiceIfNothingIsPlaying determined that there is no running media. Killing self.");
                    /*
                     * try { unbindService(mKeepAliveConnection); }
                     * catch(Exception e) { Log.w(TAG,
                     * "Caught an exception while unbinding from self. nm."
                     * +e.getMessage()); }
                     */
                    stopSelf();
                }
            }
        }, 500);
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "Thumb Remote Service is now at destroy...");
        cancelPlayingNotification();
        unregisterReceiver(mCallReceiver);
        unregisterReceiver(mNetworkChangedReceiver);

        mStatePoller.stop();

        setServiceState(State.DEAD);

        super.onDestroy();
    }

    public State getServiceState() {
        return mState;
    }

    private void onPhone() {
        if (RemoteApplication.getConfig().getPauseOnCall())
        {
            Log.i(TAG, "Got a phone call! Pausing if running...");
            if (mRemote.isMediaPlaying())
            {
                Log.d(TAG, "Pausing media, since it is runing.");
                remoteFlipPlayPause();
            }
        }
        else
        {
            Log.i(TAG, "Got a phone call! But auto-pause is disabled.");
        }
    }

    private void onNetworkChanged()
    {
        Log.i(TAG, "Got network! Trying to reconnect...");
        createStatePoller();
        setServer();
    }

    private void setServer() {
        new AsyncTask<Void, Void, Void>()
        {
            @Override
            protected Void doInBackground(Void... params) {
                if (RemoteApplication.getConfig().isManuallySetServer()) {
                    mServerAddress = RemoteApplication.getConfig().constructServer();
                    mRemote.setServer(mServerAddress);
                    setServiceState(State.IDLE);
                }
                else {
                    if (mServerDiscoverer != null)
                        mServerDiscoverer.setReceiver(null);

                    setServiceState(State.DISCOVERYING);
                    mServerDiscoverer = new BoxeeDiscovererThread(ServerRemoteService.this,
                            ServerRemoteService.this);
                    mServerDiscoverer.start();
                }
                return null;
            }
        }.execute();
    }
    
    private NotificationCompat2.Builder getSimple(String title, boolean isPlaying, PendingIntent pendingIntent) {
        return new NotificationCompat2.Builder(getApplicationContext())
            .setSmallIcon(isPlaying ? R.drawable.notification_playing
                    : R.drawable.notification_paused)
            .setTicker(getString(isPlaying ? R.string.server_is_playing
                    : R.string.server_is_paused, title))
            .setContentTitle(getText(R.string.app_name))
            .setContentText(getString(isPlaying ? R.string.server_is_playing
                    : R.string.server_is_paused, title))
            .setContentIntent(pendingIntent)
            .setPriority(NotificationCompat2.PRIORITY_MIN)
            .setOngoing(true);
      }

    private void showPlayingNotification(String title, Bitmap poster, boolean isPlaying)
    {
        Intent notificationIntent = new Intent(getApplicationContext(), RemoteUiActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);

        Builder builder = getSimple(title, isPlaying, contentIntent);

        Notification notification;
        if (poster != null) {
            notification = new NotificationCompat2.BigPictureStyle(builder)
                .bigPicture(poster)
                .build();
        } else {
            notification = builder.build();
        }

        //notification.flags |= Notification.FLAG_ONGOING_EVENT;
        //notification.flags |= Notification.FLAG_NO_CLEAR;
        // notifying
        mNotificationManager.notify(NOTIFICATION_PLAYING_ID, notification);
    }

    private void cancelPlayingNotification()
    {
        mNotificationManager.cancel(NOTIFICATION_PLAYING_ID);
    }

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

    public void setUiView(UiView ui) {
        mUi = ui;
        setServiceState(getServiceState());
        if (ui != null)
        {
            mStatePoller.comeBackToForeground();
            mUi.hello(mRemote);
        }
        else
        {
            mStatePoller.moveToBackground();
            stopServiceIfMediaIsNotActive();
        }
    }

    /*
     * @Override public boolean onUnbind(Intent intent) { Log.d(TAG,
     * "onUnbind"); super.onUnbind(intent); return false; }
     */
    public String getServerName()
    {
        return mServerAddress != null ? mServerAddress.name() : null;
    }

    @Override
    public void addAnnouncedServers(ArrayList<ServerAddress> servers) {
        // This condition shouldn't ever be true.
        if (RemoteApplication.getConfig().isManuallySetServer()) {
            Log.d(TAG, "Skipping announced servers. Set manually");
            setServiceState(State.IDLE);
            return;
        }

        String preferred = RemoteApplication.getConfig().getServerName();

        for (int k = 0; k < servers.size(); ++k) {
            final ServerAddress server = servers.get(k);
            if (server.name().equals(preferred) || TextUtils.isEmpty(preferred)) {
                if (!server.valid()) {
                    if (mUi != null)
                        mUi.showMessage(
                                String.format("Found '%s' but looks broken", server.name()), 3000);
                    continue;
                } else {
                    mServerAddress = server;
                    mRemote.setServer(mServerAddress);

                    setServiceState(State.IDLE);

                    if (server.authRequired())
                    {
                        if (!HttpRequest.hasCredentials())
                        {
                            setServiceState(State.ERROR_NO_PASSWORD);
                        }
                    }
                    return;
                }
            }
        }

        mServerAddress = null;

        setServiceState(State.ERROR_NO_SERVER);
    }

    void setServiceState(State newState) {
        mState = newState;
        if (mUi != null)
            mUi.onServerConnectionStateChanged(mState);
    }

    public void forceStop() {
        Log.i(TAG, "Force Stop was called!");
        // unbindService(mKeepAliveConnection);
        stopSelf();
    }

    @Override
    public void onRemoteActionError(String userMessage, int errorCode, boolean longDelayMessage) {
        if (errorCode == 401)
        {
            setServiceState(State.ERROR_NO_PASSWORD);
        }
        else if (!TextUtils.isEmpty(userMessage) && mUi != null)
            mUi.showMessage(userMessage, longDelayMessage ? 2500 : 1250);
    }

    @Override
    public void onRemoteActionSuccess(String successMessage, boolean longDelayMessage) {
        if (!TextUtils.isEmpty(successMessage) && mUi != null)
            mUi.showMessage(successMessage, longDelayMessage ? 2500 : 500);

        mHandler.removeCallbacks(mCheckServerStateASAP);
        mHandler.postDelayed(mCheckServerStateASAP, 100);
    }

    public static int hmsToSeconds(String hms) {
        if (TextUtils.isEmpty(hms))
            return 0;

        try
        {
            int seconds = 0;
            String[] times = hms.split(":");

            // seconds
            seconds += Integer.parseInt(times[times.length - 1]);

            // minutes
            if (times.length >= 2)
                seconds += Integer.parseInt(times[times.length - 2]) * 60;

            // hours
            if (times.length >= 3)
                seconds += Integer.parseInt(times[times.length - 3]) * 3600;

            return seconds;
        } catch (Exception e)
        {
            return 0;
        }
    }

    /* CONTROLLER interface */

    public void remoteFlipPlayPause() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.flipPlayPause();
            }
        }.execute();
    }

    public void remoteBack() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.back();
            }
        }.execute();
    }

    public void remoteSeekRelative(final double newSeekPosition) {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.seekRelative(newSeekPosition);
            }
        }.execute();
    }

    public void remoteSeekTo(final double newSeekPosition) {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.seekTo(newSeekPosition);
            }
        }.execute();
    }

    public void remoteSeekOffset(final double seekOffset)
    {
        final int duration = hmsToSeconds(mRemote.getMediaTotalTime());
        if (duration > 0)
        {
            final double newSeekPosition = seekOffset * 100f / duration;
            remoteSeekRelative(newSeekPosition);
        }
    }

    public void remoteStop() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.stop();
            }
        }.execute();
    }

    public void remoteLeft() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.left();
            }
        }.execute();
    }

    public void remoteRight() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.right();
            }
        }.execute();
    }

    public void remoteUp() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.up();
            }
        }.execute();
    }

    public void remoteDown() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.down();
            }
        }.execute();
    }

    public void remoteSelect() {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.select();
            }
        }.execute();
    }

    public void remoteKeypress(final char unicodeChar) {
        new DoServerRemoteAction(this, false) {
            @Override
            protected void callRemoteFunction() throws Exception {
                mRemote.keypress(unicodeChar);
            }
        }.execute();
    }

    public void remoteVolumeOffset(final int volumeOffset) {
        new DoServerRemoteAction(this, false) {
            private int mNewVolume = 0;

            @Override
            protected void callRemoteFunction() throws Exception {
                int volume = mRemote.getVolume();
                mNewVolume = Math.max(0, Math.min(100, volume + volumeOffset));
                mRemote.setVolume(mNewVolume);
            }

            protected String getSuccessMessage() {
                return getString(R.string.new_volume_toast, mNewVolume);
            }
        }.execute();
    }

    public void remoteRescanForServers() {
        setServer();
    }

}




Java Source Code List

.HttpClientBlocking.java
com.example.android.actionbarcompat.ActionBarHelperBase.java
com.example.android.actionbarcompat.ActionBarHelperCompat.java
com.example.android.actionbarcompat.ActionBarHelperHoneycomb.java
com.example.android.actionbarcompat.ActionBarHelperICS.java
com.example.android.actionbarcompat.SimpleMenuItem.java
com.example.android.actionbarcompat.SimpleMenu.java
iharder.base64.Base64.java
net.evendanan.android.thumbremote.MediaStateListener.java
net.evendanan.android.thumbremote.RemoteApplication.java
net.evendanan.android.thumbremote.ServerAddress.java
net.evendanan.android.thumbremote.ServerConnectionListener.java
net.evendanan.android.thumbremote.ServerConnector.java
net.evendanan.android.thumbremote.ServerRemote.java
net.evendanan.android.thumbremote.ServerStatePoller.java
net.evendanan.android.thumbremote.ServerStateUrlsProvider.java
net.evendanan.android.thumbremote.ServerState.java
net.evendanan.android.thumbremote.Settings.java
net.evendanan.android.thumbremote.ShakeListener.java
net.evendanan.android.thumbremote.UiView.java
net.evendanan.android.thumbremote.boxee.BoxeeConnector.java
net.evendanan.android.thumbremote.boxee.BoxeeDiscovererThread.java
net.evendanan.android.thumbremote.network.HttpBlocking.java
net.evendanan.android.thumbremote.network.HttpRequest.java
net.evendanan.android.thumbremote.network.Response.java
net.evendanan.android.thumbremote.network.ReusableHttpClientBlocking.java
net.evendanan.android.thumbremote.service.DoServerRemoteAction.java
net.evendanan.android.thumbremote.service.ServerRemoteService.java
net.evendanan.android.thumbremote.service.State.java
net.evendanan.android.thumbremote.ui.FixedViewFlipper.java
net.evendanan.android.thumbremote.ui.FragmentAlertDialogSupport.java
net.evendanan.android.thumbremote.ui.HelpUiActivity.java
net.evendanan.android.thumbremote.ui.RemoteUiActivity.java
net.evendanan.android.thumbremote.ui.SettingsActivity.java