303 lines
9.1 KiB
Java
303 lines
9.1 KiB
Java
|
|
|
|
package com.eaesthetics.scaleapp;
|
|
|
|
import android.app.Activity;
|
|
import android.content.pm.ActivityInfo;
|
|
import android.hardware.Sensor;
|
|
import android.hardware.SensorEvent;
|
|
import android.hardware.SensorEventListener;
|
|
import android.hardware.SensorManager;
|
|
import android.os.Bundle;
|
|
import android.view.Gravity;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.Window;
|
|
import android.widget.Button;
|
|
import android.widget.PopupWindow;
|
|
import android.widget.TextView;
|
|
/** The application */
|
|
public class MainActivity extends Activity implements SensorEventListener {
|
|
|
|
|
|
// All of the Float are used to store the data used to calculate the mass,
|
|
// All of the text views display these number, but are for debug purposes only and not displayed
|
|
protected Float calculatedMass;
|
|
protected TextView calculatedMassView;
|
|
protected Float changeInAngle;
|
|
protected TextView changeInAngleView;
|
|
protected TextView debugView;
|
|
protected Float finalAngle;
|
|
protected TextView finalAngleView;
|
|
protected Float fiveGramAngle;
|
|
protected TextView fiveGramAngleView;
|
|
protected Float initialAngle;
|
|
protected TextView initialAngleView;
|
|
protected TextView instructionsView;
|
|
protected Sensor mSensor;
|
|
protected SensorManager mSensorManager;
|
|
protected TextView pitchView;
|
|
protected Float tareAngle;
|
|
protected Float theConstantNumber;
|
|
protected TextView theConstantView;
|
|
|
|
Filter[] m_filters = { new Filter(), new Filter(), new Filter() }; // A filter used to filter the raw sensor data
|
|
float[] m_lastAccels;
|
|
float[] m_lastMagFields;
|
|
float m_lastPitch = 0.3f;
|
|
float m_lastRoll = 0.3f;
|
|
float m_lastYaw = 0.3f;
|
|
private float[] m_orientation = new float[4];
|
|
int m_pitchIndex = 0;
|
|
float[] m_prevPitch = new float[AVERAGE_BUFFER];
|
|
float[] m_prevRoll = new float[AVERAGE_BUFFER];
|
|
int m_rollIndex = 0;
|
|
private float[] m_rotationMatrix = new float[16];
|
|
final static int AVERAGE_BUFFER = 100;
|
|
|
|
/**Called when the activity is first created.
|
|
* @param savedInstanceState the saved instances from the device */
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
this.requestWindowFeature(Window.FEATURE_NO_TITLE); //Remove activity bar
|
|
setContentView(R.layout.activity_main); // binds code to XML layout
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //Forces landscape mode
|
|
setButtonClickListener();
|
|
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); //Start phone sensors
|
|
registerListeners(); //Register listeners of sensors
|
|
|
|
}
|
|
/** Called when the activity is destroyed. */
|
|
@Override
|
|
public void onDestroy() {
|
|
unregisterListeners();
|
|
super.onDestroy();
|
|
}
|
|
/** Called when the activity is paused. */
|
|
@Override
|
|
public void onPause() {
|
|
unregisterListeners();
|
|
super.onPause();
|
|
|
|
}
|
|
/** Called when the activity is resumed. */
|
|
@Override
|
|
public void onResume() {
|
|
registerListeners();
|
|
super.onResume();
|
|
}
|
|
/** Called sensors are changed. */
|
|
@Override
|
|
public void onSensorChanged(SensorEvent event) {
|
|
debug();
|
|
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
|
|
accel(event);
|
|
}
|
|
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
|
|
mag(event);
|
|
}
|
|
|
|
}
|
|
/** Called when the activity is stopped. */
|
|
@Override
|
|
public void onStop() {
|
|
unregisterListeners();
|
|
super.onStop();
|
|
}
|
|
|
|
/**Called when the device accelerates in any direction.
|
|
* @param event The sensor event*/
|
|
private void accel(SensorEvent event) {
|
|
if (m_lastAccels == null) {
|
|
m_lastAccels = new float[3];
|
|
}
|
|
|
|
System.arraycopy(event.values, 0, m_lastAccels, 0, 3);
|
|
|
|
}
|
|
/** Called when final data button is clicked.*/
|
|
|
|
public void bindFinalData() {
|
|
finalAngleView = (TextView) findViewById(R.id.vFinalAngleView);
|
|
finalAngleView.setText("The final Angle is " + finalAngle.toString());
|
|
changeInAngleView = (TextView) findViewById(R.id.vChangeInAngleView);
|
|
changeInAngleView.setText("Change in Angle is "
|
|
+ changeInAngle.toString());
|
|
theConstantView = (TextView) findViewById(R.id.vTheConstantView);
|
|
theConstantView.setText("The Constant is "
|
|
+ theConstantNumber.toString());
|
|
System.out.println(+theConstantNumber);
|
|
calculatedMassView = (TextView) findViewById(R.id.vCalculatedMassView);
|
|
|
|
calculatedMassView.setText(+ /*calculatedMass*/ (double)Math.round(calculatedMass * 100) / 100 +" g");
|
|
calculatedMassView.setVisibility(1);
|
|
|
|
}
|
|
/** Called when the five gram tare angle button is clicked */
|
|
public void bindFiveGramAngle() {
|
|
fiveGramAngle = m_lastPitch;
|
|
fiveGramAngleView = (TextView) findViewById(R.id.vFiveGramView);
|
|
fiveGramAngleView.setText("The angle at 5 grams is "
|
|
+ fiveGramAngle.toString());
|
|
}
|
|
/** Called when initial tare button is clicked. */
|
|
public void bindInitialAngle() {
|
|
initialAngle = m_lastPitch;
|
|
initialAngleView = (TextView) findViewById(R.id.vInitialAngleView);
|
|
initialAngleView.setText("The Initial angle is "
|
|
+ initialAngle.toString());
|
|
|
|
}
|
|
/** Calculates mass based on data */
|
|
public void calculateData() {
|
|
finalAngle = m_lastPitch;
|
|
tareAngle = fiveGramAngle - initialAngle;
|
|
theConstantNumber = tareAngle / 5;
|
|
changeInAngle = finalAngle - initialAngle;
|
|
calculatedMass = changeInAngle / theConstantNumber;
|
|
}
|
|
/** Computes device orientation based on sensor*/
|
|
private void computeOrientation() {
|
|
|
|
|
|
if (SensorManager.getRotationMatrix(m_rotationMatrix, null,
|
|
m_lastAccels, m_lastMagFields)) {
|
|
SensorManager.getOrientation(m_rotationMatrix, m_orientation);
|
|
|
|
/* Radian Measure 57.295 degrees */
|
|
|
|
float pitch = m_orientation[1] * 57.295f;
|
|
m_lastPitch = m_filters[1].append(pitch);
|
|
|
|
}
|
|
}
|
|
/** Debug information */
|
|
public void debug() {
|
|
debugView = (TextView) findViewById(R.id.vDebug);
|
|
Float output = m_lastPitch;
|
|
debugView.setText(output.toString());
|
|
}
|
|
/** Magnetic field information is added to an array here from the sensor data */
|
|
private void mag(SensorEvent event) {
|
|
if (m_lastMagFields == null) {
|
|
m_lastMagFields = new float[3];
|
|
}
|
|
|
|
System.arraycopy(event.values, 0, m_lastMagFields, 0, 3);
|
|
|
|
if (m_lastAccels != null) {
|
|
computeOrientation();
|
|
}
|
|
}
|
|
/** Called when the accuracy of the device is changed. It isn't during the applications lifetime */
|
|
@Override
|
|
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
/** Registers the listeners of the sensor */
|
|
private void registerListeners() {
|
|
mSensorManager.registerListener(this,
|
|
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
|
|
SensorManager.SENSOR_DELAY_GAME);
|
|
mSensorManager.registerListener(this,
|
|
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
|
|
SensorManager.SENSOR_DELAY_GAME);
|
|
}
|
|
/** Sets the click listeners of the buttons */
|
|
public void setButtonClickListener() {
|
|
Button initialButton = (Button) findViewById(R.id.bInitialButton);
|
|
Button fiveGramButton = (Button) findViewById(R.id.bFiveGramButton);
|
|
Button finalAngleButton = (Button) findViewById(R.id.bFinalAngleButton);
|
|
final Button instructionsButton = (Button) findViewById(R.id.bInstructionsButton);
|
|
initialButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
timeDelay();
|
|
bindInitialAngle();
|
|
}
|
|
|
|
});
|
|
fiveGramButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
timeDelay();
|
|
bindFiveGramAngle();
|
|
}
|
|
});
|
|
finalAngleButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
timeDelay();
|
|
calculateData();
|
|
bindFinalData();
|
|
|
|
}
|
|
});
|
|
instructionsButton.setOnClickListener(new View.OnClickListener() {
|
|
|
|
@Override
|
|
public void onClick(View arg0) {
|
|
LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
|
|
.getSystemService(LAYOUT_INFLATER_SERVICE);
|
|
View popupView = layoutInflater.inflate(
|
|
R.layout.instructions_main, null);
|
|
final PopupWindow popupWindow = new PopupWindow(popupView,
|
|
android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
|
|
Button btnDismiss = (Button) popupView
|
|
.findViewById(R.id.dismiss);
|
|
btnDismiss.setOnClickListener(new Button.OnClickListener() {
|
|
|
|
@Override
|
|
public void onClick(View v) {
|
|
popupWindow.dismiss();
|
|
}
|
|
});
|
|
popupWindow.showAtLocation(arg0, Gravity.CENTER, 0, 0);
|
|
}
|
|
});
|
|
}
|
|
/** Unregisters the listeners of the sensors */
|
|
private void unregisterListeners() {
|
|
mSensorManager.unregisterListener(this);
|
|
}
|
|
private void timeDelay() {
|
|
try {
|
|
synchronized(this){
|
|
// Wait given period of time or exit on touch
|
|
wait(1000);
|
|
}
|
|
}
|
|
catch(InterruptedException ex){
|
|
}
|
|
}
|
|
/** Filters raw sensor data into instantaneous angle */
|
|
private class Filter {
|
|
static final int AVERAGE_BUFFER = 15;
|
|
float[] m_arr = new float[AVERAGE_BUFFER];
|
|
int m_idx = 0;
|
|
|
|
public float append(float val) {
|
|
m_arr[m_idx] = val;
|
|
m_idx++;
|
|
if (m_idx == AVERAGE_BUFFER)
|
|
m_idx = 0;
|
|
|
|
return avg();
|
|
}
|
|
/** The average orientation over the AVERAGE_BUFFER */
|
|
public float avg() {
|
|
float sum = 0;
|
|
for (float x : m_arr)
|
|
sum += x;
|
|
return sum / AVERAGE_BUFFER;
|
|
}
|
|
}
|
|
}
|
|
|
|
|