org.pidome.client.phone.services.SystemService.java Source code

Java tutorial

Introduction

Here is the source code for org.pidome.client.phone.services.SystemService.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.pidome.client.phone.services;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.pidome.client.entities.EntityNotAvailableException;
import org.pidome.client.phone.dialogs.settings.LocalizationInfoInterface;
import org.pidome.client.phone.network.connectivity.AndroidBroadcastReceiver;
import org.pidome.client.phone.network.connectivity.ConnectionWatchdog;
import org.pidome.client.phone.utils.DeviceUtils;
import org.pidome.client.system.PCCCLientStatusListener;
import org.pidome.client.system.PCCClientEvent;
import org.pidome.client.system.PCCConnection;
import org.pidome.client.system.PCCConnectionEvent;
import org.pidome.client.system.PCCConnectionListener;
import org.pidome.client.system.PCCConnectionNameSpaceRPCListener;
import org.pidome.client.system.PCCSystem;
import org.pidome.pcl.backend.data.interfaces.network.NetworkAvailabilityEvent;
import org.pidome.pcl.backend.data.interfaces.network.NetworkAvailabilityEventListener;
import org.pidome.pcl.backend.data.interfaces.network.NetworkAvailabilityProvider;
import org.pidome.pcl.backend.data.interfaces.storage.LocalSettingsStorageInterface;
import org.pidome.pcl.data.parser.PCCEntityDataHandler;
import org.pidome.pcl.networking.connections.server.ServerConnection;

/**
 *
 * @author John
 */
public final class SystemService extends Service implements NetworkAvailabilityEventListener {

    /**
     * Registers running or not.
     */
    private static boolean running = false;

    /**
     * The pidome system which handles all the stuff.
     * Yes it really does handle EVERYTHING.
     */
    private PCCSystem system;

    /**
     * This service IBinder.
     * When you connect to this service it return the IBinder which can be used 
     * to get the PCC system, or this service specific components (GPS etc..).
     */
    private final BindExposer systemBinder = new BindExposer();

    private final ConnectionListener connectionListener = new ConnectionListener();
    private final ClientListener clientListener = new ClientListener();

    private final PCCConnectionNameSpaceRPCListener notificationListener = new NotificationListener();

    /**
     * Localization services like GPS and set home on home network.
     */
    private LocalizationService localizationService;

    /**
     * There is only one listener as this one put's the user in 
     */
    private ServiceConnectorListener signalHandler;

    /**
     * We want to know if the application is in the foreground or not.
     */
    private LifeCycleHandler lifeCycleHandler = new LifeCycleHandler();

    private ConnectionWatchdog watchdog;
    private AndroidPreferences prefs;

    private Context context;

    private static boolean isCalled = false;

    public SystemService() {
        super();
        isCalled = true;
    }

    public static boolean isCalled() {
        return isCalled;
    }

    @Override
    public final int onStartCommand(Intent intent, int flags, int startId) {
        context = getBaseContext();
        if (system == null) {
            getApplication().registerActivityLifecycleCallbacks(lifeCycleHandler);
            watchdog = new ConnectionWatchdog();
            watchdog.setInitialContext(context);
            prefs = new AndroidPreferences(getBaseContext());
            system = new PCCSystem(prefs, new AndroidSettings(getBaseContext()), ServerConnection.Profile.MOBILE,
                    watchdog);
            system.getConnection().setCustomBroadcastListener(new AndroidBroadcastReceiver(context));
            system.getConnection().addPCCConnectionListener(connectionListener);
            system.getConnection().addPCCConnectionNameSpaceListener("NotificationService", notificationListener);
            system.getClient().addListener(clientListener);

            localizationService = new LocalizationService(this, prefs);

            LocalSettingsStorageInterface settings = system.getLocalSettings();
            if (settings.getStringSetting("user.login", "").equals("")
                    || settings.getStringSetting("user.userinfo", "").equals("")) {
                settings.setStringSetting("user.login", generateDeviceId(context));
                settings.setStringSetting("user.userinfo", DeviceUtils.getDeviceName());
                try {
                    settings.storeSettings();
                } catch (IOException ex) {
                    Logger.getLogger(SystemService.class.getName()).log(Level.SEVERE,
                            "Problem storing initial settings", ex);
                }
            }
            Log.i("SystemService", "PiDome SystemService started");
            running = true;
            serviceLogin();
        }
        return START_STICKY;
    }

    private void serviceLogin() {
        new Thread() {
            @Override
            public final void run() {
                System.out.println("Currently logged in: " + system.getClient().isloggedIn()
                        + ", in connection progress: " + system.getConnection().inConnectionProgress()
                        + ", in login progress: " + system.getClient().inLoginProgress());
                if (!system.getConnection().inConnectionProgress() && !system.getClient().inLoginProgress()
                        && !system.getClient().isloggedIn()) {
                    if (system.getConnection().hasInitialManualConnectData()) {
                        system.getConnection().startInitialConnection();
                    } else {
                        system.getConnection().startSearch();
                    }
                }
                System.out.println("Adding system service to network watchdog");
                watchdog.addEventListener(SystemService.this);
            }
        }.start();
    }

    /**
     * When bound to this service it returns the local binder.
     * This local binder guarantees access to this service components
     * and the PCC system.
     * @param arg0
     * @return 
     */
    @Override
    public BindExposer onBind(Intent arg0) {
        return systemBinder;
    }

    /**
     * Returns if a service is running.
     * @return true when running, false when not.
     */
    public static boolean isServiceRunning() {
        return running;
    }

    @Override
    public void handleNetworkAvailabilityEvent(NetworkAvailabilityEvent nae) {
        System.out.println("Received network availbility event: " + nae.getEventType());
        if (nae.getEventType().equals(NetworkAvailabilityProvider.Status.NETWORKAVAILABLE)) {
            serviceLogin();
        }
    }

    /**
     * Used to retrieve the 
     */
    public final class BindExposer extends Binder implements SystemBinder {
        @Override
        public final PCCSystem getPCCSystem() {
            return system;
        }

        @Override
        public final void setSignalHandler(ServiceConnectorListener receiver) {
            signalHandler = receiver;
        }

        @Override
        public final LifeCycleHandler getLifeCycleHandler() {
            return lifeCycleHandler;
        }

        @Override
        public final LocalizationInfoInterface getPresenceServiceSettings() {
            return localizationService;
        }
    }

    protected final PCCSystem getSystem() {
        return this.system;
    }

    /**
     * Generate an unique id for this device.
     * @param context
     * @return 
     */
    private String generateDeviceId(Context context) {
        final String macAddr, androidId;
        WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiInf = wifiMan.getConnectionInfo();
        macAddr = wifiInf.getMacAddress();
        androidId = "" + android.provider.Settings.Secure.getString(context.getContentResolver(),
                android.provider.Settings.Secure.ANDROID_ID);
        UUID deviceUuid;
        try {
            deviceUuid = new UUID(androidId.hashCode(), macAddr.hashCode());
        } catch (NullPointerException ex) {
            deviceUuid = new UUID(androidId.hashCode(), androidId.hashCode());
        }
        return deviceUuid.toString();
    }

    private class ConnectionListener implements PCCConnectionListener {

        /**
         * Handles connection events.
         *
         * @param status The connection status event.
         * @param event Event is null when no server information is available.
         * This is mainly when for example server search fails.
         */
        @Override
        public final void handlePCCConnectionEvent(PCCConnection.PCCConnectionStatus status,
                PCCConnectionEvent event) {
            Log.i("SystemService", "Received connection event: " + status.toString());
            switch (status) {
            case CONNECTED:
                system.getClient().login();
                break;
            case DISCONNECTED:
                system.getClient().logout();
                if (signalHandler != null) {
                    signalHandler.handleUserLoggedOut();
                }
                break;
            }
        }
    }

    private class ClientListener implements PCCCLientStatusListener {

        /**
         * Handles events that have to do with the client. These events have to
         * do with plain client stuff.
         *
         * @param event The PCCClientEvent to handle.
         */
        @Override
        public final void handlePCCClientEvent(PCCClientEvent event) {
            Log.i("SystemService", "Received client event: " + event.getStatus().toString());
            switch (event.getStatus()) {
            case LOGGED_IN:
                try {
                    system.getLocalSettings().storeSettings();
                } catch (IOException ex) {
                    Logger.getLogger(SystemService.class.getName()).log(Level.SEVERE,
                            "Could not store connection settings", ex);
                }
                break;
            case INIT_DONE:
                if (signalHandler != null) {
                    signalHandler.handleUserLoggedIn();
                }
                localizationService.restartGPSExecutor();
                setHome();
                break;
            }
        }
    }

    private void setHome() {
        if (prefs != null) {
            if (prefs.getBoolPreference("wifiConnectHomeEnabled", false)) {
                ConnectivityManager connManager = (ConnectivityManager) getSystemService(
                        Context.CONNECTIVITY_SERVICE);
                NetworkInfo networkInfo = connManager.getActiveNetworkInfo();
                if (networkInfo.isConnected() && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                    final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
                    final WifiInfo connectionInfo = wifiManager.getConnectionInfo();
                    if (connectionInfo != null) {
                        String SSID = connectionInfo.getSSID();
                        String BSSID = connectionInfo.getBSSID();
                        if (SSID != null && BSSID != null) {
                            if (SSID.equals(prefs.getStringPreference("wifiConnectSSID",
                                    java.util.UUID.randomUUID().toString()))
                                    && BSSID.equals(prefs.getStringPreference("wifiConnectBSSID",
                                            java.util.UUID.randomUUID().toString()))) {
                                if (this.system != null) {
                                    try {
                                        system.getClient().getEntities().getPresenceService().setPresence(1);
                                    } catch (EntityNotAvailableException ex) {
                                        Logger.getLogger(SystemService.class.getName()).log(Level.SEVERE, null, ex);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private class NotificationListener implements PCCConnectionNameSpaceRPCListener {

        @Override
        public void handleRPCCommandByBroadcast(PCCEntityDataHandler pccedh) {
            if (pccedh.getMethod().equals("sendNotification")) {
                handleNotificationMessage(pccedh.getParameters());
            }
        }

        private void handleNotificationMessage(final Map<String, Object> params) {
            if (lifeCycleHandler.inForeground()) {

                Handler handler = new Handler(context.getMainLooper());

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast toast = Toast.makeText(context, new StringBuilder((String) params.get("subject"))
                                .append(": ").append(params.get("message")), Toast.LENGTH_LONG);
                        toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 40);
                        toast.show();
                    }
                });

            } else {

                Intent resultIntent = new Intent(SystemService.this, javafxports.android.FXActivity.class);
                PendingIntent pIntent = PendingIntent.getActivity(SystemService.this, 0, resultIntent, 0);
                /*
                Uri smallIcon = Uri.parse("/images/logo/notification-small.png");
                try {
                InputStream inputStream = getContentResolver().openInputStream(smallIcon);
                Drawable yourDrawable = Drawable.createFromStream(inputStream, smallIcon.toString() );
                } catch (FileNotFoundException e) {
                ///
                }
                */
                NotificationCompat.Builder notification = new NotificationCompat.Builder(SystemService.this)
                        .setOnlyAlertOnce(true)
                        .setSmallIcon(SystemService.this.getResources().getIdentifier("notificationsmall",
                                "drawable", SystemService.this.getPackageName()))
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                                getResources().getIdentifier("notification", "drawable",
                                        SystemService.this.getPackageName())))
                        .setContentTitle((String) params.get("subject"))
                        .setContentText((String) params.get("message")).setContentIntent(pIntent)
                        .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                        .setAutoCancel(true);

                NotificationManager mNotificationManager = (NotificationManager) SystemService.this
                        .getSystemService(Context.NOTIFICATION_SERVICE);
                /// Set an id so notification will override, it is possible when an user has a lot of notifications the list could stack up.
                /// A todo would be to create notifications which are distinguised by categories. But this is being to be discussed.
                int mId = 12345;
                mNotificationManager.notify(mId, notification.build());
            }
        }

        @Override
        public void handleRPCCommandByResult(PCCEntityDataHandler pccedh) {
            /// Not used
        }

    }

}