Skip to content
Snippets Groups Projects
Commit 03adf161 authored by toni's avatar toni
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 1016 additions and 0 deletions
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<compositeConfiguration>
<compositeBuild compositeDefinitionSource="SCRIPT" />
</compositeConfiguration>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
\ No newline at end of file
/build
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "de.tonifetzer.sensorrecorder"
minSdkVersion 14
targetSdkVersion 28
versionCode 3
versionName "1.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.tonifetzer.sensorrecorder">
<!--<uses-feature android:name="android.hardware.type.watch" /> -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.BODY_SENSORS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<application
android:allowBackup="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:roundIcon="@drawable/icon"
android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<uses-library android:name="com.google.android.wearable"
android:required="false" />
</application>
</manifest>
\ No newline at end of file
package de.tonifetzer.sensorrecorder;
import android.content.Context;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.ToggleButton;
import java.util.concurrent.TimeUnit;
import de.tonifetzer.sensorrecorder.sensors.Logger;
import de.tonifetzer.sensorrecorder.sensors.MySensor;
import de.tonifetzer.sensorrecorder.sensors.PhoneSensors;
import de.tonifetzer.sensorrecorder.sensors.SensorType;
public class MainActivity extends AppCompatActivity {
private ToggleButton recButton;
private TextView txtViewTimeCounter;
private TextView txtViewFilename;
private TextView txtViewFilesize;
private PhoneSensors phoneSensors;
private final Logger dataLogger = new Logger(this);
private int loadCounter = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//this is a small hack to get a static context
MainActivity.context = getApplicationContext();
//init the sensors of the phone
phoneSensors = new PhoneSensors(this);
//find ui elements
recButton = findViewById(R.id.toggleButton);
txtViewTimeCounter = findViewById(R.id.textViewTimeCounter);
txtViewFilename = findViewById(R.id.textViewFilename);
txtViewFilesize = findViewById(R.id.textViewFilesize);
//set the listener
phoneSensors.setListener(new MySensor.SensorListener(){
@Override public void onData(final String csv) {}
@Override public void onData(final SensorType id, final String csv) {addDataToFile(id, csv); }
});
recButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
buttonView.setBackgroundColor(Color.parseColor("#FFCC0000"));
startRecording();
}
else{
buttonView.setBackgroundColor(Color.parseColor("#FF669900"));
stopRecording();
}
}
});
}
private void startRecording() {
phoneSensors.onResume(this);
loadCounter = 0;
dataLogger.start();
String path = dataLogger.getFile().getAbsolutePath();
txtViewFilename.setText(path.substring(path.length()-17));
}
private void stopRecording() {
phoneSensors.onPause(this);
dataLogger.stop();
}
private void addDataToFile(final SensorType id, final String csv) {
dataLogger.addCSV(id, csv);
runOnUiThread(new Runnable() {
@Override public void run() {
// dump buffer stats every x entries
if (++loadCounter % 250 == 0) {
//set filesize and buffer dump
final int kbPerMin = (int) (dataLogger.getTotalSize() / 1024 * 1000 * 60 / (System.currentTimeMillis() - dataLogger.getStartTS()));
txtViewFilesize.setText( (dataLogger.getCurrentSize() / 1024) + "kb, " + kbPerMin + "kb/min");
//set time (of course, this is not perfectly accurate, however for this purpose its okay)
long minutes = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - dataLogger.getStartTS());
long seconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - dataLogger.getStartTS());
txtViewTimeCounter.setText(minutes + ":" + (seconds - (minutes * 60)));
}
}
});
}
//This is also part of the hack to get a static context
private static Context context;
public static Context getAppContext() {
return MainActivity.context;
}
}
package de.tonifetzer.sensorrecorder.sensors;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import java.io.File;
/**
* SDK save file class. Is able to open a folder on the device independent of the given
* device and android skd version.
*/
public class DataFolder {
private Context context;
private File folder;
public DataFolder(Context context, String folderName){
this.context = context;
// 1) try external data folder
folder = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), folderName);
if (isOK(folder)) {return;}
// 2) try sd-card folder
folder = new File(Environment.getExternalStorageDirectory() + "/" + folderName);
if (isOK(folder)) {return;}
// 3) try internal data folder
folder = new File(context.getApplicationInfo().dataDir);
if (isOK(folder)) {return;}
// all failed
throw new MyException("failed to create/access storage folder");
}
/** ensure the given folder is OK */
private static final boolean isOK(final File folder) {
folder.mkdirs();
final boolean ok = folder.exists() && folder.isDirectory();
if (ok) {
Log.d("dataFolder", "using: " + folder);
} else {
Log.d("dataFolder", "not OK: " + folder);
}
return ok;
}
public File getFolder(){
return folder;
}
}
package de.tonifetzer.sensorrecorder.sensors;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
/**
* log sensor data to file
*/
public final class Logger {
private static final int FLUSH_LIMIT = 2*1024*1024;
private StringBuilder sb = new StringBuilder();
private File file;
private FileOutputStream fos;
private Context context;
private int entries = 0;
private int sizeCurrent = 0;
private int sizeTotal = 0;
/** timestamp of logging start. all entries are relative to this one */
private long startTS = 0;
public Logger(Context context) {
this.context = context;
}
/** start logging (into RAM) */
public final void start() {
// start empty
sb.setLength(0);
entries = 0;
sizeTotal = 0;
sizeCurrent = 0;
// starting timestamp
startTS = System.currentTimeMillis();
// open the output-file immeditaly (to get permission errors)
// but do NOT yet write anything to the file
final DataFolder folder = new DataFolder(context, "sensorOutFiles");
file = new File(folder.getFolder(), startTS + ".csv");
try {
fos = new FileOutputStream(file);
Log.d("logger", "will write to: " + file.toString());
} catch (final Exception e) {
throw new MyException("error while opening log-file", e);
}
}
/** stop logging and flush RAM-data to the flash-chip */
public final void stop() {
synchronized (this) {
flush(true);
close();
}
}
public File getFile() {
return file;
}
public int getCurrentSize() {return sizeCurrent;}
public int getTotalSize() {return sizeTotal;}
public int getNumEntries() {return entries;}
/** add a new CSV entry for the given sensor number to the internal buffer */
public final void addCSV(final SensorType sensorNr, final String csv) {
synchronized (this) {
final long relTS = System.currentTimeMillis() - startTS;
sb.append(relTS); // relative timestamp (uses less space)
sb.append(';');
sb.append(sensorNr.id());
sb.append(';');
sb.append(csv);
sb.append('\n');
++entries;
sizeTotal += csv.length() + 10; // approx!
sizeCurrent = sb.length();
if (sb.length() > FLUSH_LIMIT) {flush(false);}
}
debug();
}
/** helper method for exception-less writing. DO NOT CALL DIRECTLY! */
private final void _write(final byte[] data) {
try {
fos.write(data);
Log.d("logger", "flushed " + data.length + " bytes to disk");
} catch (final Exception e) {
throw new RuntimeException("error while writing log-file", e);
}
}
/** helper-class for background writing */
class FlushAsync extends AsyncTask<byte[], Integer, Integer> {
@Override
protected final Integer doInBackground(byte[][] data) {
_write(data[0]);
return null;
}
};
/** flush current buffer-contents to disk */
private final void flush(boolean sync) {
// fetch current buffer contents to write and hereafter empty the buffer
// this action MUST be atomic, just like the add-method
byte[] data = null;
synchronized (this) {
data = sb.toString().getBytes(); // fetch data to write
sb.setLength(0); // reset the buffer
sizeCurrent = 0;
}
// write
if (sync) {
// write to disk using the current thread
_write(data);
} else {
// write to disk using a background-thread
new FlushAsync().execute(new byte[][] {data});
}
}
private final void close() {
try {
fos.close();
} catch (final Exception e) {
throw new MyException("error while writing log-file", e);
}
}
public final long getStartTS() {
return startTS;
}
int cnt = 0;
private final void debug() {
if (++cnt % 1000 == 0) {
Log.d("buffer", "size: " + sizeCurrent);
}
}
}
package de.tonifetzer.sensorrecorder.sensors;
import android.widget.Toast;
import de.tonifetzer.sensorrecorder.MainActivity;
/**
* Throws an exception into a Toast
*/
public class MyException extends RuntimeException {
MyException(final String err, final Throwable t) {
super(err, t);
Toast.makeText(MainActivity.getAppContext(), err, Toast.LENGTH_LONG).show();
}
MyException(final String err) {
super(err);
Toast.makeText(MainActivity.getAppContext(), err, Toast.LENGTH_LONG).show();
}
}
package de.tonifetzer.sensorrecorder.sensors;
import android.app.Activity;
/**
* base-class for all Sensors
*/
public abstract class MySensor {
/** listen for sensor events */
public interface SensorListener {
public void onData(final String csv);
/** received data from the given sensor */
public void onData(final SensorType id, final String csv);
}
/** the listener to inform (if any) */
protected SensorListener listener = null;
/** start the sensor */
public abstract void onResume(final Activity act);
/** stop the sensor */
public abstract void onPause(final Activity act);
/** attach the given listener to the sensor */
public void setListener(final SensorListener listener) {this.listener = listener;}
}
package de.tonifetzer.sensorrecorder.sensors;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* all available sensors
* and what to do within one class
*
*/
public class PhoneSensors extends MySensor implements SensorEventListener{
private static final int SENSOR_TYPE_HEARTRATE = 65562;
private SensorManager sensorManager;
private Sensor acc;
private Sensor grav;
private Sensor lin_acc;
private Sensor gyro;
private Sensor magnet;
private Sensor press;
private Sensor ori;
private Sensor heart;
private Sensor humidity;
private Sensor rotationVector;
private Sensor light;
private Sensor temperature;
/** local gravity copy (needed for orientation matrix) */
private float[] mGravity = new float[3];
/** local geomagnetic copy (needed for orientation matrix) */
private float[] mGeomagnetic = new float[3];
/** ctor */
public PhoneSensors(final Activity act){
// fetch the sensor manager from the activity
sensorManager = (SensorManager) act.getSystemService(Context.SENSOR_SERVICE);
// try to get each sensor
acc = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
grav = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
lin_acc = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
gyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
magnet = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
press = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
ori = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
heart = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
humidity = sensorManager.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY);
rotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
light = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
temperature = sensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
// dump sensor-vendor info to file
dumpVendors(act);
}
private final char NL = '\n';
/** Write Vendors to file */
private void dumpVendors(final Activity act) {
final DataFolder folder = new DataFolder(act, "sensorOutFiles");
final File file = new File(folder.getFolder(), "vendors.txt");
try {
final FileOutputStream fos = new FileOutputStream(file);
final StringBuilder sb = new StringBuilder();
// constructor smartphone details
sb.append("[Device]").append(NL);
sb.append("\tModel: ").append(Build.MODEL).append(NL);
sb.append("\tAndroid: ").append(Build.VERSION.RELEASE).append(NL);
sb.append(NL);
// construct sensor details
dumpSensor(sb, SensorType.ACCELEROMETER, acc);
dumpSensor(sb, SensorType.GRAVITY, grav);
dumpSensor(sb, SensorType.LINEAR_ACCELERATION, lin_acc);
dumpSensor(sb, SensorType.GYROSCOPE, gyro);
dumpSensor(sb, SensorType.MAGNETIC_FIELD, magnet);
dumpSensor(sb, SensorType.PRESSURE, press);
dumpSensor(sb, SensorType.RELATIVE_HUMIDITY, humidity);
dumpSensor(sb, SensorType.ORIENTATION_OLD, ori);
dumpSensor(sb, SensorType.LIGHT, light);
dumpSensor(sb, SensorType.AMBIENT_TEMPERATURE, temperature);
dumpSensor(sb, SensorType.HEART_RATE, heart);
// write
fos.write(sb.toString().getBytes());
fos.close();
}catch (final IOException e) {
throw new RuntimeException(e);
}
}
/** dump all details of the given sensor into the provided stringbuilder */
private void dumpSensor(final StringBuilder sb, final SensorType type, final Sensor sensor) {
sb.append("[Sensor]").append(NL);
sb.append("\tour_id: ").append(type.id()).append(NL);
sb.append("\ttype: ").append(type).append(NL);
if (sensor != null) {
sb.append("\tVendor: ").append(sensor.getVendor()).append(NL);
sb.append("\tName: ").append(sensor.getName()).append(NL);
sb.append("\tVersion: ").append(sensor.getVersion()).append(NL);
sb.append("\tMinDelay: ").append(sensor.getMinDelay()).append(NL);
//sb.append("\tMaxDelay: ").append(sensor.getMaxDelay()).append(NL);
sb.append("\tMaxRange: ").append(sensor.getMaximumRange()).append(NL);
sb.append("\tPower: ").append(sensor.getPower()).append(NL);
//sb.append("ReportingMode: ").append(sensor.getReportingMode()).append(NL);
sb.append("\tResolution: ").append(sensor.getResolution()).append(NL);
sb.append("\tType: ").append(sensor.getType()).append(NL);
} else {
sb.append("\tnot available!\n");
}
sb.append("\n");
}
@Override
public void onSensorChanged(SensorEvent event) {
/*
// to compare with the other orientation
if(event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
// inform listeners
if (listener != null){
listener.onData(SensorType.ORIENTATION_OLD,
Float.toString(event.values[0]) + ";" +
Float.toString(event.values[1]) + ";" +
Float.toString(event.values[2])
);
}
}
*/
if(event.sensor.getType() == Sensor.TYPE_HEART_RATE) {
// inform listeners
if (listener != null){
listener.onData(SensorType.HEART_RATE,
Float.toString(event.values[0])
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_LIGHT) {
// inform listeners
if (listener != null){
listener.onData(SensorType.LIGHT,
Float.toString(event.values[0])
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE) {
// inform listeners
if (listener != null){
listener.onData(SensorType.AMBIENT_TEMPERATURE,
Float.toString(event.values[0])
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_RELATIVE_HUMIDITY) {
// inform listeners
if (listener != null){
listener.onData(SensorType.RELATIVE_HUMIDITY,
Float.toString(event.values[0])
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
// inform listeners
if (listener != null){
if(event.values.length > 3){
listener.onData(SensorType.ROTATION_VECTOR,
event.values[0] + ";" +
event.values[1] + ";" +
event.values[2] + ";" +
event.values[3]
);
} else {
listener.onData(SensorType.ROTATION_VECTOR,
event.values[0] + ";" +
event.values[1] + ";" +
event.values[2]
);
}
}
}
else if(event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
// inform listeners
if (listener != null){
listener.onData(SensorType.GYROSCOPE,
event.values[0] + ";" +
event.values[1] + ";" +
event.values[2]
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_PRESSURE) {
// inform listeners
if (listener != null){
listener.onData(SensorType.PRESSURE,
Float.toString(event.values[0])
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
// inform listeners
if (listener != null){
listener.onData(SensorType.LINEAR_ACCELERATION,
event.values[0] + ";" +
event.values[1] + ";" +
event.values[2] + ";"
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_GRAVITY) {
// inform listeners
if (listener != null){
listener.onData(SensorType.GRAVITY,
event.values[0] + ";" +
event.values[1] + ";" +
event.values[2]
);
}
}
else if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// inform listeners
if (listener != null){
listener.onData(SensorType.ACCELEROMETER,
event.values[0] + ";" +
event.values[1] + ";" +
event.values[2]
);
}
// keep a local copy (needed for orientation matrix)
System.arraycopy(event.values, 0, mGravity, 0, 3);
// NOTE:
// @see TYPE_MAGNETIC_FIELD
//updateOrientation();
}
else if(event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// inform listeners
if (listener != null){
listener.onData(SensorType.MAGNETIC_FIELD,
event.values[0] + ";" +
event.values[1] + ";" +
event.values[2]
);
}
// keep a local copy (needed for orientation matrix)
System.arraycopy(event.values, 0, mGeomagnetic, 0, 3);
// NOTE
// @see TYPE_ACCELEROMETER
// only MAG updates the current orientation as MAG is usually slower than ACC and this reduces the file-footprint
updateOrientation();
}
}
/** calculate orientation from acc and mag */
private void updateOrientation() {
// skip orientation update if either grav or geo is missing
if (mGravity == null) {return;}
if (mGeomagnetic == null) {return;}
// calculate rotationMatrix and orientation
float[] R = new float[16];
float[] I = new float[16];
// derive rotation matrix from grav and geo sensors
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (!success) {return;}
// derive orientation-vector using the rotation matrix
float[] orientationNew = new float[3];
SensorManager.getOrientation(R, orientationNew);
// inform listeners
if (listener != null) {
// orientation vector
listener.onData(SensorType.ORIENTATION_NEW,
orientationNew[0] + ";" +
orientationNew[1] + ";" +
orientationNew[2]
);
// rotation matrix
//Write the whole rotationMatrix R into the Listener.
String sb = String.valueOf(R[0]) + ';' +
R[1] + ';' +
R[2] + ';' +
R[3] + ';' +
R[4] + ';' +
R[5] + ';' +
R[6] + ';' +
R[7] + ';' +
R[8];
listener.onData(SensorType.ROTATION_MATRIX, sb);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// nothing to-do here
}
@Override
public void onResume(final Activity act) {
// attach as listener to each of the available sensors
registerIfPresent(acc, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(grav, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(gyro, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(lin_acc, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(magnet, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(press, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(ori, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(heart, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(humidity, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(rotationVector, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(light, SensorManager.SENSOR_DELAY_FASTEST);
registerIfPresent(temperature, SensorManager.SENSOR_DELAY_FASTEST);
}
private void registerIfPresent(final Sensor sens, final int delay) {
if (sens != null) {
sensorManager.registerListener(this, sens, delay);
Log.d("PhoneSensors", "added sensor " + sens.toString());
} else {
Log.d("PhoneSensors", "sensor not present. skipping");
}
}
@Override
public void onPause(final Activity act) {
// detach from all events
sensorManager.unregisterListener(this);
}
}
package de.tonifetzer.sensorrecorder.sensors;
/**
* The different sensor types and their id's
*/
public enum SensorType {
ACCELEROMETER(0),
GRAVITY(1),
LINEAR_ACCELERATION(2),
GYROSCOPE(3),
MAGNETIC_FIELD(4),
PRESSURE(5),
ORIENTATION_NEW(6),
ROTATION_MATRIX(7),
WIFI(8),
BEACON(9),
RELATIVE_HUMIDITY(10),
ORIENTATION_OLD(11),
ROTATION_VECTOR(12),
LIGHT(13),
AMBIENT_TEMPERATURE(14),
HEART_RATE(15),
;
private int id;
SensorType(final int id) {
this.id = id;
}
public final int id() {return id;}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="true"
android:drawable="@android:color/holo_green_light" />
<item android:state_focused="false" android:state_pressed="true"
android:drawable="@android:color/holo_green_light" />
<item android:drawable="@android:color/holo_green_dark" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="true"
android:drawable="@android:color/holo_red_light" />
<item android:state_focused="false" android:state_pressed="true"
android:drawable="@android:color/holo_red_light" />
<item android:drawable="@android:color/holo_red_dark" />
</selector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
app/src/main/res/drawable-v24/icon.png

8.95 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment