package com.resl.sensors; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import android.app.Activity; import android.app.Dialog; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.media.MediaPlayer; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.os.Vibrator; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import com.resl.sensors.ServiceSensors.ServiceSensorListener; public class ActivityDataCollection extends Activity { private static int BUTTON_CLICK_TIME = 5000; private ServiceSensors mService; private TextView tvProfileName; private TextView tvFirstName; private TextView tvLastName; private ImageView ivUserPicture; private Spinner spinnerActivity; private EditText etLabel; private LinearLayout llStartStop; private TextView tvStartStopButton; private TextView tvStartStopButtonMessage; private ImageButton ibVibration; private ImageButton ibSound; private ImageView ivTimerCheckbox; private TextView tvTimer; private String timerString = ""; private boolean isVibrationEnabled; private boolean isSoundEnabled; private boolean isFirstCheck; private boolean hasStarted; private Profile mProfile; private static MediaPlayer mMediaPlayer; private static Vibrator vibrator; ArrayList<String> activities; long mStartTime = 0L; String mainPath = Environment.getExternalStorageDirectory() + "/RESL_Data"; private SharedPreferences sharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_data_collection); // Get shared preferences sharedPreferences = getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Activity.MODE_PRIVATE); // Initialize if not already initialized if (!sharedPreferences.contains(Constants.KEY_SENSOR_TYPE)) { Editor editor = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE) .edit(); String[] arraySensorTypes = getResources().getStringArray(R.array.array_sensor_type); String[] arrayDelayOptions = getResources().getStringArray(R.array.array_rate); // Use first element as default editor.putString(Constants.KEY_SENSOR_TYPE, arraySensorTypes[0]); editor.putString(Constants.KEY_RATE_GYROSCOPE, arrayDelayOptions[0]); editor.putString(Constants.KEY_RATE_ACCELEROMETER, arrayDelayOptions[0]); editor.putBoolean(Constants.KEY_ROTATED_GYROSCOPE, false); editor.putBoolean(Constants.KEY_ROTATED_ACCELEROMETER, false); // Commit the changes editor.commit(); } // Get UI elements tvProfileName = (TextView) findViewById(R.id.textview_data_collection_profilename); tvFirstName = (TextView) findViewById(R.id.textview_data_collection_firstname); tvLastName = (TextView) findViewById(R.id.textview_data_collection_lastname); ivUserPicture = (ImageView) findViewById(R.id.imageview_data_collection_user_picture); spinnerActivity = (Spinner) findViewById(R.id.spinner_data_collection_activity); etLabel = (EditText) findViewById(R.id.edittext_data_collection_label); llStartStop = (LinearLayout) findViewById(R.id.linearlayout_data_collection_start_stop); tvStartStopButton = (TextView) findViewById(R.id.textview_button_start_stop); tvStartStopButtonMessage = (TextView) findViewById(R.id.textview_button_start_stop_message); ibVibration = (ImageButton) findViewById(R.id.imagebutton_data_collection_vibration); ibSound = (ImageButton) findViewById(R.id.imagebutton_data_collection_sound); tvTimer = (TextView) findViewById(R.id.textview_data_collection_timer); ivTimerCheckbox = (ImageView) findViewById(R.id.imageview_data_collection_timer_checkbox); initializeClickListeners(); isVibrationEnabled = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE) .getBoolean(Constants.KEY_VIBRATION, true); isSoundEnabled = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE) .getBoolean(Constants.KEY_SOUND, true); isFirstCheck = true; vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); updateVibrationIcon(); updateSoundIcon(); startService(); } @Override protected void onResume() { super.onResume(); setSpinner(); // Check if a profile is present or not String profile = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE) .getString(Constants.KEY_PROFILE, Constants.KEY_NO_PROFILE); if (profile.compareTo(Constants.KEY_NO_PROFILE) == 0) { Intent intent = new Intent(ActivityDataCollection.this, ActivityProfile.class); startActivity(intent); } else { loadProfile(profile); } } @Override public void onDestroy() { unbindFromService(); super.onDestroy(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.menu_select_profile: Intent intent = new Intent(ActivityDataCollection.this, ActivityProfile.class); startActivity(intent); return true; case R.id.menu_view_data: Intent intentChart = new Intent(ActivityDataCollection.this, ActivityBrowse.class); intentChart.putExtra(ActivityBrowse.KEY_DISPLAY_FOLDERS, true); intentChart.putExtra(ActivityBrowse.KEY_DELETING, false); intentChart.putExtra(ActivityBrowse.KEY_FOLDER_NAME, mProfile.getProfilePath()); startActivity(intentChart); return true; case R.id.menu_settings: Intent intentSettings = new Intent(ActivityDataCollection.this, ActivitySettings.class); startActivity(intentSettings); return true; case R.id.menu_send_feedback: final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); String[] emailAdresses = { "ankit@usc.edu" }; emailIntent.setType("plain/text"); emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Movement Trackr: Feedback / Comment"); emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, emailAdresses); startActivity(Intent.createChooser(emailIntent, "Send mail...")); return true; case R.id.menu_exit: this.finish(); return true; default: return super.onOptionsItemSelected(item); } } private void setSpinner() { activities = new ArrayList<String>(); String stringActivities = sharedPreferences.getString(Constants.KEY_ADD_ACTIVTY, ""); String[] predefinedActivities = getResources().getStringArray(R.array.array_activities); String[] customActivities = stringActivities.split(","); // Add predefined activities for (int i = 0; i < predefinedActivities.length; i++) { activities.add(predefinedActivities[i]); } // Add custom activities for (int i = 0; i < customActivities.length; i++) { if (customActivities[i].length() > 0) { activities.add(customActivities[i]); } } ArrayAdapter<String> activityAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, activities); spinnerActivity.setAdapter(activityAdapter); System.gc(); } private void loadProfile(String profileName) { File profile = new File(mainPath + "/" + profileName + "/.profile"); String fullText = ""; String line = ""; if (profile.exists()) { FileInputStream fstream; try { fstream = new FileInputStream(profile); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); while ((line = br.readLine()) != null) { fullText += line; } fstream.close(); mProfile = new Profile(profileName, fullText); } catch (Exception e) { Log.e("ACTIVITY_PROFILE", "Error reading profile. Error : " + e.getMessage()); } } else { Toast.makeText(ActivityDataCollection.this, "Error loading profile. Profile does not exists. Please select a profile using Menu > Select Profile.", Toast.LENGTH_LONG).show(); Log.e("ACTIVITY_PROFILE", "Profile '" + profileName + "' does not exists. Creating new."); } displayProfile(); // Load profile avatar File file = new File(mainPath + "/" + profileName + "/avatar.jpg"); if (file.exists()) { Drawable drawable = new BitmapDrawable(mainPath + "/" + profileName + "/avatar.jpg"); ivUserPicture.setImageDrawable(drawable); } else { ivUserPicture.setImageResource(R.drawable.userdetails_avatarplaceholder); } } private void displayProfile() { tvProfileName.setText(mProfile.getProfileName()); tvFirstName.setText(mProfile.getFirstName()); tvLastName.setText(mProfile.getLastName()); } private void initializeClickListeners() { llStartStop.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mService != null) { if (mService.isCollectingData()) { stopCollectingData(); } else { if (isFirstCheck) { isFirstCheck = false; hasStarted = false; llStartStop.setBackgroundResource(R.drawable.background_confirm); tvStartStopButton.setText("Confirm"); new Thread() { @Override public void run() { int check_interval = 100; int ticks = BUTTON_CLICK_TIME / check_interval; // Check if 5 seconds are over or not while (!isFirstCheck && (ticks > 0)) { // Display the message if exacts to a // second if ((ticks % 10) == 0) { final int milliSeconds = ticks; runOnUiThread(new Runnable() { public void run() { tvStartStopButtonMessage.setVisibility(View.VISIBLE); tvStartStopButtonMessage.setText("Click within " + (milliSeconds / 10) + " seconds to start"); } }); } try { Thread.sleep(check_interval); } catch (InterruptedException e) { } ticks--; } isFirstCheck = true; // Check if Service is not collecting the // data if ((mService != null) && (!hasStarted)) { if (!mService.isCollectingData()) { runOnUiThread(new Runnable() { public void run() { hasStarted = false; try { if (tvStartStopButton != null) { tvStartStopButton.setText("Start"); } if (tvStartStopButtonMessage != null) { tvStartStopButtonMessage.setVisibility(View.GONE); } if (llStartStop != null) { llStartStop.setBackgroundResource(R.drawable.background_start); } } catch (Exception ex) { } } }); } } } }.start(); } else { isFirstCheck = true; hasStarted = true; tvStartStopButtonMessage.setVisibility(View.GONE); startCollectingData(); if (isVibrationEnabled) { vibrate(1500); } if (isSoundEnabled) { playAudio(ActivityDataCollection.this, R.raw.beep); } } } } } }); ibVibration.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { isVibrationEnabled = !isVibrationEnabled; Editor editor = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE) .edit(); editor.putBoolean(Constants.KEY_VIBRATION, isVibrationEnabled); editor.commit(); updateVibrationIcon(); } }); ibSound.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { isSoundEnabled = !isSoundEnabled; Editor editor = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE) .edit(); editor.putBoolean(Constants.KEY_SOUND, isSoundEnabled); editor.commit(); updateSoundIcon(); } }); if (sharedPreferences.getBoolean(Constants.KEY_TIMER, false)) { long time = sharedPreferences.getLong(Constants.KEY_TIMER_TIME, 0); int seconds = (int) (time % 60); time /= 60; int minutes = (int) (time % 60); time /= 60; int hours = (int) time; final String secondsString = (seconds < 10) ? "0" + String.valueOf(seconds) : String.valueOf(seconds); final String minutesString = (minutes < 10) ? "0" + String.valueOf(minutes) : String.valueOf(minutes); timerString = hours + ":" + minutesString + ":" + secondsString; tvTimer.setText(timerString); ivTimerCheckbox.setImageResource(R.drawable.checkbox_on); } else { tvTimer.setText("0:00:00"); ivTimerCheckbox.setImageResource(R.drawable.checkbox_off); } ivTimerCheckbox.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { final Dialog dialog = new Dialog(ActivityDataCollection.this); dialog.setContentView(R.layout.timer_picker); dialog.setTitle("Custom Dialog"); Button buttonEnable = (Button) dialog.findViewById(R.id.button_dialog_enable); Button buttonDisable = (Button) dialog.findViewById(R.id.button_dialog_disable); final NumberPicker npHours = (NumberPicker) dialog.findViewById(R.id.numberpicker_dialog_hours); final NumberPicker npMinutes = (NumberPicker) dialog.findViewById(R.id.numberpicker_dialog_minutes); final NumberPicker npSeconds = (NumberPicker) dialog.findViewById(R.id.numberpicker_dialog_seconds); npHours.setRange(0, 24); if (sharedPreferences.getBoolean(Constants.KEY_TIMER, false)) { long time = sharedPreferences.getLong(Constants.KEY_TIMER_TIME, 0); int seconds = (int) (time % 60); time /= 60; int minutes = (int) (time % 60); time /= 60; int hours = (int) time; npHours.setCurrent(hours); npMinutes.setCurrent(minutes); npSeconds.setCurrent(seconds); } else { npHours.setCurrent(0); npMinutes.setCurrent(0); npSeconds.setCurrent(0); } buttonDisable.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Editor editor = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE).edit(); // Use first element as default editor.putBoolean(Constants.KEY_TIMER, (Boolean) false); // Commit the changes editor.commit(); ivTimerCheckbox.setImageResource(R.drawable.checkbox_off); timerString = "0:00:00"; tvTimer.setText(timerString); dialog.dismiss(); } }); buttonEnable.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if ((npHours.getCurrent() * 3600 + npMinutes.getCurrent() * 60 + npSeconds.getCurrent()) <= 0) { Toast.makeText(ActivityDataCollection.this, "Time can not be 0", Toast.LENGTH_SHORT).show(); } else { long time = npHours.getCurrent() * 3600 + npMinutes.getCurrent() * 60 + npSeconds.getCurrent(); Editor editor = getApplicationContext().getSharedPreferences(Constants.PREFERENCES_KEY_APPLICATION, Context.MODE_PRIVATE).edit(); editor.putBoolean(Constants.KEY_TIMER, true); // Save the time editor.putLong(Constants.KEY_TIMER_TIME, time); // Commit the changes editor.commit(); final String secondsString = (npSeconds.getCurrent() < 10) ? "0" + String.valueOf(npSeconds.getCurrent()) : String.valueOf(npSeconds.getCurrent()); final String minutesString = (npMinutes.getCurrent() < 10) ? "0" + String.valueOf(npMinutes.getCurrent()) : String.valueOf(npMinutes.getCurrent()); timerString = npHours.getCurrent() + ":" + minutesString + ":" + secondsString; tvTimer.setText(timerString); ivTimerCheckbox.setImageResource(R.drawable.checkbox_on); dialog.dismiss(); } } }); dialog.show(); } }); } private void updateSoundIcon() { if (isSoundEnabled) { ibSound.setBackgroundResource(R.drawable.sound_on); } else { ibSound.setBackgroundResource(R.drawable.sound_off); } } private void updateVibrationIcon() { if (isVibrationEnabled) { ibVibration.setBackgroundResource(R.drawable.vibration_on); } else { ibVibration.setBackgroundResource(R.drawable.vibration_off); } } private static void playAudio(Context context, int resource) { mMediaPlayer = MediaPlayer.create(context, resource); new Thread(new Runnable() { @Override public void run() { try { mMediaPlayer.start(); while (mMediaPlayer.isPlaying()) { Thread.sleep(2000); } releaseAudio(); } catch (Exception e) { Log.e("Sound", e.toString()); } } }).start(); } /** * Releases audio player instance created */ public static void releaseAudio() { mMediaPlayer.release(); } private void vibrate(int milliseconds) { vibrator.vibrate(milliseconds); } private void startService() { // Start the service (even if already started Intent intent = new Intent(ActivityDataCollection.this, ServiceSensors.class); startService(intent); // Bind to the service to get sensor values new Thread() { @Override public void run() { bindService(new Intent(ActivityDataCollection.this, ServiceSensors.class), mConnection, Context.BIND_AUTO_CREATE); } }.start(); } private void unbindFromService() { // Check if service is not null if (mService != null) { // Check if data is still being collected if (mService.isCollectingData()) { // Stop Collecting Data mService.stopCollectingData(); } mService.removeOnServiceSensorListener(); } // Check if connection is not null if (mConnection != null) { // Unbind the service unbindService(mConnection); } mConnection = null; mService = null; } public void startCollectingData() { if (mService != null) { tvStartStopButton.setText("Stop"); llStartStop.setBackgroundResource(R.drawable.background_stop); tvStartStopButtonMessage.setText(""); spinnerActivity.setEnabled(false); etLabel.setEnabled(false); String activity = (String) spinnerActivity.getSelectedItem(); String label = etLabel.getEditableText().toString(); String name = mProfile.getLastName() + "_" + mProfile.getFirstName(); activity = activity.replace(' ', '_'); mService.startCollectingData(true, mProfile.getProfileName(), name, activity, label); } } public void stopCollectingData() { if (mService != null) { if (timerString.length() > 0) { tvTimer.setText(timerString); } else { tvTimer.setText("0:00:00"); } tvStartStopButton.setText("Start"); llStartStop.setBackgroundResource(R.drawable.background_start); spinnerActivity.setEnabled(true); etLabel.setEnabled(true); mService.stopCollectingData(); } } private final ServiceSensorListener mListener = new ServiceSensorListener() { @Override public void onMessage(int message) { Toast.makeText(ActivityDataCollection.this, "Sampling Rate : " + message, Toast.LENGTH_SHORT).show(); } @Override public void onGyroscopeReadings(int serviceCode) { // TODO Auto-generated method stub } @Override public void onCompassReadings(int readings) { // TODO Auto-generated method stub } @Override public void onAccelerometerReadings(int test) { // TODO Auto-generated method stub } @Override public void onTimerTimeUpdate(long time) { final long timeOriginal = time; int seconds = (int) (time % 60); time /= 60; int minutes = (int) (time % 60); time /= 60; final int hours = (int) (time % 60); final String secondsString = (seconds < 10) ? "0" + String.valueOf(seconds) : String.valueOf(seconds); final String minutesString = (minutes < 10) ? "0" + String.valueOf(minutes) : String.valueOf(minutes); runOnUiThread(new Runnable() { @Override public void run() { tvTimer.setText(hours + ":" + minutesString + ":" + secondsString); if (timeOriginal == 0) { stopCollectingData(); } } }); } }; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. mService = ((ServiceSensors.LocalBinder) service).getService(); // Create a connection to the service mService.setOnServiceSensorListener(mListener); Log.i("ACTIVITY_DATA_COLLECTION", "Service bounded"); } @Override public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. mService = null; Log.e("ACTIVTY_DATA_COLLECTION", "Service crashed unexpectedly."); } }; }