src.com.nustats.pacelogger.RecordingActivity.java Source code

Java tutorial

Introduction

Here is the source code for src.com.nustats.pacelogger.RecordingActivity.java

Source

/**    CycleTracks, Copyright 2009,2010 San Francisco County Transportation Authority
 *                                    San Francisco, CA, USA
 *
 *     @author Billy Charlton <billy.charlton@sfcta.org>
 *
 *   This file is part of CycleTracks.
 *
 *   CycleTracks 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.
 *
 *   CycleTracks 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 CycleTracks.  If not, see <http://www.gnu.org/licenses/>.
 */

package src.com.nustats.pacelogger;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class RecordingActivity extends Activity {
    Intent fi;
    TripData trip;
    boolean isRecording = false;
    Button pauseButton;
    Button finishButton;
    Timer timer;
    float curDistance;

    TextView txtStat;
    TextView txtDistance;
    TextView txtDuration;
    TextView txtCurSpeed;
    TextView txtMaxSpeed;
    TextView txtAvgSpeed;

    final SimpleDateFormat sdf = new SimpleDateFormat("H:mm:ss");

    // Need handler for callbacks to the UI thread
    final Handler mHandler = new Handler();
    final Runnable mUpdateTimer = new Runnable() {
        public void run() {
            updateTimer();
        }
    };

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

        setContentView(R.layout.recording);

        txtStat = (TextView) findViewById(R.id.TextRecordStats);
        txtDistance = (TextView) findViewById(R.id.TextDistance);
        txtDuration = (TextView) findViewById(R.id.TextDuration);
        txtCurSpeed = (TextView) findViewById(R.id.TextSpeed);
        txtMaxSpeed = (TextView) findViewById(R.id.TextMaxSpeed);
        txtAvgSpeed = (TextView) findViewById(R.id.TextAvgSpeed);

        pauseButton = (Button) findViewById(R.id.ButtonPause);
        finishButton = (Button) findViewById(R.id.ButtonFinished);

        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

        // Query the RecordingService to figure out what to do.
        Intent rService = new Intent(this, RecordingService.class);
        startService(rService);
        ServiceConnection sc = new ServiceConnection() {
            public void onServiceDisconnected(ComponentName name) {
            }

            public void onServiceConnected(ComponentName name, IBinder service) {
                IRecordService rs = (IRecordService) service;

                switch (rs.getState()) {
                // If recording service is idle, start recording
                case RecordingService.STATE_IDLE:
                    trip = TripData.createTrip(RecordingActivity.this);
                    rs.startRecording(trip);
                    isRecording = true;
                    RecordingActivity.this.pauseButton.setEnabled(true);
                    RecordingActivity.this.setTitle("PaceLogger - Recording...");
                    break;
                // If recording service is recording, fetch data
                case RecordingService.STATE_RECORDING:
                    long id = rs.getCurrentTrip();
                    trip = TripData.fetchTrip(RecordingActivity.this, id);
                    isRecording = true;
                    RecordingActivity.this.pauseButton.setEnabled(true);
                    RecordingActivity.this.setTitle("PaceLogger - Recording...");
                    break;
                // If recording service is paused, fetch data, display resume option
                case RecordingService.STATE_PAUSED:
                    long tid = rs.getCurrentTrip();
                    isRecording = false;
                    trip = TripData.fetchTrip(RecordingActivity.this, tid);
                    RecordingActivity.this.pauseButton.setEnabled(true);
                    RecordingActivity.this.pauseButton.setText("Resume");
                    RecordingActivity.this.setTitle("PaceLogger - Paused...");
                    break;
                case RecordingService.STATE_FULL:
                    // Should never get here, right?
                    break;
                }
                rs.setListener(RecordingActivity.this);
                unbindService(this);
            }
        };
        bindService(rService, sc, Context.BIND_AUTO_CREATE);

        // Pause button
        pauseButton.setEnabled(false);
        pauseButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                isRecording = !isRecording;
                if (isRecording) {
                    pauseButton.setText("Pause");
                    RecordingActivity.this.setTitle("PaceLogger - Recording...");
                    // Don't include pause time in trip duration
                    if (trip.pauseStartedAt > 0) {
                        trip.totalPauseTime += (System.currentTimeMillis() - trip.pauseStartedAt);
                        trip.pauseStartedAt = 0;
                    }
                    Toast.makeText(getBaseContext(), "GPS restarted. It may take a moment to resync.",
                            Toast.LENGTH_LONG).show();
                } else {
                    pauseButton.setText("Resume");
                    RecordingActivity.this.setTitle("PaceLogger - Paused...");
                    trip.pauseStartedAt = System.currentTimeMillis();
                    Toast.makeText(getBaseContext(), "Recording paused; GPS now offline", Toast.LENGTH_LONG).show();
                }
                RecordingActivity.this.setListener();
            }
        });

        // Finish button
        finishButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // If we have points, go to the save-trip activity
                if (trip.numpoints > 0) {
                    // Handle pause time gracefully
                    if (trip.pauseStartedAt > 0) {
                        trip.totalPauseTime += (System.currentTimeMillis() - trip.pauseStartedAt);
                    }
                    if (trip.totalPauseTime > 0) {
                        trip.endTime = System.currentTimeMillis() - trip.totalPauseTime;
                    }
                    // Save trip so far (points and extent, but no purpose or notes)
                    fi = new Intent(RecordingActivity.this, SaveTrip.class);
                    trip.updateTrip("", "", "", "");
                }
                // Otherwise, cancel and go back to main screen
                else {

                    Toast.makeText(getBaseContext(), "No GPS data acquired; nothing to submit.", Toast.LENGTH_SHORT)
                            .show();

                    cancelRecording();

                    // Go back to main screen
                    fi = new Intent(RecordingActivity.this, MainInput.class);
                    fi.putExtra("keep", true);
                }

                // Either way, activate next task, and then kill this task
                startActivity(fi);
                RecordingActivity.this.finish();
            }
        });
    }

    public void updateStatus(int points, float distance, float spdCurrent, float spdMax) {
        this.curDistance = distance;

        //TODO: check task status before doing this?
        if (points > 0) {
            txtStat.setText("" + points + " data points received...");
        } else {
            txtStat.setText("Waiting for GPS fix...");
        }
        txtCurSpeed.setText(String.format("%1.1f mph", spdCurrent));
        txtMaxSpeed.setText(String.format("Max Speed: %1.1f mph", spdMax));

        float miles = 0.0006212f * distance;
        txtDistance.setText(String.format("%1.1f miles", miles));
    }

    void setListener() {
        Intent rService = new Intent(this, RecordingService.class);
        ServiceConnection sc = new ServiceConnection() {
            public void onServiceDisconnected(ComponentName name) {
            }

            public void onServiceConnected(ComponentName name, IBinder service) {
                IRecordService rs = (IRecordService) service;
                if (RecordingActivity.this.isRecording) {
                    rs.resumeRecording();
                } else {
                    rs.pauseRecording();
                }
                unbindService(this);
            }
        };
        // This should block until the onServiceConnected (above) completes, but doesn't
        bindService(rService, sc, Context.BIND_AUTO_CREATE);
    }

    void cancelRecording() {
        Intent rService = new Intent(this, RecordingService.class);
        ServiceConnection sc = new ServiceConnection() {
            public void onServiceDisconnected(ComponentName name) {
            }

            public void onServiceConnected(ComponentName name, IBinder service) {
                IRecordService rs = (IRecordService) service;
                rs.cancelRecording();
                unbindService(this);
            }
        };
        // This should block until the onServiceConnected (above) completes.
        bindService(rService, sc, Context.BIND_AUTO_CREATE);
    }

    // onResume is called whenever this activity comes to foreground.
    // Use a timer to update the trip duration.
    @Override
    public void onResume() {
        super.onResume();

        timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                mHandler.post(mUpdateTimer);
            }
        }, 0, 1000); // every second
    }

    void updateTimer() {
        if (trip != null && isRecording) {
            double dd = System.currentTimeMillis() - trip.startTime - trip.totalPauseTime;

            txtDuration.setText(sdf.format(dd));

            double avgSpeed = 3600.0 * 0.6212 * this.curDistance / dd;
            txtAvgSpeed.setText(String.format("%1.1f mph", avgSpeed));
        }
    }

    // Don't do pointless UI updates if the activity isn't being shown.
    @Override
    public void onPause() {
        super.onPause();
        if (timer != null)
            timer.cancel();
    }
}