<commit_before>package com.platypus.android.server;

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.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.ServerValue;
import com.platypus.crw.CrwSecurityManager;
import com.platypus.crw.data.Utm;
import com.platypus.crw.data.UtmPose;
import com.platypus.crw.udp.UdpVehicleService;

import org.jscience.geography.coordinates.LatLong;
import org.jscience.geography.coordinates.UTM;
import org.jscience.geography.coordinates.crs.ReferenceEllipsoid;

import java.util.concurrent.atomic.AtomicBoolean;

import javax.measure.unit.NonSI;
import javax.measure.unit.SI;

import robotutils.Pose3D;
import robotutils.Quaternion;

/**
 * Android Service to register sensor and Amarino handlers for Android.s
 * Contains a RosVehicleServer and a VehicleServer object.
 *
 * @author pkv
 * @author kshaurya
 */
public class VehicleService extends Service {
    public static final String START_ACTION = "com.platypus.android.server.SERVICE_START";
    public static final String STOP_ACTION = "com.platypus.android.server.SERVICE_STOP";
    private static final int SERVICE_ID = 11312;
    private static final String TAG = VehicleService.class.getSimpleName();
    final int GPS_UPDATE_RATE = 200; // in milliseconds

    // Variable storing the current started/stopped status of the service.
    protected AtomicBoolean isRunning = new AtomicBoolean(false);

    // Variable storing the Firebase instance ID associated with this particular run.
    protected String mFirebaseId = null;

    // Reference to vehicle logfile.
    private VehicleLogger mLogger;

    // Reference to vehicle controller;
    private Controller mController;

    // Objects implementing actual functionality
    private VehicleServerImpl _vehicleServerImpl;
    private UdpVehicleService _udpService;
    private final Object mUdpLock = new Object();

    // Lock objects that prevent the phone from sleeping
    private WakeLock _wakeLock = null;
    private WifiLock _wifiLock = null;
    // global variable to reference rotation vector values
    private float[] rotationMatrix = new float[9];
    private final SensorEventListener rotationVectorListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                // TODO Auto-generated method stub
                SensorManager.getRotationMatrixFromVector(rotationMatrix,
                        event.values);
                double yaw = Math.atan2(-rotationMatrix[5], -rotationMatrix[2]);

                if (_vehicleServerImpl != null) {
                    _vehicleServerImpl.filter.compassUpdate(yaw,
                            System.currentTimeMillis());
//					logger.info("COMPASS: " + yaw);
                }
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
    /**
     * UPDATE: 7/03/12 - Handles gyro updates by calling the appropriate update.
     */
    private final SensorEventListener gyroListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            // TODO Auto-generated method stub
            /*
             * Convert phone coordinates to world coordinates. use magnetometer
			 * and accelerometer to get orientation Simple rotation is 90�
			 * clockwise about positive y axis. Thus, transformation is: // / M[
			 * 0] M[ 1] M[ 2] \ / values[0] \ = gyroValues[0] // | M[ 3] M[ 4]
			 * M[ 5] | | values[1] | = gyroValues[1] // \ M[ 6] M[ 7] M[ 8] / \
			 * values[2] / = gyroValues[2] //
			 */
            float[] gyroValues = new float[3];
            gyroValues[0] = rotationMatrix[0] * event.values[0]
                    + rotationMatrix[1] * event.values[1] + rotationMatrix[2]
                    * event.values[2];
            gyroValues[1] = rotationMatrix[3] * event.values[0]
                    + rotationMatrix[4] * event.values[1] + rotationMatrix[5]
                    * event.values[2];
            gyroValues[2] = rotationMatrix[6] * event.values[0]
                    + rotationMatrix[7] * event.values[1] + rotationMatrix[8]
                    * event.values[2];

            if (_vehicleServerImpl != null)
                _vehicleServerImpl.setPhoneGyro(gyroValues);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
    /**
     * Handles GPS updates by calling the appropriate update.
     */
    private LocationListener locationListener = new LocationListener() {
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onProviderDisabled(String provider) {
        }

        public void onLocationChanged(Location location) {

            // Convert from lat/long to UTM coordinates
            UTM utmLoc = UTM.latLongToUtm(
                    LatLong.valueOf(location.getLatitude(),
                            location.getLongitude(), NonSI.DEGREE_ANGLE),
                    ReferenceEllipsoid.WGS84);

            // Convert to UTM data structure
            Pose3D pose = new Pose3D(utmLoc.eastingValue(SI.METER),
                    utmLoc.northingValue(SI.METER), (location.hasAltitude()
                    ? location.getAltitude()
                    : 0.0), (location.hasBearing()
                    ? Quaternion.fromEulerAngles(0.0, 0.0,
                    (90.0 - location.getBearing()) * Math.PI
                            / 180.0)
                    : Quaternion.fromEulerAngles(0, 0, 0)));
            Utm origin = new Utm(utmLoc.longitudeZone(),
                    utmLoc.latitudeZone() > 'O');
            UtmPose utm = new UtmPose(pose, origin);

            // Apply update using filter object
            if (_vehicleServerImpl != null) {
                _vehicleServerImpl.filter.gpsUpdate(utm, location.getTime());
//				logger.info("GPS: " + utmLoc + ", " + utmLoc.longitudeZone()
//						+ utmLoc.latitudeZone() + ", " + location.getAltitude()
//						+ ", " + location.getBearing());
            }
        }
    };

    /**
     * A shared preference listener that changes settings on the implementation if
     * settings are changed.
     */
    private SharedPreferences.OnSharedPreferenceChangeListener mPreferenceListener =
            new SharedPreferences.OnSharedPreferenceChangeListener() {
                @Override
                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
                    if ("pref_server_port".equals(key))
                        startOrUpdateUdpServer();
                }
            };

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

        // Disable all DNS lookups (safer for private/ad-hoc networks)
        CrwSecurityManager.loadIfDNSIsSlow();

        // Disable strict-mode (TODO: remove this and use handlers)
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
                .permitAll().build();
        StrictMode.setThreadPolicy(policy);

        // Register a shared preference listener to listen for updates.
        PreferenceManager.getDefaultSharedPreferences(this)
                .registerOnSharedPreferenceChangeListener(mPreferenceListener);

        // Get reference to vehicle controller service.
        mController = new Controller(this);

        // TODO: optimize this to allocate resources up here and handle multiple
        // start commands
    }

    /**
     * Access method to get underlying implementation of server functionality.
     *
     * @return An interface allowing high-level control of the boat.
     */
    public VehicleServerImpl getServer() {
        return _vehicleServerImpl;
    }

    /**
     * Starts UDP server, either at startup or when the UDP port is changed.
     * If a server instance already exists, it is shutdown first.
     */
    private void startOrUpdateUdpServer() {
        // Start up UDP vehicle service in the background
        new Thread(new Runnable() {
            @Override
            public void run() {
                final SharedPreferences preferences =
                        PreferenceManager.getDefaultSharedPreferences(VehicleService.this);

                synchronized (mUdpLock) {
                    if (_udpService != null)
                        _udpService.shutdown();

                    try {
                        final int port = Integer.parseInt(preferences.getString("pref_server_port", "11411"));
                        _udpService = new UdpVehicleService(port, _vehicleServerImpl);
                        Log.i(TAG, "UdpVehicleService launched on port " + port + ".");
                    } catch (Exception e) {
                        Log.e(TAG, "UdpVehicleService failed to launch", e);
                        sendNotification("UdpVehicleService failed: " + e.getMessage());
                        stopSelf();
                    }
                }
            }
        }).start();
    }

    /**
     * Main service initialization: called whenever a request is made to start
     * the Airboat service.
     * <p/><commit_msg>Added changes to allow app to accept port numbers with spaces that can be trimmed off.<commit_after>package com.platypus.android.server;

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.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.ServerValue;
import com.platypus.crw.CrwSecurityManager;
import com.platypus.crw.data.Utm;
import com.platypus.crw.data.UtmPose;
import com.platypus.crw.udp.UdpVehicleService;

import org.jscience.geography.coordinates.LatLong;
import org.jscience.geography.coordinates.UTM;
import org.jscience.geography.coordinates.crs.ReferenceEllipsoid;

import java.util.concurrent.atomic.AtomicBoolean;

import javax.measure.unit.NonSI;
import javax.measure.unit.SI;

import robotutils.Pose3D;
import robotutils.Quaternion;

/**
 * Android Service to register sensor and Amarino handlers for Android.s
 * Contains a RosVehicleServer and a VehicleServer object.
 *
 * @author pkv
 * @author kshaurya
 */
public class VehicleService extends Service {
    public static final String START_ACTION = "com.platypus.android.server.SERVICE_START";
    public static final String STOP_ACTION = "com.platypus.android.server.SERVICE_STOP";
    private static final int SERVICE_ID = 11312;
    private static final String TAG = VehicleService.class.getSimpleName();
    final int GPS_UPDATE_RATE = 200; // in milliseconds

    // Variable storing the current started/stopped status of the service.
    protected AtomicBoolean isRunning = new AtomicBoolean(false);

    // Variable storing the Firebase instance ID associated with this particular run.
    protected String mFirebaseId = null;

    // Reference to vehicle logfile.
    private VehicleLogger mLogger;

    // Reference to vehicle controller;
    private Controller mController;

    // Objects implementing actual functionality
    private VehicleServerImpl _vehicleServerImpl;
    private UdpVehicleService _udpService;
    private final Object mUdpLock = new Object();

    // Lock objects that prevent the phone from sleeping
    private WakeLock _wakeLock = null;
    private WifiLock _wifiLock = null;
    // global variable to reference rotation vector values
    private float[] rotationMatrix = new float[9];
    private final SensorEventListener rotationVectorListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                // TODO Auto-generated method stub
                SensorManager.getRotationMatrixFromVector(rotationMatrix,
                        event.values);
                double yaw = Math.atan2(-rotationMatrix[5], -rotationMatrix[2]);

                if (_vehicleServerImpl != null) {
                    _vehicleServerImpl.filter.compassUpdate(yaw,
                            System.currentTimeMillis());
//					logger.info("COMPASS: " + yaw);
                }
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
    /**
     * UPDATE: 7/03/12 - Handles gyro updates by calling the appropriate update.
     */
    private final SensorEventListener gyroListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            // TODO Auto-generated method stub
            /*
             * Convert phone coordinates to world coordinates. use magnetometer
			 * and accelerometer to get orientation Simple rotation is 90�
			 * clockwise about positive y axis. Thus, transformation is: // / M[
			 * 0] M[ 1] M[ 2] \ / values[0] \ = gyroValues[0] // | M[ 3] M[ 4]
			 * M[ 5] | | values[1] | = gyroValues[1] // \ M[ 6] M[ 7] M[ 8] / \
			 * values[2] / = gyroValues[2] //
			 */
            float[] gyroValues = new float[3];
            gyroValues[0] = rotationMatrix[0] * event.values[0]
                    + rotationMatrix[1] * event.values[1] + rotationMatrix[2]
                    * event.values[2];
            gyroValues[1] = rotationMatrix[3] * event.values[0]
                    + rotationMatrix[4] * event.values[1] + rotationMatrix[5]
                    * event.values[2];
            gyroValues[2] = rotationMatrix[6] * event.values[0]
                    + rotationMatrix[7] * event.values[1] + rotationMatrix[8]
                    * event.values[2];

            if (_vehicleServerImpl != null)
                _vehicleServerImpl.setPhoneGyro(gyroValues);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
    /**
     * Handles GPS updates by calling the appropriate update.
     */
    private LocationListener locationListener = new LocationListener() {
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onProviderDisabled(String provider) {
        }

        public void onLocationChanged(Location location) {

            // Convert from lat/long to UTM coordinates
            UTM utmLoc = UTM.latLongToUtm(
                    LatLong.valueOf(location.getLatitude(),
                            location.getLongitude(), NonSI.DEGREE_ANGLE),
                    ReferenceEllipsoid.WGS84);

            // Convert to UTM data structure
            Pose3D pose = new Pose3D(utmLoc.eastingValue(SI.METER),
                    utmLoc.northingValue(SI.METER), (location.hasAltitude()
                    ? location.getAltitude()
                    : 0.0), (location.hasBearing()
                    ? Quaternion.fromEulerAngles(0.0, 0.0,
                    (90.0 - location.getBearing()) * Math.PI
                            / 180.0)
                    : Quaternion.fromEulerAngles(0, 0, 0)));
            Utm origin = new Utm(utmLoc.longitudeZone(),
                    utmLoc.latitudeZone() > 'O');
            UtmPose utm = new UtmPose(pose, origin);

            // Apply update using filter object
            if (_vehicleServerImpl != null) {
                _vehicleServerImpl.filter.gpsUpdate(utm, location.getTime());
//				logger.info("GPS: " + utmLoc + ", " + utmLoc.longitudeZone()
//						+ utmLoc.latitudeZone() + ", " + location.getAltitude()
//						+ ", " + location.getBearing());
            }
        }
    };

    /**
     * A shared preference listener that changes settings on the implementation if
     * settings are changed.
     */
    private SharedPreferences.OnSharedPreferenceChangeListener mPreferenceListener =
            new SharedPreferences.OnSharedPreferenceChangeListener() {
                @Override
                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
                    if ("pref_server_port".equals(key))
                        startOrUpdateUdpServer();
                }
            };

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

        // Disable all DNS lookups (safer for private/ad-hoc networks)
        CrwSecurityManager.loadIfDNSIsSlow();

        // Disable strict-mode (TODO: remove this and use handlers)
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
                .permitAll().build();
        StrictMode.setThreadPolicy(policy);

        // Register a shared preference listener to listen for updates.
        PreferenceManager.getDefaultSharedPreferences(this)
                .registerOnSharedPreferenceChangeListener(mPreferenceListener);

        // Get reference to vehicle controller service.
        mController = new Controller(this);

        // TODO: optimize this to allocate resources up here and handle multiple
        // start commands
    }

    /**
     * Access method to get underlying implementation of server functionality.
     *
     * @return An interface allowing high-level control of the boat.
     */
    public VehicleServerImpl getServer() {
        return _vehicleServerImpl;
    }

    /**
     * Starts UDP server, either at startup or when the UDP port is changed.
     * If a server instance already exists, it is shutdown first.
     */
    private void startOrUpdateUdpServer() {
        // Start up UDP vehicle service in the background
        new Thread(new Runnable() {
            @Override
            public void run() {
                final SharedPreferences preferences =
                        PreferenceManager.getDefaultSharedPreferences(VehicleService.this);

                synchronized (mUdpLock) {
                    if (_udpService != null)
                        _udpService.shutdown();

                    try {
                        final int port = Integer.parseInt(preferences.getString("pref_server_port", "11411").trim());
                        _udpService = new UdpVehicleService(port, _vehicleServerImpl);
                        Log.i(TAG, "UdpVehicleService launched on port " + port + ".");
                    } catch (Exception e) {
                        Log.e(TAG, "UdpVehicleService failed to launch", e);
                        sendNotification("UdpVehicleService failed: " + e.getMessage());
                        stopSelf();
                    }
                }
            }
        }).start();
    }

    /**
     * Main service initialization: called whenever a request is made to start
     * the Airboat service.
     * <p/>
{'fraction_non_alphanumeric': 0.08969082033119556, 'fraction_numerical': 0.007944864554417536, 'mean_word_length': 2.349631292080795, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5217052', 'n_tokens_mistral': 5721, 'n_tokens_neox': 5407, 'n_words': 1386}