My code :
#Override
public void onSensorChanged(SensorEvent event) {
float f1 = event.values[0];
float f2 = event.values[1];
float f3 = event.values[2];
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(context,"10 second",Toast.LENGTH_SHORT).show();
new Handler().postDelayed(this, 10000);
}
}, 10000);
this.LastX = event.values[0];
this.LastY = event.values[1];
this.LastZ = event.values[2];
float f4 = Math.abs(this.LastX - f1);
float f5 = Math.abs(this.LastY - f2);
float f6 = Math.abs(this.LastZ - f3);
if(f4<0.003 && f5<0.003 && f6<0.003){
MainActivity.LockState = true;
// Toast.makeText(context,"Düz zemin",Toast.LENGTH_LONG).show();
}
}
I'm trying to compare sensor data every 10 second but postDelayed function does only work first time.After this the toast message is spamming.
You can simply get timestamp from SensorEvent and check if there is 10 seconds difference between the last and current timestamps.
For example:
private SensorEventListener sensorEventListener = new SensorEventListener() {
private long lastTimestamp;
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
long currentTimestamp = sensorEvent.timestamp;
if (currentTimestamp - lastTimestamp >= TimeUnit.SECONDS.toNanos(10)) {
lastTimestamp = currentTimestamp;
Toast.makeText(mContext, "10 seconds", Toast.LENGTH_SHORT).show();
//Here you can compare sensor data
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
Related
I am working on an app that collects Accelerometer, magnetometer data every 20 milliseconds and it saves the data to a csv file.
What I want to do is collect precise latitude and longitude too at the time of data collection so that I can create a heat map (eg. of house).
I am not an android expert. So, I don't know much on how to implement this feature. Is it possible to get coordinate data every 20 milliseconds during indoor data collection?
Below is my current work. Please help me with how can I get real time lat, long and save it to my csv file and what changes I should make?
public class MainActivity extends AppCompatActivity implements SensorEventListener
{
private SensorManager sensorManager;
private Sensor magnetic;
private int counter = 1;
private boolean recording = false;
private boolean counterOn = false;
private float magValues[] = new float[3];
private Context context;
private static final int REQUESTCODE_STORAGE_PERMISSION = 1;
Collection<String[]> magneticData = new ArrayList<>();
private CsvWriter csvWriter = null;
public static DecimalFormat DECIMAL_FORMATTER;
TextView stateText;
EditText fileIDEdit;
TextView magText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(listenerStartButton);
findViewById(R.id.button2).setOnClickListener(listenerStopButton);
fileIDEdit = (EditText)findViewById(R.id.editText);
magText = (TextView) findViewById(R.id.textView3);
stateText = (TextView) findViewById(R.id.textView);
stateText.setText("Stand by");
context = this;
// Sensor
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
magnetic = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
symbols.setDecimalSeparator('.');
DECIMAL_FORMATTER = new DecimalFormat("#.000", symbols);
}
private View.OnClickListener listenerStartButton = new View.OnClickListener() {
#Override
public void onClick(View v) {
recording = true;
stateText.setText("Recording started");
stateText.setTextColor(Color.parseColor("#FF0000"));
}
};
private int REQUEST_CODE = 1;
private View.OnClickListener listenerStopButton = new View.OnClickListener() {
#Override
public void onClick(View v) {
if(recording == true)
{
recording = false;
counter = 0;
String value = fileIDEdit.getText().toString();
stateText.setText("Recording Stopped");
stateText.setTextColor(Color.parseColor("#0000FF"));
if (storagePermitted((Activity) context)){
csvWriter = new CsvWriter();
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "magnetic" + value + ".csv");
//File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "magnetic" + value + ".csv");
try {
csvWriter.write(file, StandardCharsets.UTF_8, magneticData);
Toast.makeText(MainActivity.this, "File is recorded in memory.", Toast.LENGTH_LONG).show();
} catch (IOException io) {
Log.d("Error", io.getLocalizedMessage());
}
}
}
else{
Toast.makeText(MainActivity.this, "Nothing to save. Recording was not started.", Toast.LENGTH_LONG).show();
}
}
};
#Override
protected void onResume(){
super.onResume();
sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_GAME);
}
#Override
public void onSensorChanged(SensorEvent event) {
long timeInMillisec = (new Date()).getTime() + (event.timestamp - System.nanoTime()) / 1000000L;
if(recording) {
float x = 0;
float y = 0;
float z = 0;
double magnitude = 0;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// New Code:
x = event.values[0];
y = event.values[1];
z = event.values[2];
magnitude = Math.sqrt((x * x) + (y + y)
+ (z * z));
//magText.setText("Magnetometer: " + timeInMillisec+" X= " + roundThis(event.values[0]) + " Y= " + roundThis(event.values[1]) + " Z= " + roundThis(event.values[2]));
magText.setText("Magnetometer: X= " + x + " Y= " + y + " Z= " + z + " Magnitude: " + DECIMAL_FORMATTER.format(magnitude) + "\u00b5Tesla");
Log.d("Record", "Magnetometer" + String.valueOf(counter));
magValues = event.values;
}
//magneticData.add(new String[]{String.valueOf(timeInMillisec), String.valueOf(magValues[0]), String.valueOf(magValues[1]), String.valueOf(magValues[2])});
#SuppressLint("SimpleDateFormat") SimpleDateFormat logLineStamp = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS", Locale.getDefault());
//logLineStamp.setTimeZone(TimeZone.getTimeZone("UTC"));
magneticData.add(new String[]{logLineStamp.format(new Date(timeInMillisec)), String.valueOf(x), String.valueOf(y), String.valueOf(z), String.valueOf(magnitude)});
counter++;
}
}
// Checks if the the storage permissions are given or not by the user
// It will request the use if not
private static boolean storagePermitted(Activity activity){
// Check read write permission
Boolean readPermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
Boolean writePermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
if (readPermission && writePermission){
return true;
}
ActivityCompat.requestPermissions(activity, new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUESTCODE_STORAGE_PERMISSION);
return false;
}
public static float roundThis(float value){
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(4, RoundingMode.HALF_UP);
return bd.floatValue();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
I have this swapAnimation method which basically swaps two views. I call this method inside a loop and pass different views on the swapAnimation method each time. But the problem is the animation happens only once. I want it to repeat n number of times.
void swapAnimation(View v1,View v2){
if(isAnimating)return;
isAnimating = true;
float x1,y1,x2,y2;
x1 =getRelativeX(v1);
x2 = getRelativeX(v2);
y1 = getRelativeY(v1);
y2 = getRelativeY(v2);
float x_displacement = (x2-x1);
float y_displacement = (y2-y1);
v1.animate().xBy(x_displacement).yBy(y_displacement);
v2.animate().xBy(-x_displacement).yBy(-y_displacement);
v1.animate().setDuration(500);
v2.animate().setDuration(500);
long duration = v1.animate().getDuration();
new CountDownTimer(duration+10,duration+10){
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
isAnimating = false;
}
}.start();
}
public static void arrange(LinearLayout container, Context context){
MainActivity activity = (MainActivity) context;
for(int i=0;i<container.getChildCount();i++){
BarView v1 = (BarView) container.getChildAt(i);
for(int j=i;j<container.getChildCount();j++){
BarView v2 = (BarView) container.getChildAt(j);
if(v1.getWeight() > v2.getWeight()){
Log.d(TAG, "bubbleSort: "+v1.getWeight()+">"+v2.getWeight());
activity.swapAnimation(v1,v2);
}
}
}
}
Try this
animation.setRepeatCount(Animation.INFINITE);
I need to get values from a compass and do it in rxJava.
So I've made this code:
private void goCompass()
{
Observable.create(new Observable.OnSubscribe<SensorEventListener>()
{
SensorEventListener listener = null;
#Override
public void call(final Subscriber<? super SensorEventListener> subscriber)
{
Sensor gsensor;
Sensor msensor;
final float[] mGravity = new float[3];
final float[] mGeomagnetic = new float[3];
listener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
final float alpha = 0.97f;
Float azimuth = 0f;
synchronized (this) {
if(switchChecked == false) {
subscriber.onNext(listener);
subscriber.onCompleted();
}
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity[0] = alpha * mGravity[0] + (1 - alpha)
* event.values[0];
mGravity[1] = alpha * mGravity[1] + (1 - alpha)
* event.values[1];
mGravity[2] = alpha * mGravity[2] + (1 - alpha)
* event.values[2];
// mGravity = event.values;
// Log.e(TAG, Float.toString(mGravity[0]));
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// mGeomagnetic = event.values;
mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha)
* event.values[0];
mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha)
* event.values[1];
mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha)
* event.values[2];
// Log.e(TAG, Float.toString(event.values[0]));
}
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimuth = (float) Math.toDegrees(orientation[0]); // orientation
azimuth = (azimuth + 360) % 360;
Log.d("obs", "azimuth (rad): " + azimuth);
layout.setRotation(azimuth);
imageView.setRotation(-azimuth);
contlayout.setRotation(azimuth);
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
sensorManager = (SensorManager) getActivity()
.getSystemService(Context.SENSOR_SERVICE);
gsensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
msensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
sensorManager.registerListener(listener, gsensor,
SensorManager.SENSOR_DELAY_FASTEST);
sensorManager.registerListener(listener, msensor,
SensorManager.SENSOR_DELAY_FASTEST);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<SensorEventListener>() {
#Override
public void onCompleted()
{
}
#Override
public void onError(Throwable e)
{
}
#Override
public void onNext(SensorEventListener listener)
{
sensorManager.unregisterListener(listener);
}
});
}
and it works. However, I'm at the beginning of rxJava and I want to know if there are better ways to do this things:
I've tried to get the azimuth value in onNext() method any times, but it doesn't work
I want to make it asynchronously but I couldn't because registerListener works only in the mainThread() and so if I use Schedulers.io() I need also to do runOnUiThread() method.
There are other ways to do it?
Thank you for help
I wrote an Android Application to measure acceleration in y-direction. The sensor values are being processed by a thread to keep my UI responsive.
This is my thread:
public class SensorThread extends Thread implements SensorEventListener {
private Context context;
private SensorManager sensorManager;
private Sensor accelerometer;
private long lastUpdate;
private long startTime;
private final float RC = 150.0f;
float accel_y_smoothed = 1000000f;
float raw_y = 0f;
private Handler handler;
public SensorThread(Context context, Handler handler) {
this.context = context;
this.handler = handler;
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
startTime = System.currentTimeMillis();
lastUpdate = System.currentTimeMillis();
}
public void run() {
}
#Override
public void onSensorChanged(SensorEvent event) {
// Gather Sensor data
raw_y = event.values[1];
if (System.currentTimeMillis() - lastUpdate > 10) {
// Filter Sensor data
float timeInterval = System.currentTimeMillis() - lastUpdate;
//plot_raw.addValue(accel_y, startTime - System.currentTimeMillis());
float alpha = timeInterval / (RC + timeInterval);
if (accel_y_smoothed == 1000000f) {
accel_y_smoothed = raw_y;
} else {
accel_y_smoothed = alpha * raw_y + (1 - alpha) * accel_y_smoothed;
}
//plot.addValue(accel_y_smoothed, startTime - System.currentTimeMillis());
lastUpdate = System.currentTimeMillis();
Message message = handler.obtainMessage(0);
Bundle bundle = new Bundle();
bundle.putFloat("smoothed_y", accel_y_smoothed);
bundle.putFloat("raw_y", raw_y);
bundle.putLong("timestamp", startTime - System.currentTimeMillis());
message.setData(bundle);
handler.sendMessage(message);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void stopThread() {
sensorManager.unregisterListener(this);
}
public void resumeThread() {
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
}
public void calibrate() {
long startCalibrationTime = System.currentTimeMillis() + 500;
ArrayList<Float> calibration_values = new ArrayList<Float>();
long lastUpdateCalibration = 0;
while (System.currentTimeMillis() - startCalibrationTime + 500 < 1000) {
if (lastUpdateCalibration != lastUpdate) {
calibration_values.add(raw_y);
}
}
float mean = 0.0f;
for (int i = 0; i < calibration_values.size(); i++) {
mean += calibration_values.get(i);
}
mean = mean / calibration_values.size();
Message message = handler.obtainMessage(1);
Bundle bundle = new Bundle();
bundle.putFloat("y_offset", mean);
message.setData(bundle);
handler.sendMessage(message);
}
}
Now I implemented a calibrate() function to measure the mean offset when the phone is lying still on a table for example. The problem is, when I call this function from my main thread, it blocks the UI.
sensorThread.calibrate(); is called from my main thread on my instance of sensorThread which was created when the main activity started.
How do I properly call this function to not block my UI?
As zapl correctly stated:
A method is executed in the thread it was called from, not in which class it's source is.
So I used a message to let my Thread now I require a new calibration. This works fine for me.
In android studio in the MainActivity in the onCreate i did:
timerValueRecord = (TextView) findViewById(R.id.timerValueRecord);
In strings.xml i added:
<string name="timerValRecord">Recording Time: 00:00:00</string>
In activity_main.xml i added:
<TextView
android:id="#+id/timerValueRecord"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="20sp"
android:textColor="#000000"
android:layout_marginTop="315dp"
android:text="#string/timerValRecord" />
In the activity_main designer it looks like:
In the MainActivity i have a touch event:
#Override
public boolean onTouchEvent(MotionEvent event)
{
float eventX = event.getX();
float eventY = event.getY();
float lastdownx = 0;
float lastdowny = 0;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
lastdownx = eventX;
lastdowny = eventY;
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
byte[] response = null;
if (connectedtoipsuccess == true)
{
if (is_start == true)
{
response = Get(iptouse + "start");
is_start = false;
} else
{
textforthespeacch = "Recording stopped and preparing the file to be shared on youtube";
MainActivity.this.initTTS();
response = Get(iptouse + "stop");
is_start = true;
startuploadstatusthread = true;
servercheckCounter = 0;
}
if (response != null)
{
try
{
a = new String(response, "UTF-8");
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
if (a.equals("Recording started"))
{
status1.setText("Recording");
}
if (a.equals("Recording stopped and preparing the file to be shared on youtube"))
{
status1.setText("Recording Stopped");
}
}
});
textforthespeacch = a;
MainActivity.this.initTTS();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
Logger.getLogger("MainActivity(inside thread)").info(a);
}
}
}
});
t.start();
return true;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
return true;
}
What i want to do is when in the touch event it's true after this line:
if (is_start == true)
Start the timer and display on the timerValueRecord the time running including milliseconds seconds and minutes until the user touch again and then it's getting to the stop part and then to stop the timer.
The problem is how to build the timer at all and how to stop and start it.
You can try this below Code:
public class ShowTimer {
private long startTime = 0L;
private Handler customHandler = new Handler();
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
public void StartTimer() {
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
}
public void StopTimer() {
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(updateTimerThread);
}
private Runnable updateTimerThread = new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (timeInMilliseconds / 1000);
int mins = secs / 60;
secs = secs % 60;
int hours = mins / 60;
mins = mins % 60;
//int milliseconds = (int) (updatedTime % 1000);
//+ ":" + String.format("%03d", milliseconds)
String timer = "" + String.format("%02d", hours) + ":" + String.format("%02d", mins) + ":" + String.format("%02d", secs);
//set yout textview to the String timer here
customHandler.postDelayed(this, 1000);
}
};
You can use StartTimer() and StopTimer() function where you want to start or stop the timer:
try this way
public class AndroidTimerTaskExample extends Activity {
Timer timer;
TimerTask timerTask;
//we are going to use a handler to be able to run in our TimerTask
final Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
//onResume we start our timer so it can start when the app comes from the background
startTimer();
}
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, after the first 5000ms the TimerTask will run every 10000ms
timer.schedule(timerTask, 5000, 10000); //
}
public void stoptimertask(View v) {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
//use a handler to run a toast that shows the current timestamp
handler.post(new Runnable() {
public void run() {
//get the current timeStamp
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
final String strDate = simpleDateFormat.format(calendar.getTime());
//show the toast
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(getApplicationContext(), strDate, duration);
toast.show();
}
});
}
};
}
}