Java tutorial
/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.cellbots.logger; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.BatteryManager; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.StatFs; import android.text.format.DateUtils; import android.util.Log; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.view.View; import android.view.WindowManager; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.SlidingDrawer; import android.widget.TextView; import android.widget.Toast; import com.cellbots.logger.GpsManager.GpsManagerListener; import com.cellbots.logger.RemoteControl.Command; import com.cellbots.logger.WapManager.ScanResults; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.zip.Deflater; /** * Main activity for a data gathering tool. This tool enables recording video * and collecting data from sensors. Data is stored in: * /sdcard/SmartphoneLoggerData/. * * @author clchen@google.com (Charles L. Chen) */ public class LoggerActivity extends Activity { /* * Constants */ public static final String TAG = "CELLBOTS LOGGER"; public static final String EXTRA_MODE = "MODE"; public static final String EXTRA_PICTURE_DELAY = "PICTURE_DELAY"; public static final String EXTRA_USE_ZIP = "USE_ZIP"; public static final int MODE_VIDEO_FRONT = 0; public static final int MODE_VIDEO_BACK = 1; public static final int MODE_PICTURES = 2; private static final int UI_BAR_MAX_TOP_PADDING = 275; private static final float TEMPERATURE_MAX = 500; // max file size. if this is set to zero, only 1 .zip file is created protected static final int MAX_OUTPUT_ZIP_CHUNK_SIZE = 50 * 1024 * 1024; private static final int PROGRESS_ID = 123122312; /* * App state */ private volatile Boolean mIsRecording; private boolean useZip; private long startRecTime = 0; private Thread zipperThread; private long mDelay = 0; private LoggerApplication application; /* * UI Elements */ private AbstractCamcorderPreview mCamcorderView; private CameraPreview mCameraView; private TextView mAccelXTextView; private TextView mAccelYTextView; private TextView mAccelZTextView; private TextView mGyroXTextView; private TextView mGyroYTextView; private TextView mGyroZTextView; private TextView mMagXTextView; private TextView mMagYTextView; private TextView mMagZTextView; private BarImageView mBatteryTempBarImageView; private TextView mBatteryTempTextView; private TextView mBatteryTempSpacerTextView; private LinearLayout mFlashingRecGroup; private TextView mRecTimeTextView; private BarImageView mStorageBarImageView; private TextView mStorageTextView; private TextView mStorageSpacerTextView; private SlidingDrawer mDiagnosticsDrawer; private SlidingDrawer mDataDrawer; private TextView mPictureCountView; private TextView mGpsLocationView; /* * Sensors */ private List<Sensor> sensors; private SensorManager mSensorManager; private int mBatteryTemp = 0; private BufferedWriter mBatteryTempWriter; private BufferedWriter mBatteryLevelWriter; private BufferedWriter mBatteryVoltageWriter; private BufferedWriter mWifiWriter; private HashMap<String, BufferedWriter> sensorLogFileWriters; private StatFs mStatFs; private int mFreeSpacePct; private BufferedWriter mGpsLocationWriter; private BufferedWriter mGpsStatusWriter; private BufferedWriter mGpsNmeaWriter; private GpsManager mGpsManager; private WapManager mWapManager; private RemoteControl mRemoteControl; /* * Event handlers */ private SensorEventListener mSensorEventListener = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { Sensor sensor = event.sensor; if (sensor.getType() == Sensor.TYPE_GYROSCOPE) { // Gyroscope doesn't really have a notion of accuracy. // Due to a bug in Android, the gyroscope incorrectly returns // its status as unreliable. This can be safely ignored and does // not impact the accuracy of the readings. event.accuracy = SensorManager.SENSOR_STATUS_ACCURACY_HIGH; } updateSensorUi(sensor.getType(), event.accuracy, event.values); synchronized (mIsRecording) { if (mIsRecording) { String valuesStr = ""; for (int i = 0; i < event.values.length; i++) { valuesStr = valuesStr + event.values[i] + ","; } BufferedWriter writer = sensorLogFileWriters.get(sensor.getName()); try { writer.write(event.timestamp + "," + event.accuracy + "," + valuesStr + "\n"); writer.flush(); } catch (IOException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }; private BroadcastReceiver batteryBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Display and log the temperature mBatteryTemp = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0); float percentage = mBatteryTemp / TEMPERATURE_MAX; mBatteryTempBarImageView.setPercentage(percentage); int paddingTop = (int) ((1.0 - percentage) * UI_BAR_MAX_TOP_PADDING); mBatteryTempTextView.setText((mBatteryTemp / 10) + "C"); mBatteryTempSpacerTextView.setPadding(mBatteryTempSpacerTextView.getPaddingLeft(), paddingTop, mBatteryTempSpacerTextView.getPaddingRight(), mBatteryTempSpacerTextView.getPaddingBottom()); synchronized (mIsRecording) { if (!mIsRecording) return; try { mBatteryTempWriter.write(System.currentTimeMillis() + "," + mBatteryTemp + "\n"); } catch (IOException e) { e.printStackTrace(); } // Log the battery level int batteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); try { mBatteryLevelWriter.write(System.currentTimeMillis() + "," + batteryLevel + "\n"); } catch (IOException e) { e.printStackTrace(); } // Log the battery voltage level int batteryVoltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0); try { mBatteryVoltageWriter.write(System.currentTimeMillis() + "," + batteryVoltage + "\n"); } catch (IOException e) { e.printStackTrace(); } } } }; private WapManager.WapManagerListener mWifiListener = new WapManager.WapManagerListener() { @Override public void onScanResults(long timestamp, ScanResults results) { synchronized (mIsRecording) { if (!mIsRecording) return; } try { // Convert results to a json object JSONObject obj = new JSONObject(); obj.put("timestamp", timestamp); obj.put("results", new JSONObject(results)); // Write that object to a file mWifiWriter.write(obj.toString()); mWifiWriter.write("\n"); } catch (JSONException e) { Log.e("LoggerActivity", "Error logging wifi results. JSON Error"); e.printStackTrace(); } catch (IOException e) { Log.e("LoggerActivity", "Error logging wifi results. IO error"); e.printStackTrace(); } } }; private RemoteControl.CommandListener mCommandListener = new RemoteControl.CommandListener() { @Override public boolean onCommandReceived(Command c) throws Exception { if (c.command.equals("start")) { return onStartStopCommandReceived(c, true); } else if (c.command.equals("stop")) { return onStartStopCommandReceived(c, false); } else if (c.command.equals("status")) { if (mIsRecording) c.sendResponse("Status: RECORDING\n"); else c.sendResponse("Status: STOPPED\n"); } return false; } private boolean onStartStopCommandReceived(Command c, boolean start) { if (mIsRecording == start) { c.sendResponse("Recording already "); if (start) c.sendResponse("started.\n"); else c.sendResponse("stopped.\n"); return true; } final ImageButton recordButton = (ImageButton) findViewById(R.id.button_record); recordButton.performClick(); return false; } }; /* * Runnables */ private Runnable updateRecTimeDisplay = new Runnable() { // @Override @Override public void run() { boolean isRecording; synchronized (mIsRecording) { isRecording = mIsRecording; } while (isRecording) { mStatFs = new StatFs(Environment.getExternalStorageDirectory().toString()); final float percentage = (float) (mStatFs.getBlockCount() - mStatFs.getAvailableBlocks()) / (float) mStatFs.getBlockCount(); final int paddingTop = (int) ((1.0 - percentage) * UI_BAR_MAX_TOP_PADDING); mFreeSpacePct = (int) (percentage * 100); runOnUiThread(new Runnable() { // @Override @Override public void run() { if (mFlashingRecGroup != null) { if (mFlashingRecGroup.getVisibility() == View.VISIBLE) { mFlashingRecGroup.setVisibility(View.INVISIBLE); } else { mFlashingRecGroup.setVisibility(View.VISIBLE); } } if (mRecTimeTextView != null) { mRecTimeTextView.setText(DateUtils .formatElapsedTime((System.currentTimeMillis() - startRecTime) / 1000)); } if ((mPictureCountView != null) && (mCameraView != null)) { mPictureCountView.setText("Pictures taken: " + mCameraView.getPictureCount()); } mStorageBarImageView.setPercentage(percentage); mStorageTextView = (TextView) findViewById(R.id.storage_text); mStorageTextView.setText(mFreeSpacePct + "%"); mStorageSpacerTextView.setPadding(mStorageSpacerTextView.getPaddingLeft(), paddingTop, mStorageSpacerTextView.getPaddingRight(), mStorageSpacerTextView.getPaddingBottom()); } }); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (mIsRecording) { isRecording = mIsRecording; } } runOnUiThread(new Runnable() { // @Override @Override public void run() { if (mFlashingRecGroup != null) { mFlashingRecGroup.setVisibility(View.INVISIBLE); } } }); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); application = (LoggerApplication) getApplication(); // Keep the screen on to make sure the phone stays awake. getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); mIsRecording = false; useZip = getIntent().getBooleanExtra(EXTRA_USE_ZIP, true); final int mode = getIntent().getIntExtra(EXTRA_MODE, MODE_VIDEO_FRONT); if ((mode == MODE_VIDEO_FRONT) || (mode == MODE_VIDEO_BACK)) { if (mode == MODE_VIDEO_FRONT) { setContentView(R.layout.video_front_mode); } else { setContentView(R.layout.video_back_mode); } mCamcorderView = (AbstractCamcorderPreview) findViewById(R.id.surface); final SurfaceHolder previewHolder = mCamcorderView.getHolder(); previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } else { mDelay = getIntent().getIntExtra(EXTRA_PICTURE_DELAY, 30) * 1000; if (mDelay < 0) { mDelay = 0; } setContentView(R.layout.pictures_mode); mCameraView = (CameraPreview) findViewById(R.id.surface); } // Setup the initial available space mStatFs = new StatFs(Environment.getExternalStorageDirectory().toString()); float percentage = (float) (mStatFs.getBlockCount() - mStatFs.getAvailableBlocks()) / (float) mStatFs.getBlockCount(); mFreeSpacePct = (int) (percentage * 100); mStorageBarImageView = (BarImageView) findViewById(R.id.storage_barImageView); mStorageBarImageView.setPercentage(percentage); mStorageTextView = (TextView) findViewById(R.id.storage_text); mStorageSpacerTextView = (TextView) findViewById(R.id.storage_text_spacer); mStorageTextView.setText(mFreeSpacePct + "%"); mStorageSpacerTextView.setPadding(mStorageSpacerTextView.getPaddingLeft(), (int) ((1 - percentage) * UI_BAR_MAX_TOP_PADDING), mStorageSpacerTextView.getPaddingRight(), mStorageSpacerTextView.getPaddingBottom()); mFlashingRecGroup = (LinearLayout) findViewById(R.id.flashingRecGroup); mRecTimeTextView = (TextView) findViewById(R.id.recTime); mGpsLocationView = (TextView) findViewById(R.id.gpsLocation); mPictureCountView = (TextView) findViewById(R.id.pictureCount); mDataDrawer = (SlidingDrawer) findViewById(R.id.dataDrawer); mDiagnosticsDrawer = (SlidingDrawer) findViewById(R.id.diagnosticsDrawer); final ImageButton recordButton = (ImageButton) findViewById(R.id.button_record); recordButton.setOnClickListener(new View.OnClickListener() { // @Override @Override public void onClick(View v) { synchronized (mIsRecording) { if ((mode == MODE_VIDEO_FRONT) || (mode == MODE_VIDEO_BACK)) { if (!mIsRecording) { try { mIsRecording = true; recordButton.setImageResource(R.drawable.rec_button_pressed); // initializes recording mCamcorderView.initializeRecording(); // starts recording mCamcorderView.startRecording(); startRecTime = System.currentTimeMillis(); new Thread(updateRecTimeDisplay).start(); if (mRemoteControl != null) mRemoteControl.broadcastMessage("*** Recording Started ***\n"); } catch (Exception e) { Log.e("ls", "Recording has failed...", e); Toast.makeText(getApplicationContext(), "Camera hardware error. Please restart the application.", Toast.LENGTH_LONG) .show(); finish(); return; } } else { cleanup(); } } else { if (!mIsRecording) { try { mIsRecording = true; recordButton.setImageResource(R.drawable.rec_button_pressed); mCameraView.takePictures(mDelay); new Thread(updateRecTimeDisplay).start(); } catch (Exception e) { Log.e("ls", "Taking pictures has failed...", e); Toast.makeText(getApplicationContext(), "Taking pictures is not possible at the moment: " + e.toString(), Toast.LENGTH_SHORT).show(); } } else { cleanup(); } } } } }); final ImageButton dataButton = (ImageButton) findViewById(R.id.button_data); dataButton.setOnClickListener(new View.OnClickListener() { // @Override @Override public void onClick(View v) { if (mDataDrawer.isOpened()) { dataButton.setImageResource(R.drawable.data_button_up); mDataDrawer.animateClose(); } else { dataButton.setImageResource(R.drawable.data_button_pressed); mDataDrawer.animateOpen(); } } }); final ImageButton diagnosticsButton = (ImageButton) findViewById(R.id.button_diagnostics); diagnosticsButton.setOnClickListener(new View.OnClickListener() { // @Override @Override public void onClick(View v) { if (mDiagnosticsDrawer.isOpened()) { diagnosticsButton.setImageResource(R.drawable.diagnostics_button_up); mDiagnosticsDrawer.animateClose(); } else { diagnosticsButton.setImageResource(R.drawable.diagnostics_button_pressed); mDiagnosticsDrawer.animateOpen(); } } }); // setupSensors(); initSensorUi(); } @Override protected void onResume() { super.onResume(); setupSensors(); NetworkHelper.startConfiguration(getApplicationContext()); mRemoteControl = new RemoteControl(getApplicationContext()); mRemoteControl.registerCommandListener("start", mCommandListener); mRemoteControl.registerCommandListener("stop", mCommandListener); mRemoteControl.registerCommandListener("status", mCommandListener); mRemoteControl.start(); } @Override protected void onPause() { super.onPause(); Log.i("LoggerActivity", "onPause called"); // Unregister sensor listeners for (Sensor s : sensors) { mSensorManager.unregisterListener(mSensorEventListener, s); } // Does the gps cleanup/file closing cleanup(); // Unregister battery unregisterReceiver(batteryBroadcastReceiver); // Unregister WiFi mWapManager.unregisterReceiver(); // Stop the remote commanding mRemoteControl.shutdown(); mRemoteControl = null; Log.i("LoggerActivity", "onPause finished."); } @Override protected Dialog onCreateDialog(int id) { if (id != PROGRESS_ID) { return super.onCreateDialog(id); } final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setCancelable(false); // The setMessage call must be in both onCreateDialog and // onPrepareDialog otherwise it will // fail to update the dialog in onPrepareDialog. progressDialog.setMessage("Processing..."); return progressDialog; } @Override public void onPrepareDialog(int id, Dialog dialog, Bundle bundle) { super.onPrepareDialog(id, dialog, bundle); if (id != PROGRESS_ID) { return; } final ProgressDialog progressDialog = (ProgressDialog) dialog; progressDialog.setMessage("Processing..."); final Handler handler = new Handler() { @Override public void handleMessage(android.os.Message msg) { int done = msg.getData().getInt("percentageDone"); String status = msg.getData().getString("status"); progressDialog.setProgress(done); progressDialog.setMessage(status); if (mRemoteControl != null) { mRemoteControl.broadcastMessage("Zipping Progress: " + done + "%\n"); } } }; zipperThread = new Thread() { @Override public void run() { if (useZip) { ZipItUpRequest request = new ZipItUpRequest(); String directoryName = application.getLoggerPathPrefix(); request.setInputFiles(new FileListFetcher().getFilesAndDirectoriesInDir(directoryName)); request.setOutputFile(directoryName + "/logged-data.zip"); request.setMaxOutputFileSize(MAX_OUTPUT_ZIP_CHUNK_SIZE); request.setDeleteInputfiles(true); request.setCompressionLevel(Deflater.NO_COMPRESSION); try { new ZipItUpProcessor(request).chunkIt(handler); } catch (IOException e) { Log.e("Oh Crap!", "IoEx", e); } } // closing dialog progressDialog.dismiss(); application.generateNewFilePathUniqueIdentifier(); // TODO: Need to deal with empty directories that are created if // another recording // session is never started. initSensorLogFiles(); if (mCamcorderView != null) { try { mCamcorderView.startPreview(); if (mRemoteControl != null) mRemoteControl.broadcastMessage("*** Packaging Finished: OK to start ***\n"); } catch (RuntimeException e) { e.printStackTrace(); runOnUiThread(new Runnable() { // @Override @Override public void run() { Toast.makeText(getApplicationContext(), "Camera hardware error. Please restart the application.", Toast.LENGTH_LONG) .show(); } }); finish(); return; } } } }; zipperThread.start(); } private void setupSensors() { // initSensorUi(); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL); initSensorLogFiles(); // initBattery(); // *Note* This function deals with UI, not actual // readings. registerBattery(); // This is the actual function that deals with // receivers. initGps(); initWifi(); printSensors(); } private void initSensorUi() { mAccelXTextView = (TextView) findViewById(R.id.accelerometerX_text); mAccelYTextView = (TextView) findViewById(R.id.accelerometerY_text); mAccelZTextView = (TextView) findViewById(R.id.accelerometerZ_text); mGyroXTextView = (TextView) findViewById(R.id.gyroX_text); mGyroYTextView = (TextView) findViewById(R.id.gyroY_text); mGyroZTextView = (TextView) findViewById(R.id.gyroZ_text); mMagXTextView = (TextView) findViewById(R.id.magneticFieldX_text); mMagYTextView = (TextView) findViewById(R.id.magneticFieldY_text); mMagZTextView = (TextView) findViewById(R.id.magneticFieldZ_text); initBattery(); } private void initSensorLogFiles() { sensorLogFileWriters = new HashMap<String, BufferedWriter>(); String directoryName = application.getDataLoggerPath(); File directory = new File(directoryName); if (!directory.exists() && !directory.mkdirs()) { try { throw new IOException("Path to file could not be created. " + directory.getAbsolutePath()); } catch (IOException e) { Log.e(TAG, "Directory could not be created. " + e.toString()); } } for (int i = 0; i < sensors.size(); i++) { Sensor s = sensors.get(i); String sensorFilename = directoryName + s.getName().replaceAll(" ", "_") + "_" + application.getFilePathUniqueIdentifier() + ".txt"; File file = new File(sensorFilename); try { BufferedWriter writer = new BufferedWriter(new FileWriter(file)); sensorLogFileWriters.put(s.getName(), writer); } catch (IOException e) { e.printStackTrace(); } mSensorManager.registerListener(mSensorEventListener, s, SensorManager.SENSOR_DELAY_GAME); } // The battery is a special case since it is not a real sensor mBatteryTempWriter = createBufferedWriter("/BatteryTemp_", directoryName); mBatteryLevelWriter = createBufferedWriter("/BatteryLevel_", directoryName); mBatteryVoltageWriter = createBufferedWriter("/BatteryVoltage_", directoryName); // GPS is another special case since it is not a real sensor mGpsLocationWriter = createBufferedWriter("/GpsLocation_", directoryName); mGpsStatusWriter = createBufferedWriter("/GpsStatus_", directoryName); mGpsNmeaWriter = createBufferedWriter("/GpsNmea_", directoryName); // Wifi is another special case mWifiWriter = createBufferedWriter("/Wifi_", directoryName); } /** * Creates a new BufferedWriter. * * @param prefix The prefix for the file that we're writing to. * @return A BufferedWriter for a file in the specified directory. Null if * creation failed. */ private BufferedWriter createBufferedWriter(String prefix, String directoryName) { String filename = directoryName + prefix + application.getFilePathUniqueIdentifier() + ".txt"; File file = new File(filename); BufferedWriter bufferedWriter = null; try { bufferedWriter = new BufferedWriter(new FileWriter(file)); } catch (IOException e) { e.printStackTrace(); } return bufferedWriter; } private void updateSensorUi(int sensorType, int accuracy, float[] values) { // IMPORTANT: DO NOT UPDATE THE CONTENTS INSIDE A DRAWER IF IT IS BEING // ANIMATED VIA A CALL TO animateOpen/animateClose!!! // Updating anything inside will stop the animation from running. // Note that this does not seem to affect the animation if it had been // triggered by dragging the drawer instead of being called // programatically. if (mDataDrawer.isMoving()) { return; } TextView xTextView; TextView yTextView; TextView zTextView; if (sensorType == Sensor.TYPE_ACCELEROMETER) { xTextView = mAccelXTextView; yTextView = mAccelYTextView; zTextView = mAccelZTextView; } else if (sensorType == Sensor.TYPE_GYROSCOPE) { xTextView = mGyroXTextView; yTextView = mGyroYTextView; zTextView = mGyroZTextView; } else if (sensorType == Sensor.TYPE_MAGNETIC_FIELD) { xTextView = mMagXTextView; yTextView = mMagYTextView; zTextView = mMagZTextView; } else { return; } int textColor = Color.WHITE; String prefix = ""; switch (accuracy) { case SensorManager.SENSOR_STATUS_ACCURACY_HIGH: prefix = " "; break; case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM: prefix = " *"; break; case SensorManager.SENSOR_STATUS_ACCURACY_LOW: prefix = " **"; break; case SensorManager.SENSOR_STATUS_UNRELIABLE: prefix = " ***"; break; } xTextView.setTextColor(textColor); yTextView.setTextColor(textColor); zTextView.setTextColor(textColor); xTextView.setText(prefix + numberDisplayFormatter(values[0])); yTextView.setText(prefix + numberDisplayFormatter(values[1])); zTextView.setText(prefix + numberDisplayFormatter(values[2])); } private void initGps() { mGpsManager = new GpsManager(this, new GpsManagerListener() { // @Override @Override public void onGpsLocationUpdate(long time, float accuracy, double latitude, double longitude, double altitude, float bearing, float speed) { synchronized (mIsRecording) { if (!mIsRecording) return; } try { if (mGpsLocationView != null) { mGpsLocationView.setText("Lat: " + latitude + "\nLon: " + longitude); } mGpsLocationWriter.write(time + "," + accuracy + "," + latitude + "," + longitude + "," + altitude + "," + bearing + "," + speed + "\n"); } catch (IOException e) { e.printStackTrace(); } } // @Override @Override public void onGpsNmeaUpdate(long time, String nmeaString) { synchronized (mIsRecording) { if (!mIsRecording) return; } try { mGpsNmeaWriter.write(time + "," + nmeaString + "\n"); } catch (IOException e) { e.printStackTrace(); } } // @Override @Override public void onGpsStatusUpdate(long time, int maxSatellites, int actualSatellites, int timeToFirstFix) { synchronized (mIsRecording) { if (!mIsRecording) return; } try { mGpsStatusWriter.write( time + "," + maxSatellites + "," + actualSatellites + "," + timeToFirstFix + "\n"); } catch (IOException e) { e.printStackTrace(); } } }); } private void initBattery() { // Battery isn't a regular sensor; instead we have to use a Broadcast // receiver. // // We always write this file since the battery changed event isn't // called that often; otherwise, we might miss the initial battery // reading. // // Note that we are reading the current time in MILLISECONDS for this, // as opposed to NANOSECONDS for regular sensors. mBatteryTempBarImageView = (BarImageView) findViewById(R.id.temperature_barImageView); mBatteryTempTextView = (TextView) findViewById(R.id.batteryTemp_text); mBatteryTempSpacerTextView = (TextView) findViewById(R.id.batteryTemp_text_spacer); } private void initWifi() { if (mWapManager == null) mWapManager = new WapManager(getApplicationContext(), mWifiListener); mWapManager.registerReceiver(); } private void registerBattery() { IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); registerReceiver(batteryBroadcastReceiver, batteryFilter); } /** * Prints all the sensors to LogCat. */ private void printSensors() { List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL); for (int i = 0; i < sensors.size(); i++) { Sensor s = sensors.get(i); Log.d("DEBUG", s.getName()); } Log.d("DEBUG", "Also logging wifi. You're welcome."); } private void closeFiles() { try { Collection<BufferedWriter> writers = sensorLogFileWriters.values(); BufferedWriter[] w = new BufferedWriter[0]; w = writers.toArray(w); for (int i = 0; i < w.length; i++) { w.clone(); } if (mBatteryTempWriter != null) { mBatteryTempWriter.close(); } if (mBatteryLevelWriter != null) { mBatteryLevelWriter.close(); } if (mBatteryVoltageWriter != null) { mBatteryVoltageWriter.close(); } if (mGpsLocationWriter != null) { mGpsLocationWriter.close(); } if (mGpsStatusWriter != null) { mGpsStatusWriter.close(); } if (mGpsNmeaWriter != null) { mGpsNmeaWriter.close(); } if (mWifiWriter != null) { mWifiWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } private String numberDisplayFormatter(float value) { String displayedText = Float.toString(value); if (value >= 0) { displayedText = " " + displayedText; } if (displayedText.length() > 8) { displayedText = displayedText.substring(0, 8); } while (displayedText.length() < 8) { displayedText = displayedText + " "; } return displayedText; } private void cleanup() { boolean wasRecording = false; try { mGpsManager.shutdown(); synchronized (mIsRecording) { wasRecording = mIsRecording; if (!mIsRecording) { cleanupEmptyFiles(); } if (mCamcorderView != null) { if (mIsRecording) { mCamcorderView.stopRecording(); } mCamcorderView.releaseRecorder(); } if (mCameraView != null) { if (mIsRecording) { mCameraView.stop(); } mCameraView.releaseCamera(); } mIsRecording = false; } startRecTime = 0; ((ImageButton) findViewById(R.id.button_record)).setImageResource(R.drawable.rec_button_up); if (mRecTimeTextView != null) { mRecTimeTextView.setText(R.string.start_rec_time); } } catch (RuntimeException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { closeFiles(); if (wasRecording) { if (mRemoteControl != null) mRemoteControl.broadcastMessage("*** Recording Stopped ***\n"); showDialog(PROGRESS_ID); } } } private void cleanupEmptyFiles() { Log.i(TAG, "cleaning up empty dirs and zero byte files"); String logPath = application.getLoggerPathPrefix(); List<String> filesAndDirs = new FileListFetcher().getFilesAndDirectoriesInDir(logPath); List<String> allFilesAndDir = new ArrayList<String>(filesAndDirs.size() + 1); allFilesAndDir.addAll(filesAndDirs); allFilesAndDir.add(logPath); // make sure that all files in this list are zero byte files for (String name : allFilesAndDir) { File f = new File(name); if (f.isFile() && f.length() != 0) { // encountered a non-zero length file, abort deletes Log.i(TAG, "File: " + name + " has length: " + f.length() + "; aborting cleanup"); return; } } // delete all files and dirs boolean atLeastOneFileWasDeleted = true; while (atLeastOneFileWasDeleted) { atLeastOneFileWasDeleted = false; for (String name : allFilesAndDir) { File f = new File(name); if (f.exists() && f.delete()) { Log.d(TAG, "deleted " + name); atLeastOneFileWasDeleted = true; } } } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { boolean shouldExitApp; synchronized (mIsRecording) { shouldExitApp = !mIsRecording; } // cleanup(); if (shouldExitApp) { finish(); } return true; } return super.onKeyDown(keyCode, event); } }