csic.ceab.movelab.beepath.Util.java Source code

Java tutorial

Introduction

Here is the source code for csic.ceab.movelab.beepath.Util.java

Source

/*
 * This file incorporates code from Space Mapper, which is subject 
 * to the following terms: 
 *
 *       Space Mapper
 *       Copyright (C) 2012, 2013 John R.B. Palmer
 *       Contact: jrpalmer@princeton.edu
 *
 *       Space Mapper is free software: you can redistribute it and/or modify 
 *       it under the terms of the GNU General Public License as published by 
 *       the Free Software Foundation, either version 3 of the License, or (at 
 *       your option) any later version.
 * 
 *       Space Mapper is distributed in the hope that it will be useful, but 
 *       WITHOUT ANY WARRANTY; without even the implied warranty of 
 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 *       See the GNU General Public License for more details.
 * 
 *       You should have received a copy of the GNU General Public License along 
 *       with Space Mapper.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * This file also incorporates code written by Chang Y. Chung and Necati E. Ozgencil 
 * for the Human Mobility Project, which is subject to the following terms: 
 * 
 *       Copyright (C) 2010, 2011 Human Mobility Project
 *
 *      Permission is hereby granted, free of charge, to any person obtaining 
 *      a copy of this software and associated documentation files (the
 *      "Software"), to deal in the Software without restriction, including
 *      without limitation the rights to use, copy, modify, merge, publish, 
 *      distribute, sublicense, and/or sell copies of the Software, and to
 *      permit persons to whom the Software is furnished to do so, subject to
 *      the following conditions:
 *
 *      The above copyright notice and this permission notice shall be included
 *      in all copies or substantial portions of the Software.
 *
 *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *      EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *      IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 *      CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *      TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 *      SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 
 */

package csic.ceab.movelab.beepath;

import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.FileLock;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Various static fields and methods used in the application, some taken from
 * Human Mobility Project.
 * 
 * @author Chang Y. Chung
 * @author Necati E. Ozgencil
 * @author John R.B. Palmer
 */
public class Util {

    public static final boolean testMode = false;

    public static String getPassword() {

        if (testMode) {
            return "1234";
        } else {
            return PropertyHolder.getPassword();
        }

    }

    public static String getUserId() {

        if (testMode) {
            return "john";
        } else {
            return PropertyHolder.getUserId();
        }

    }

    public static final String FILEPREFIX_UPLOAD_ERRORS = "UE";

    public static final String DIRECTORY_JSON_UPLOAD_ERROR_QUEUE_FIXES = "json_upload_error_queue_fixes";

    public static final String DIRECTORY_JSON_UPLOAD_ERROR_QUEUE_SENSORS = "json_upload_error_queue_sensors";

    public static final String DIRECTORY_JSON_UPLOADQUEUE = "json_upload_queue";

    public static final String DIRECTORY_JSON_FIXARRAY_UPLOADQUEUE = "json_fixarray_upload_queue";

    public static final boolean USE_SENSORS = true;

    public final static String MESSAGE_STOP_FIXGET = ".STOP_FIXGET";
    public final static String MESSAGE_LONGSTOP_FIXGET = ".LONGSTOP_FIXGET";
    public final static String MESSAGE_SCHEDULE = ".SCHEDULE_SERVICE";
    public final static String MESSAGE_UNSCHEDULE = ".UNSCHEDULE_SERVICE";
    public final static String MESSAGE_FIX_RECORDED = ".NEW_FIX_RECORDED";
    public final static String MESSAGE_FIX_UPLOADED = ".NEW_FIX_UPLOADED";
    public final static String MESSAGE_UPLOADS_NEEDED = ".UPLOADS_NEEDED";
    public final static String MESSAGE_UPLOADS_NOT_NEEDED = ".UPLOADS_NOT_NEEDED";

    public static String createInternalMessage(String msg, Context context) {
        return context.getResources().getString(R.string.internal_message_id) + msg;
    }

    public final static int TRACKING_NOTIFICATION = 0;

    public static String[] ALPHA_NUMERIC_DIGITS = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C",
            "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
            "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
            "t", "u", "v", "w", "x", "y", "z" };

    public static boolean privateMode = false;

    public static int EXTRARUNS = 4;

    public static boolean flushGPSFlag = false;

    public static boolean redrawMap = false;

    public static long xTime = 1 * 60 * 60 * 1000;
    /**
     * Default value for the interval between location fixes. In milliseconds.
     */
    public static final long ALARM_INTERVAL = 15000; // 15 second

    public static final long UPLOAD_INTERVAL = 1000 * 60 * 2; // 2 minutes

    /**
     * Server URLs for uploads.
     */

    public static final String URL_FIXES_JSON = "http://161.116.80.73:8000/api/v1/update/";
    public static final String URL_SENSOR_JSON = "http://161.116.80.73:8000/api/v1/sensor_update/";

    /**
     * Extension to append to all files saved for uploading.
     */
    public static final String EXTENSION = ".dat";

    /**
     * Maximum length of time to run location listeners during each fix attempt.
     * In milliseconds.
     */
    public static final long LISTENER_WINDOW = 5 * 1000;

    public static final long LONG_LISTENER_WINDOW = 60 * 1000;

    public final static long SECONDS = 1000;
    public final static long MINUTES = SECONDS * 60;
    public final static long HOURS = MINUTES * 60;
    public final static long DAYS = HOURS * 24;
    public final static long WEEKS = DAYS * 7;

    // Min average comfortable walking speed (cm/s) from Bohannon 1997,
    // http://ageing.oxfordjournals.org/content/26/1/15.full.pdf+html
    public static int WALKING_SPEED = 127;

    // Use the distance one would cover at walking speed capped at 80 (which is
    // standard city block size)
    public static int getMinDist(Context context) {

        PropertyHolder.init(context);

        int fixIntervalSeconds = (int) ((int) PropertyHolder.getAlarmInterval() / (int) SECONDS);

        int expectedWalkingDistanceMeters = (int) (WALKING_SPEED * fixIntervalSeconds) / 100;
        return Math.min(MIN_DIST, expectedWalkingDistanceMeters);
    }

    public static int MIN_DIST = 80;

    /**
     * Value at which a GPS location will be preferred to a network location,
     * even if the network location is listed with a higher accuracy.
     */
    public static final float MIN_GPS_ACCURACY = 50;

    /**
     * Value at which a location will be used, and both listeners stopped even
     * if not yet at the end of the listener window.
     * 
     * SETTING THIS FROM 15 TO 5 FOR FESTA
     */
    public static final float OPT_ACCURACY = 5;

    /**
     * Value at which a location will be used, and both listeners stopped even
     * if not yet at the end of the listener window - for long runs.
     */
    public static final float OPT_ACCURACY_LONGRUNS = 50;

    /**
     * Minimum accuracy necessary for location to be used.
     */
    public static final float MIN_ACCURACY = 500;

    /**
     * Default time for storing user data when user selects to do so. In days.
     */
    public static final int STORAGE_DAYS = 7;

    /**
     * Dummy variable indicating whether application is currently trying to
     * upload data.
     */
    public static boolean uploading = false;

    /**
     * Default value for figuring out when alarm manager started counting. For
     * use with the display timer in the DriverMapActivity activity.
     */
    public static long countingFrom = 0;

    public static long lastFixStartedAt = 0;

    /**
     * counter for how many fixes have been missed in a row.
     */
    public static int missedFixes = 0;

    /**
     * temp holder for info on latest fix.
     */
    public static String lastFixTimeStamp = null;

    /**
     * temp holder for info on latest fix.
     */
    public static long lastFixTime = 0;

    /**
     * temp holder for info on latest fix.
     */
    public static double lastFixLat = 0;

    /**
     * temp holder for info on latest fix.
     */
    public static double lastFixLon = 0;

    /**
     * holder for current value of the listener window
     */
    public static long listenerTimer = LISTENER_WINDOW;

    /**
     * Surrounds the given string in quotation marks. Taken from Human Mobility
     * Project code written by Chang Y. Chung and Necati E. Ozgencil.
     * 
     * @param str
     *            The string to be encased in quotation marks.
     * @return The given string trimmed and encased in quotation marks.
     */
    public static String enquote(String str) {
        final String dq = "\"";
        final String ddq = dq + dq;
        StringBuilder sb = new StringBuilder("");
        sb.append(dq);
        sb.append((str.trim()).replace(dq, ddq));
        sb.append(dq);
        return sb.toString();
    }

    /**
     * Formats the given coordinate and converts to String form. Taken from
     * Human Mobility Project code written by Chang Y. Chung and Necati E.
     * Ozgencil.
     * 
     * @param coord
     *            The coordinate value to be formatted.
     * @return The properly formatted coordinate in String form
     */
    public static String fmtCoord(double coord) {
        return String.format("%1$11.6f", coord);
    }

    /**
     * Formats the given time and converts to String form. Taken from Human
     * Mobility Project code written by Chang Y. Chung and Necati E. Ozgencil.
     * 
     * @param time
     *            The time value to be formatted.
     * @return The properly formatted time value in String form
     */
    public static String iso8601(long time) {
        return String.format("%1$tFT%1$tT", time);
    }

    /**
     * Formats the given time and converts to String form. Taken from Human
     * Mobility Project code written by Chang Y. Chung and Necati E. Ozgencil.
     * 
     * @param datetime
     *            The Date object, whose long time value must be formatted.
     * @return The properly formatted time value of the Date Object in String
     *         form
     */
    public static String iso8601(Date datetime) {
        return iso8601(datetime.getTime());
    }

    /**
     * Formats a date object for displaying it to the user.
     * 
     * @param date
     *            The Date object to be formatted.
     * @return The properly formatted time and date as a String.
     * 
     */
    public static String userDate(Date date) {
        SimpleDateFormat s = new SimpleDateFormat("HH:mm dd/MM/yyyy");
        String format = s.format(date);
        return format;
    }

    /**
     * Formats the location time, given as a long in milliseconds, for use in
     * filenames.
     * 
     * @param locationTime
     *            The long value to be formatted.
     * @return The properly formatted time and date as a String.
     */
    public static String fileNameDate(long locationTime) {
        Date date = new Date(locationTime);
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        String format = s.format(date);
        return format;
    }

    /**
     * Gets the current system time in milliseconds. Taken from Human Mobility
     * Project code written by Chang Y. Chung and Necati E. Ozgencil.
     * 
     * @return The current system time in milliseconds.
     */
    public static String now() {
        return iso8601(System.currentTimeMillis());
    }

    /**
     * Displays a brief message on the phone screen. Taken from Human Mobility
     * Project code written by Chang Y. Chung and Necati E. Ozgencil.
     * 
     * @param context
     *            Interface to application environment
     * @param msg
     *            The message to be displayed to the user
     */
    public static void toast(Context context, String msg) {

        TextView tv = new TextView(context);
        tv.setText(msg);
        Drawable bknd = context.getResources().getDrawable(R.drawable.white_border);
        tv.setBackgroundDrawable(bknd);
        tv.setPadding(20, 20, 20, 20);
        tv.setTextSize(20);

        Toast t = new Toast(context);
        t.setDuration(Toast.LENGTH_LONG);
        t.setView(tv);
        t.show();
    }

    /**
     * Checks if the phone has an internet connection.
     * 
     * @param context
     *            The application context.
     * @return True if phone has a connection; false if not.
     */
    public static boolean isOnline(Context context) {

        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo = cm.getActiveNetworkInfo();
        if (netInfo != null && netInfo.isConnected()) {
            return true;
        }
        return false;
    }

    public static boolean uploadFile(byte[] bytes, String filename, String uploadurl) {

        HttpURLConnection conn = null;
        DataOutputStream dos = null;
        // DataInputStream inStream = null;

        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";

        int bytesRead, bytesAvailable, bufferSize;
        byte[] buffer;
        int maxBufferSize = 64 * 1024; // old value 1024*1024
        ByteArrayInputStream byteArrayInputStream = null;
        boolean isSuccess = true;
        try {
            // ------------------ CLIENT REQUEST

            byteArrayInputStream = new ByteArrayInputStream(bytes);

            // open a URL connection to the Servlet
            URL url = new URL(uploadurl);
            // Open a HTTP connection to the URL
            conn = (HttpURLConnection) url.openConnection();
            // Allow Inputs
            conn.setDoInput(true);
            // Allow Outputs
            conn.setDoOutput(true);
            // Don't use a cached copy.
            conn.setUseCaches(false);
            // set timeout
            conn.setConnectTimeout(60000);
            conn.setReadTimeout(60000);
            // Use a post method.
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

            dos = new DataOutputStream(conn.getOutputStream());
            dos.writeBytes(twoHyphens + boundary + lineEnd);
            dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + filename + "\""
                    + lineEnd);
            dos.writeBytes(lineEnd);

            // create a buffer of maximum size
            bytesAvailable = byteArrayInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];

            // read file and write it into form...
            bytesRead = byteArrayInputStream.read(buffer, 0, bufferSize);
            while (bytesRead > 0) {
                dos.write(buffer, 0, bufferSize);
                bytesAvailable = byteArrayInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                bytesRead = byteArrayInputStream.read(buffer, 0, bufferSize);
            }

            // send multipart form data necesssary after file data...
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

            // close streams
            // Log.e(TAG,"UploadService Runnable:File is written");
            // fileInputStream.close();
            // dos.flush();
            // dos.close();
        } catch (Exception e) {
            // Log.e(TAG, "UploadService Runnable:Client Request error", e);
            isSuccess = false;
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                    // Log.e(TAG, "exception" + e);

                }
            }
            if (byteArrayInputStream != null) {
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    // Log.e(TAG, "exception" + e);

                }
            }

        }

        // ------------------ read the SERVER RESPONSE
        try {

            if (conn.getResponseCode() != 200) {
                isSuccess = false;
            }
        } catch (IOException e) {
            // Log.e(TAG, "Connection error", e);
            isSuccess = false;
        }

        return isSuccess;
    }

    public static boolean uploadJSONArray(Context context, JSONArray jsonArray, String uploadurl) {

        String response = "";

        try {

            // Create a new HttpClient and Post Header
            HttpPatch httppatch = new HttpPatch(uploadurl);

            HttpParams myParams = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(myParams, 10000);
            HttpConnectionParams.setSoTimeout(myParams, 60000);
            HttpConnectionParams.setTcpNoDelay(myParams, true);

            httppatch.setHeader("Content-type", "application/json");

            String auth = "-u john:1234";

            httppatch.setHeader("Authorization", auth);

            HttpClient httpclient = new DefaultHttpClient();

            ByteArrayEntity bae = new ByteArrayEntity(jsonArray.toString().getBytes("UTF8"));

            // StringEntity se = new StringEntity(jsonArray.toString(),
            // HTTP.UTF_8);
            // se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
            // "application/json"));
            bae.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
            httppatch.setEntity(bae);

            // Execute HTTP Post Request

            ResponseHandler<String> responseHandler = new BasicResponseHandler();

            response = httpclient.execute(httppatch, responseHandler);

        } catch (ClientProtocolException e) {

        } catch (IOException e) {
        }

        if (response.contains("SUCCESS")) {
            Log.i("SERVER RESPONSE", response);
            return true;
        } else {
            Log.i("SERVER RESPONSE", response);
            return false;
        }

    }

    /**
     * Saves a byte array to the internal storage directory.
     * 
     * @param context
     *            The application context.
     * @param filename
     *            The file name to use.
     * @param bytes
     *            The byte array to be saved.
     */
    public static void saveJSON(Context context, String dir, String fileprefix, String inputString) {
        // String TAG = "Util.saveFile";
        FileOutputStream fos = null;
        FileLock lock = null;

        try {
            byte[] bytes = inputString.getBytes("UTF-8");

            File directory = new File(context.getFilesDir().getAbsolutePath(), dir);

            directory.mkdirs();

            File target = new File(directory, fileprefix + System.currentTimeMillis() + ".txt");
            fos = new FileOutputStream(target);

            lock = fos.getChannel().lock();

            fos.write(bytes);

        } catch (IOException e) {
            // logging exception but doing nothing
            // Log.e(TAG, "Exception " + e);
        } finally {

            if (lock != null) {

                try {
                    lock.release();
                } catch (Exception e) {

                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    // logging exception but doing nothing
                    // Log.e(TAG, "Exception " + e);

                }
            }

        }

    }

    public static String readJSON(File file) {
        int bytesRead, bytesAvailable, bufferSize;
        byte[] buffer;
        int maxBufferSize = 64 * 1024; // old value 1024*1024
        FileInputStream fileInputStream = null;
        String result = "";

        try {
            fileInputStream = new FileInputStream(file);

            bytesAvailable = fileInputStream.available();

            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];

            // read file and write it into form...
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            while (bytesRead > 0) {
                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            }
            result = new String(buffer, "UTF-8");

        } catch (FileNotFoundException e) {

        }

        catch (IOException e) {
        }

        finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {

                }
            }

        }

        return result;

    }

    public File[] listJSONFiles(Context context) {
        String dir = context.getFilesDir().getAbsolutePath();
        File directory = new File(dir, DIRECTORY_JSON_UPLOADQUEUE);
        File[] files = directory.listFiles();
        return files;
    }

    public static boolean patch2DjangoJSONArray(Context context, JSONArray jsonArray, String uploadurl,
            String username, String password) {

        String response = "";

        try {

            JSONObject obj = new JSONObject();
            obj.put("objects", jsonArray);
            JSONArray emptyarray = new JSONArray();
            obj.put("deleted_objects", emptyarray);

            CredentialsProvider credProvider = new BasicCredentialsProvider();
            credProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
                    new UsernamePasswordCredentials(username, password));

            // Create a new HttpClient and Post Header
            HttpPatch httppatch = new HttpPatch(uploadurl);

            HttpParams myParams = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(myParams, 10000);
            HttpConnectionParams.setSoTimeout(myParams, 60000);
            HttpConnectionParams.setTcpNoDelay(myParams, true);

            httppatch.setHeader("Content-type", "application/json");

            DefaultHttpClient httpclient = new DefaultHttpClient();

            httpclient.setCredentialsProvider(credProvider);
            // ByteArrayEntity bae = new ByteArrayEntity(obj.toString()
            // .getBytes("UTF8"));

            StringEntity se = new StringEntity(obj.toString(), HTTP.UTF_8);
            se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
            // bae.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
            // "application/json"));
            httppatch.setEntity(se);

            // Execute HTTP Post Request

            HttpResponse httpResponse = httpclient.execute(httppatch);

            response = httpResponse.getStatusLine().toString();

        } catch (ClientProtocolException e) {

        } catch (IOException e) {

        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (response.contains("ACCEPTED")) {
            return true;
        } else {
            return false;
        }

    }

    public static int getBatteryLevel(Context context) {
        Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        int level = batteryIntent.getIntExtra("level", -1);
        int scale = batteryIntent.getIntExtra("scale", -1);

        // Error checking that probably isn't needed but I added just in case.
        if (level == -1 || scale == -1) {
            return -1;
        }

        int powerLevel = (int) Math.round(level * 100.0 / scale);

        return powerLevel;
    }

}