Android Open Source - simple-dash Telemetry Connector






From Project

Back to project page simple-dash.

License

The source code is released under:

MIT License

If you think the Android project simple-dash 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 org.bmdtech.simpledash.telemetry;
/*from   w ww. ja v a  2s . c  o  m*/
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.bmdtech.simpledash.event.ConnectivityEvent;
import org.bmdtech.simpledash.event.TelemetryEvent;
import org.joda.time.DateTime;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static org.bmdtech.simpledash.event.ConnectivityEvent.Type.CLOSED;
import static org.bmdtech.simpledash.event.ConnectivityEvent.Type.ERROR;
import static org.bmdtech.simpledash.event.ConnectivityEvent.Type.OPEN;
import static org.bmdtech.simpledash.event.ConnectivityEvent.Type.RETRY;
import static org.bmdtech.simpledash.event.TelemetryEvent.CURRENT_GEAR_FIELD;
import static org.bmdtech.simpledash.event.TelemetryEvent.RPM_FIELD;
import static org.bmdtech.simpledash.event.TelemetryEvent.SPEED_FIELD;
import static org.bmdtech.simpledash.event.TelemetryEvent.TELEMETRY_EVENT_TYPE;
import static org.bmdtech.simpledash.event.TelemetryEvent.TYPE_FIELD;
import static org.bmdtech.simpledash.utils.Logging.logEvent;

public final class TelemetryConnector {

    private static final String TAG = "TCP";

    private final Handler androidMessageHandler;
    private final ObjectMapper objectMapper;

    private TelemetryClient telemetryClient;

    public TelemetryConnector(Handler androidMessageHandler) {
        this.androidMessageHandler = androidMessageHandler;
        this.objectMapper = new ObjectMapper();
    }

    public void connect(String ipAddress, String port) {
        this.telemetryClient = new TelemetryClient(ipAddress, port);
        Log.d(TAG, "Connecting client");
        telemetryClient.connect();
    }

    public void disconnect() {
        if (telemetryClient != null) {
            Log.d(TAG, "Disconnecting client");
            telemetryClient.disconnect();
        }
    }

    private class TelemetryClient {

        private static final int CONNECTION_TIMEOUT = 1000;
        private static final int RESCHEDULE_CONNECTION_DELAY = 5000;

        private final ScheduledExecutorService executorService;

        private final String ipAddress;
        private final String port;

        private final Socket clientSocket;

        private Thread readerThread;

        private TelemetryClient(String ipAddress, String port) {
            this.ipAddress = ipAddress;
            this.port = port;
            this.clientSocket = new Socket();
            this.executorService = Executors.newSingleThreadScheduledExecutor();
        }

        public void connect() {
            readerThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        clientSocket.connect(new InetSocketAddress(ipAddress, Integer.valueOf(port)), CONNECTION_TIMEOUT);
                        readData();
                    } catch (Exception e) {
                        rescheduleConnection(ERROR);
                    }
                }

                private void readData() {
                    BufferedReader inFromServer = null;

                    try {
                        inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                        while (true) {
                            if (clientSocket.isConnected() && !clientSocket.isClosed()) {
                                String message = inFromServer.readLine();
                                if (message == null) {
                                    Log.e(TAG, "Message is null, rescheduling connection");
                                    rescheduleConnection(CLOSED);
                                    break;
                                }

                                handleMessage(message);
                            } else {
                                break;
                            }
                        }
                    } catch (Exception e) {
                        Log.e(TAG, "Error while reading data from server.", e);
                        rescheduleConnection(CLOSED);
                    } finally {
                        try {
                            if (inFromServer != null) {
                                inFromServer.close();
                            }
                        } catch (Exception e) {
                            // ignore
                        }
                    }
                }
            });

            readerThread.start();
        }

        public void disconnect() {
            executorService.shutdownNow();

            try {
                clientSocket.close();
            } catch (Exception e) {
                // ignore, system is shutting down and the client could have been already disconnected
            }
        }

        private void handleMessage(String message) {
            try {
                TypeReference<HashMap<String, String>> mapTypeReference = new TypeReference<HashMap<String, String>>() {
                };
                Map<String, String> jsonValueMap = objectMapper.readValue(message, mapTypeReference);

                if (jsonValueMap.containsKey(TYPE_FIELD)) {
                    switch (jsonValueMap.get(TYPE_FIELD)) {
                        case TELEMETRY_EVENT_TYPE:
                            TelemetryEvent event = new TelemetryEvent(new DateTime(Long.valueOf(jsonValueMap.get(TelemetryEvent.EVENT_TIMESTAMP_FIELD))),
                                    Integer.valueOf(jsonValueMap.get(CURRENT_GEAR_FIELD)),
                                    Float.valueOf(jsonValueMap.get(SPEED_FIELD)),
                                    Float.valueOf(jsonValueMap.get(RPM_FIELD)));

                            logEvent(TAG, event);
                            Message.obtain(androidMessageHandler, 0, event).sendToTarget();
                            break;
                        case "ConnectionClosed":
                            rescheduleConnection(CLOSED);
                            break;
                        case "ConnectionOpen":
                            handleConnectionOpen();
                            break;
                        default:
                            Log.w(TAG, String.format("Received event with type <%s> which is currently unrecognized", jsonValueMap.get(TYPE_FIELD)));
                            break;
                    }
                } else {
                    Log.w(TAG, String.format("Received JSON message <%s>, but it did not have a type identifier", message));
                }

            } catch (Exception e) {
                Log.e(TAG, String.format("Error while trying to parse message <%s>. Not a valid JSON?", message), e);
            }
        }

        private void handleConnectionOpen() {
            Log.d(TAG, "Server connection successful!");
            Message.obtain(androidMessageHandler, 0, new ConnectivityEvent(OPEN)).sendToTarget();
        }

        private void rescheduleConnection(ConnectivityEvent.Type type) {
            // for some reason Android does not garbage collect the WebSocket client class
            // after an activity has been paused -> resumed. This can result in a "rogue"
            // thread that sill receives events and updates the UI

            if (!executorService.isTerminated()) {
                Message.obtain(androidMessageHandler, 0, new ConnectivityEvent(type)).sendToTarget();
                executorService.schedule(new ReconnectionTask(ipAddress, port), RESCHEDULE_CONNECTION_DELAY, TimeUnit.MILLISECONDS);
            }
        }
    }

    private class ReconnectionTask implements Runnable {

        private final String ipAddress;
        private final String port;

        private ReconnectionTask(String ipAddress, String port) {
            this.ipAddress = ipAddress;
            this.port = port;
        }

        @Override
        public void run() {
            Message.obtain(androidMessageHandler, 0, new ConnectivityEvent(RETRY)).sendToTarget();
            disconnect();
            connect(ipAddress, port);
        }
    }
}




Java Source Code List

org.bmdtech.simpledash.SimpleDashApp.java
org.bmdtech.simpledash.activity.MainActivity.java
org.bmdtech.simpledash.activity.SettingsActivity.java
org.bmdtech.simpledash.activity.UpdatableActivity.java
org.bmdtech.simpledash.event.BaseEvent.java
org.bmdtech.simpledash.event.ConnectivityEvent.java
org.bmdtech.simpledash.event.TelemetryEvent.java
org.bmdtech.simpledash.handler.AndroidMessageHandler.java
org.bmdtech.simpledash.telemetry.TelemetryConnector.java
org.bmdtech.simpledash.utils.Logging.java
org.bmdtech.simpledash.utils.SpeedUnit.java
org.bmdtech.simpledash.utils.Validators.java