<commit_before>package com.mahali.gpslogger;

import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDeviceConnection;
import android.content.SharedPreferences;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.ToggleButton;

// Dropbox Includes
import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.exception.DropboxException;
import com.dropbox.client2.session.AppKeyPair;
import com.dropbox.client2.session.Session;

// usbSerialForAndroid Includes
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;


import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class MainActivity extends ActionBarActivity {

    private final String TAG = MainActivity.class.getSimpleName();
    private UsbManager mUsbManager;

    // The directory, in external storage, where mahali files will be stored
    private final String mahali_directory = "mahali";

    // The directory for the user's public documents directory.
    File dirFile;
    File sessFile;
    BufferedOutputStream bufOS = null;

    //for holding a reference to the file that we're currently reading from/writing to
    GPSSession mCurrentSession = null;

    // List of the previous sessions found by the app
    private ArrayList<GPSSession> sessionList = null;

    //Required dropbox fields. Get app key, app secret, and access type from App Console on dropbox website. Make sure the key matches the key in AndroidManifest.xml!
    private static final String APP_KEY = "<KEY>";
    private static final String APP_SECRET = "<KEY>";
    private static final Session.AccessType ACCESS_TYPE = Session.AccessType.APP_FOLDER;
    private DropboxAPI<AndroidAuthSession> mDBApi;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // TODO: pull a GPS recvr config file from dropbox

        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        // ------------------------------------------------
        //Setup for DropBox connection

        AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);

        //apparently the below is deprecated, but I got it directly from the tutorial at https://www.dropbox.com/developers/core/start/android
        AndroidAuthSession session = new AndroidAuthSession(appKeys, ACCESS_TYPE);
        mDBApi = new DropboxAPI<AndroidAuthSession>(session);

        // See if we already have information about a dropbox connection stored in the shared preferences file

        // returns the preferences file for "this" (i.e. MainActivity object). See http://developer.android.com/training/basics/data-storage/shared-preferences.html
        // SharedPreferences is a simple way to store basic key-value pairs. In this case we're using it to store dropbox configuration info
        SharedPreferences sharedPref = this.getPreferences(Context.MODE_PRIVATE);

        // get value of DB OAuth2AccessToken from shared preferences file. If it's not present, will take value "not_created"
        String OAuth2AccessToken = sharedPref.getString("OAuth2AccessToken","not_authenticated");

        Log.i(TAG,"OAuth2AccessToken at startup: "+OAuth2AccessToken);

        // if we do already have info about a DB session stored, set that up
        if (!OAuth2AccessToken.equals("not_authenticated")) {

            Log.i(TAG,"authenticated, at startup: ");
            //sets the OAuth2AccessToken, causing the mDBApi AndroidAuthSession object to be linked (and thus useable for dropbox transactions)
            mDBApi.getSession().setOAuth2AccessToken(OAuth2AccessToken);
            assert mDBApi.getSession().isLinked();
        }

        // ------------------------------------------------

        // TODO: make sure external storage is mounted/available see info here:
        // http://developer.android.com/training/basics/data-storage/files.html#WriteExternalStorage
        dirFile = new File(Environment.getExternalStorageDirectory(),mahali_directory);
        if (!dirFile.mkdirs()) {
            Log.i(TAG, "Directory not created - it already exists!");
        }

        Log.i(TAG, "Directory loaded: "+dirFile.exists());
        final ListView lv = (ListView) findViewById(R.id.sessionListView);

        updateSessionListView();

        // this method handles the selection of sessions from the list
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> a, View v, int position, long id) {
                Object o = lv.getItemAtPosition(position);
                GPSSession fullObject = (GPSSession)o;
                Log.i(TAG, "You have chosen: " + " " + fullObject.getFileName());

                //TODO: implement a selection menu in front of these options...

                // Try to upload the file to dropbox for the time being
                sendToDB(fullObject.getAbsolutePath());

                // Stub for deleting the file (only if upload successful?)
                deleteFile();
            }
        });

    }

    private void updateSessionListView() {
        final ListView lv = (ListView) findViewById(R.id.sessionListView);

        sessionList = loadGPSSessions();

        lv.setAdapter(new GPSSessionBaseAdaptor(this,sessionList));
    }

    public void startSession(View v) throws IOException {
        // Throws IOException when something goes wrong

        // Probe for devices
        final List<UsbSerialDriver> drivers =
                UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager);

        // Get the first port of the first driver
        // TODO: probably shouldn't be hard-coded, but multiple cables are unlikely
        try {
            sPort = drivers.get(0).getPorts().get(0);
        } catch (IndexOutOfBoundsException e) {
            Log.e(TAG,"Serial port not available");
            throw new IOException("Serial port not available");
        }

        // Open a connection
        UsbDeviceConnection connection = mUsbManager.openDevice(sPort.getDriver().getDevice());
        if (connection == null) {
            Log.e(TAG, "Error opening USB device");
            throw new IOException("Error opening USB device");
        }

        try {
            sPort.open(connection);
            // TODO: port configuration should almost certainly be configuration
            sPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
        } catch (IOException e) {
            Log.e(TAG, "Error setting up device: " + e.getMessage(), e);
            try {
                sPort.close();
            } catch (IOException e2) {
                // Ignore.
            }
            sPort = null;
            throw new IOException("Error configuring USB device:" + e.getMessage());
        }

        Log.i(TAG,"startSession: creating new GPS session");
        mCurrentSession = new GPSSession();
        sessFile = new File(dirFile.getPath(),mCurrentSession.getFileName());
        if (sessFile.exists()) {
            Log.e(TAG,"Session file already exists!");
            throw new IOException("Session file already exists: " + mCurrentSession.getFileName());
        }
        // Create file
        try {
            boolean fileCreated = sessFile.createNewFile();
            Log.i(TAG, "fileCreated: " + fileCreated);
        } catch (IOException e) {
            Log.e(TAG, "Failed to create new file: " + e.getMessage());
            throw new IOException("Failed to create new file: " + e.getMessage());
        }
        // Create output buffer
        try {
            bufOS = new BufferedOutputStream(new FileOutputStream(sessFile));
        } catch (FileNotFoundException e) {
            Log.e(TAG, "File not found exception: " + e.getMessage());
            throw new IOException("File not found exception during buffer creation");
        }

        // Start the IO manager thread
        startIoManager();
    }

    public void stopSession(View v) {
        stopIoManager();

        // Block until mSerialIoManager has finished writing and has shutdown?
        //mSerialIoManager.waitForStop();

        try {
            bufOS.flush();
            bufOS.close();
        } catch (IOException e) {
            Log.e(TAG, "stopSession failed to flush or close file" + e.getMessage());
        }

        updateSessionListView();
    }

    public void onConfigButtonClicked(View view) {

        Intent intent = new Intent(this, ConfigActivity.class);
        startActivity(intent);

    }

    public void onSessionToggleClicked(View view) {
        // Is the toggle on?
        boolean on = ((ToggleButton) view).isChecked();

        if (on) {
            // Handle toggle on
            Log.i(TAG,"Starting session.");
            try {
                startSession(view);
            } catch (IOException e) {
                // Failed to start session
                Toast.makeText(this, e.getLocalizedMessage(),Toast.LENGTH_LONG).show();
                ((ToggleButton) view).setChecked(false);
            }

        } else {
            // Handle toggle off
            Log.i(TAG, "Stopping session.");
            stopSession(view);
        }
    }

    /// Serial Port code
    private static UsbSerialPort sPort = null;
    private SerialInputOutputManager mSerialIoManager;
    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();

    // SerialInputOutputManager.Listen is a subclass of Runnable (this makes it's own thread!)
    private final SerialInputOutputManager.Listener mListener =
            new SerialInputOutputManager.Listener() {
                @Override
                public void onRunError(Exception e) {
                    Log.d(TAG, "Runner stopped.");
                }
                @Override
                public void onNewData(final byte[] data) {
                    // Write data to session file
                    try {
                        bufOS.write(data);
                    } catch (IOException e) {
                        Log.e(TAG, "mListener failed to write data to output buffer" + e.getMessage());
                    }

                    // Also push the bytes out to the log
                    //String decoded = new String(data);
                    //Log.d(TAG, '\n'+decoded+'\n');
                }
            };
    private void stopIoManager() {
        if (mSerialIoManager != null) {
            Log.i(TAG, "Stopping io manager ..");
            mSerialIoManager.stop();
            mSerialIoManager = null;
        }
    }
    private void startIoManager() {
        if (sPort != null) {
            Log.i(TAG, "Starting io manager ..");
            mSerialIoManager = new SerialInputOutputManager(sPort, mListener);
            mExecutor.submit(mSerialIoManager);

            SharedPreferences settings = getSharedPreferences(ConfigActivity.PREFS_NAME, 0);
            String curConfig = settings.getString("gpsConfig", ConfigActivity.DEFAULT_GPS_CONFIG);
            // TODO: do we need to add CR+LF chars here for the Novatel?
            Log.i(TAG,"Sending to GPS"+curConfig);

            // NOTE: writeAsync writes into a smallish buffer that we may want to make bigger,
            // otherwise an exception will be thrown.
            mSerialIoManager.writeAsync(curConfig.getBytes());
        }<commit_msg>Cleaned up TODOs<commit_after>package com.mahali.gpslogger;

import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDeviceConnection;
import android.content.SharedPreferences;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.ToggleButton;

// Dropbox Includes
import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.exception.DropboxException;
import com.dropbox.client2.session.AppKeyPair;
import com.dropbox.client2.session.Session;

// usbSerialForAndroid Includes
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;


import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class MainActivity extends ActionBarActivity {

    private final String TAG = MainActivity.class.getSimpleName();
    private UsbManager mUsbManager;

    // The directory, in external storage, where mahali files will be stored
    private final String mahali_directory = "mahali";

    // The directory for the user's public documents directory.
    File dirFile;
    File sessFile;
    BufferedOutputStream bufOS = null;

    //for holding a reference to the file that we're currently reading from/writing to
    GPSSession mCurrentSession = null;

    // List of the previous sessions found by the app
    private ArrayList<GPSSession> sessionList = null;

    //Required dropbox fields. Get app key, app secret, and access type from App Console on dropbox website. Make sure the key matches the key in AndroidManifest.xml!
    private static final String APP_KEY = "<KEY>";
    private static final String APP_SECRET = "<KEY>";
    private static final Session.AccessType ACCESS_TYPE = Session.AccessType.APP_FOLDER;
    private DropboxAPI<AndroidAuthSession> mDBApi;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // TODO: pull a GPS recvr config file from dropbox

        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        // ------------------------------------------------
        //Setup for DropBox connection

        AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);

        //apparently the below is deprecated, but I got it directly from the tutorial at https://www.dropbox.com/developers/core/start/android
        AndroidAuthSession session = new AndroidAuthSession(appKeys, ACCESS_TYPE);
        mDBApi = new DropboxAPI<AndroidAuthSession>(session);

        // See if we already have information about a dropbox connection stored in the shared preferences file

        // returns the preferences file for "this" (i.e. MainActivity object). See http://developer.android.com/training/basics/data-storage/shared-preferences.html
        // SharedPreferences is a simple way to store basic key-value pairs. In this case we're using it to store dropbox configuration info
        SharedPreferences sharedPref = this.getPreferences(Context.MODE_PRIVATE);

        // get value of DB OAuth2AccessToken from shared preferences file. If it's not present, will take value "not_created"
        String OAuth2AccessToken = sharedPref.getString("OAuth2AccessToken","not_authenticated");

        Log.i(TAG,"OAuth2AccessToken at startup: "+OAuth2AccessToken);

        // if we do already have info about a DB session stored, set that up
        if (!OAuth2AccessToken.equals("not_authenticated")) {

            Log.i(TAG,"authenticated, at startup: ");
            //sets the OAuth2AccessToken, causing the mDBApi AndroidAuthSession object to be linked (and thus useable for dropbox transactions)
            mDBApi.getSession().setOAuth2AccessToken(OAuth2AccessToken);
            assert mDBApi.getSession().isLinked();
        }

        // ------------------------------------------------

        // TODO: make sure external storage is mounted/available see info here:
        // http://developer.android.com/training/basics/data-storage/files.html#WriteExternalStorage
        dirFile = new File(Environment.getExternalStorageDirectory(),mahali_directory);
        if (!dirFile.mkdirs()) {
            Log.i(TAG, "Directory not created - it already exists!");
        }

        Log.i(TAG, "Directory loaded: "+dirFile.exists());
        final ListView lv = (ListView) findViewById(R.id.sessionListView);

        updateSessionListView();

        // this method handles the selection of sessions from the list
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> a, View v, int position, long id) {
                Object o = lv.getItemAtPosition(position);
                GPSSession fullObject = (GPSSession)o;
                Log.i(TAG, "You have chosen: " + " " + fullObject.getFileName());

                //TODO: implement a selection menu in front of these options...

                // Try to upload the file to dropbox for the time being
                sendToDB(fullObject.getAbsolutePath());

                // Stub for deleting the file (only if upload successful?)
                deleteFile();
            }
        });

    }

    private void updateSessionListView() {
        final ListView lv = (ListView) findViewById(R.id.sessionListView);

        sessionList = loadGPSSessions();

        lv.setAdapter(new GPSSessionBaseAdaptor(this,sessionList));
    }

    public void startSession(View v) throws IOException {
        // Throws IOException when something goes wrong

        // Probe for devices
        final List<UsbSerialDriver> drivers =
                UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager);

        // Get the first port of the first driver
        // TODO: probably shouldn't be hard-coded, but multiple cables are unlikely
        try {
            sPort = drivers.get(0).getPorts().get(0);
        } catch (IndexOutOfBoundsException e) {
            Log.e(TAG,"Serial port not available");
            throw new IOException("Serial port not available");
        }

        // Open a connection
        UsbDeviceConnection connection = mUsbManager.openDevice(sPort.getDriver().getDevice());
        if (connection == null) {
            Log.e(TAG, "Error opening USB device");
            throw new IOException("Error opening USB device");
        }

        try {
            sPort.open(connection);
            // TODO: port configuration should almost certainly be configuration
            sPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
        } catch (IOException e) {
            Log.e(TAG, "Error setting up device: " + e.getMessage(), e);
            try {
                sPort.close();
            } catch (IOException e2) {
                // Ignore.
            }
            sPort = null;
            throw new IOException("Error configuring USB device:" + e.getMessage());
        }

        Log.i(TAG,"startSession: creating new GPS session");
        mCurrentSession = new GPSSession();
        sessFile = new File(dirFile.getPath(),mCurrentSession.getFileName());
        if (sessFile.exists()) {
            Log.e(TAG,"Session file already exists!");
            throw new IOException("Session file already exists: " + mCurrentSession.getFileName());
        }
        // Create file
        try {
            boolean fileCreated = sessFile.createNewFile();
            Log.i(TAG, "fileCreated: " + fileCreated);
        } catch (IOException e) {
            Log.e(TAG, "Failed to create new file: " + e.getMessage());
            throw new IOException("Failed to create new file: " + e.getMessage());
        }
        // Create output buffer
        try {
            bufOS = new BufferedOutputStream(new FileOutputStream(sessFile));
        } catch (FileNotFoundException e) {
            Log.e(TAG, "File not found exception: " + e.getMessage());
            throw new IOException("File not found exception during buffer creation");
        }

        // Start the IO manager thread
        startIoManager();
    }

    public void stopSession(View v) {
        stopIoManager();

        // Block until mSerialIoManager has finished writing and has shutdown?
        //mSerialIoManager.waitForStop();

        try {
            bufOS.flush();
            bufOS.close();
        } catch (IOException e) {
            Log.e(TAG, "stopSession failed to flush or close file" + e.getMessage());
        }

        updateSessionListView();
    }

    public void onConfigButtonClicked(View view) {

        Intent intent = new Intent(this, ConfigActivity.class);
        startActivity(intent);

    }

    public void onSessionToggleClicked(View view) {
        // Is the toggle on?
        boolean on = ((ToggleButton) view).isChecked();

        if (on) {
            // Handle toggle on
            Log.i(TAG,"Starting session.");
            try {
                startSession(view);
            } catch (IOException e) {
                // Failed to start session
                Toast.makeText(this, e.getLocalizedMessage(),Toast.LENGTH_LONG).show();
                ((ToggleButton) view).setChecked(false);
            }

        } else {
            // Handle toggle off
            Log.i(TAG, "Stopping session.");
            stopSession(view);
        }
    }

    /// Serial Port code
    private static UsbSerialPort sPort = null;
    private SerialInputOutputManager mSerialIoManager;
    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();

    // SerialInputOutputManager.Listen is a subclass of Runnable (this makes it's own thread!)
    private final SerialInputOutputManager.Listener mListener =
            new SerialInputOutputManager.Listener() {
                @Override
                public void onRunError(Exception e) {
                    Log.d(TAG, "Runner stopped.");
                }
                @Override
                public void onNewData(final byte[] data) {
                    // Write data to session file
                    try {
                        bufOS.write(data);
                    } catch (IOException e) {
                        Log.e(TAG, "mListener failed to write data to output buffer" + e.getMessage());
                    }

                    // Also push the bytes out to the log
                    //String decoded = new String(data);
                    //Log.d(TAG, '\n'+decoded+'\n');
                }
            };
    private void stopIoManager() {
        if (mSerialIoManager != null) {
            Log.i(TAG, "Stopping io manager ..");
            mSerialIoManager.stop();
            mSerialIoManager = null;
        }
    }
    private void startIoManager() {
        if (sPort != null) {
            Log.i(TAG, "Starting io manager ..");
            mSerialIoManager = new SerialInputOutputManager(sPort, mListener);
            mExecutor.submit(mSerialIoManager);

            SharedPreferences settings = getSharedPreferences(ConfigActivity.PREFS_NAME, 0);
            String curConfig = settings.getString("gpsConfig", ConfigActivity.DEFAULT_GPS_CONFIG);
            Log.i(TAG,"Sending to GPS"+curConfig);

            // NOTE: writeAsync writes into a smallish buffer that we may want to make bigger,
            // otherwise an exception will be thrown.
            // TODO: do we need to add CR+LF chars here for the Novatel?
            mSerialIoManager.writeAsync(curConfig.getBytes());
        }
{'fraction_non_alphanumeric': 0.09886054904505089, 'fraction_numerical': 0.0021896922265925954, 'mean_word_length': 2.3788190163036034, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, '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': '2400021', 'n_tokens_mistral': 6443, 'n_tokens_neox': 6183, 'n_words': 1812}